Chuyển đến nội dung chính

Tích hợp A-Parser với Redis: API nâng cao

So sánh với HTTP API

A-Parser Redis API được phát triển để thay thế các phương thức oneRequestbulkRequest nhằm triển khai hiệu suất cao hơn và hỗ trợ các kịch bản sử dụng bổ sung:

  • Redis đóng vai trò là máy chủ truy vấn và kết quả
  • khả năng yêu cầu kết quả không đồng bộ hoặc ở chế độ chặn (blocking)
  • khả năng kết nối nhiều công cụ cào dữ liệu (trên cùng một hoặc các máy chủ khác nhau) để xử lý truy vấn với một điểm đầu vào duy nhất
  • khả năng thiết lập số luồng để xử lý truy vấn và xem nhật ký hoạt động
  • khả năng tổ chức thời gian chờ (timeout) cho các hoạt động
  • tự động Expire các kết quả không được yêu cầu

Chủ đề thảo luận trên diễn đàn

Thiết lập sơ bộ

Khác với A-Parser HTTP API, để sử dụng Redis API, bạn cần cấu hình trước và chạy một tác vụ với công cụ cào dữ liệu API::Server::RedisAPI::Server::Redis:

  • cài đặt và chạy máy chủ Redis (cục bộ hoặc từ xa)
  • tạo một bản thiết lập sẵn (preset) cho công cụ cào dữ liệu API::Server::RedisAPI::Server::Redis, chỉ định:
    • Redis Host - địa chỉ máy chủ Redis, mặc định là 127.0.0.1
    • Redis Port - cổng máy chủ Redis, mặc định là 6379
    • Redis Queue Key - tên khóa để trao đổi dữ liệu với A-Parser, mặc định là aparser_redis_api, bạn có thể tạo các hàng đợi riêng biệt và xử lý chúng bằng các tác vụ khác nhau hoặc các bản sao A-Parser khác nhau
    • Result Expire(TTL) - thời gian sống của kết quả tính bằng giây, dùng để tự động kiểm soát và xóa các kết quả không được yêu cầu, mặc định là 3600 giây (1 giờ)
  • thêm một tác vụ với công cụ cào dữ liệu API::Server::RedisAPI::Server::Redis
    • trong phần truy vấn cần chỉ định {num:1:N}, trong đó N phải tương ứng với số luồng được chỉ định trong tác vụ
    • bạn cũng có thể bật tùy chọn ghi nhật ký, nhờ đó sẽ có thể xem nhật ký cho từng truy vấn

Ví dụ cấu hình tác vụ với API::Server::RedisAPI::Server::Redis

Nhận yêu cầu API

Khởi chạy A-Parser cùng với Redis bằng docker-compose

Với phương pháp khởi chạy này, thay vì địa chỉ IP, bạn có thể chỉ định tên dịch vụ làm địa chỉ máy chủ Redis (Redis Host), trong các ví dụ dưới đây là redis

Nếu A-Parser chưa từng được chạy qua docker-compose trước đây

  1. Tải xuống và giải nén bộ cài đặt (trước tiên cần lấy liên kết một lần trong Khu vực Thành viên, như được mô tả tại đây):
curl -O https://a-parser.com/members/onetime/ce42f308eaa577b5/aparser.tar.gz
tar zxf aparser.tar.gz
rm -f aparser.tar.gz
  1. Tạo tệp docker-compose.yml và đặt nội dung sau vào đó:

    • Phương án cơ bản không có mật khẩu và không mở cổng, Redis sẽ chỉ khả dụng bên trong mạng Docker
    version: '3'

    services:
    a-parser:
    image: aparser/runtime:latest
    command: ./aparser
    restart: always
    volumes:
    - ./aparser:/app
    ports:
    - 9091:9091

    redis:
    image: redis:latest
    restart: always
    • Phương án có mật khẩu và mở cổng, Redis sẽ khả dụng từ bên ngoài, vì vậy chúng tôi thực sự khuyên bạn nên sử dụng mật khẩu
    version: '3'

    services:
    a-parser:
    image: aparser/runtime:latest
    command: ./aparser
    restart: always
    volumes:
    - ./aparser:/app
    ports:
    - 9091:9091

    redis:
    image: redis:latest
    restart: always
    command: redis-server --requirepass TUY_CHON_MAT_KHAU_REDIS
    ports:
    - 6379:6379

    Thay vì MAT_KHAU_REDIS_TAI_DAY, hãy nghĩ ra và chỉ định mật khẩu sẽ được sử dụng khi xác thực vào Redis.

  2. Khởi chạy các container:

docker compose up -d

Nếu A-Parser đã được chạy qua docker-compose trước đó

  1. Chỉnh sửa tệp docker-compose.yml bằng cách thêm nội dung sau vào cuối:

    • Phương án cơ bản không có mật khẩu và không mở cổng, Redis sẽ chỉ khả dụng bên trong mạng Docker
      redis:
    image: redis:latest
    restart: always
    • Phương án có mật khẩu và mở cổng, Redis sẽ khả dụng từ bên ngoài, vì vậy chúng tôi thực sự khuyên bạn nên sử dụng mật khẩu
      redis:
    image: redis:latest
    restart: always
    command: redis-server --requirepass TUY_CHON_MAT_KHAU_REDIS
    ports:
    - 6379:6379

    Thay vì MAT_KHAU_REDIS_TAI_DAY, hãy nghĩ ra và chỉ định mật khẩu sẽ được sử dụng khi xác thực vào Redis.

  2. Khởi chạy các container:

docker compose up -d
ghi chú

Nếu A-Parser đã được chạy và cấu hình của nó không thay đổi, nó sẽ không được khởi động lại, mà Docker sẽ chỉ thêm và chạy Redis.

Thực hiện truy vấn

Hoạt động của Redis API dựa trên Redis Lists (danh sách), các thao tác trên danh sách cho phép thêm vào hàng đợi số lượng truy vấn không giới hạn (bị giới hạn bởi bộ nhớ RAM), cũng như nhận kết quả ở chế độ chặn với thời gian chờ (blpop) hoặc ở chế độ không đồng bộ (lpop).

  • tất cả các cài đặt, ngoại trừ useproxy, proxyCheckerproxybannedcleanup được lấy từ mẫu (preset) của công cụ cào dữ liệu được gọi + overrideOpts
  • các cài đặt useproxy, proxyCheckerproxybannedcleanup được lấy từ preset API::Server::RedisAPI::Server::Redis + overrideOpts

Truy vấn được thêm vào Redis bằng lệnh lpush, mỗi truy vấn bao gồm một mảng [queryId, parser, preset, query, overrideOpts, apiOpts] được tuần tự hóa bằng JSON:

  • parser, preset, query tương ứng với các tham số tương tự cho truy vấn API oneRequest
  • queryId - được tạo cùng với truy vấn, chúng tôi khuyên bạn nên sử dụng số thứ tự từ cơ sở dữ liệu của bạn hoặc một số ngẫu nhiên tốt, dựa trên ID này bạn có thể nhận được kết quả
  • overrideOpts - ghi đè các cài đặt cho mẫu của công cụ cào dữ liệu
  • apiOpts - các tham số xử lý API bổ sung
ghi chú

Khi truy vấn qua Redis, bước định dạng kết quả sẽ bị bỏ qua, vì toàn bộ kết quả được truyền dưới dạng JSON để xử lý lập trình tiếp theo.

redis-cli

Ví dụ thực hiện truy vấn, để kiểm tra bạn có thể sử dụng redis-cli:

127.0.0.1:6379> lpush aparser_redis_api '["some_unique_id", "Net::HTTP", "default", "https://ya.ru"]'
(integer) 1
127.0.0.1:6379> blpop aparser_redis_api:some_unique_id 0
1) "aparser_redis_api:some_unique_id"
2) "{\"data\":\"<!DOCTYPE html><html.....

Các trường hợp sử dụng

Kiểm tra sự tồn tại của kết quả không đồng bộ

lpop aparser_redis_api:some_unique_id

Sẽ trả về kết quả nếu nó đã được xử lý hoặc nil nếu truy vấn vẫn đang trong quá trình xử lý

Nhận kết quả ở chế độ chặn

blpop aparser_redis_api:some_unique_id 0

Truy vấn này sẽ bị chặn cho đến khi nhận được kết quả, bạn cũng có thể chỉ định thời gian chờ tối đa để nhận kết quả, sau đó lệnh sẽ trả về nil

Lưu kết quả vào một hàng đợi duy nhất

Theo mặc định, A-Parser lưu kết quả cho mỗi truy vấn dưới khóa duy nhất của nó aparser_redis_api:query_id, cho phép tổ chức xử lý đa luồng, gửi truy vấn và nhận kết quả riêng biệt cho mỗi luồng

Trong một số trường hợp, cần xử lý kết quả trong một luồng khi chúng đến, trong trường hợp này sẽ thuận tiện hơn khi lưu kết quả vào một hàng đợi kết quả duy nhất (khóa phải khác với khóa cho các truy vấn)

Để làm điều này, cần chỉ định khóa output_queue cho apiOpts:

lpush aparser_redis_api '["some_unique_id", "Net::HTTP", "default", "https://ya.ru", {}, {"output_queue": "aparser_results"}]'

Nhận kết quả từ hàng đợi chung:

127.0.0.1:6379> blpop aparser_results 0
1) "aparser_results"
2) "{\"queryId\":\"some_unique_id\",\"results\":{\"data\":\"<!DOCTYPE html><html class=...

Ví dụ triển khai (trường hợp SpySERP)

Giả sử chúng ta đang tạo một dịch vụ SaaS thực hiện đánh giá các tham số của tên miền, để đơn giản chúng ta sẽ kiểm tra ngày đăng ký tên miền

Dịch vụ của chúng ta gồm 2 trang:

  • /index.php - trang landing, trên đó có biểu mẫu nhập tên miền
  • /results.php?domain=google.com - trang hiển thị kết quả hoạt động của dịch vụ

Để cải thiện trải nghiệm người dùng, chúng ta muốn các trang của dịch vụ tải ngay lập tức, và quá trình chờ đợi dữ liệu trông tự nhiên và hiển thị trình tải (loader)

Khi có yêu cầu tới results.php, trước tiên chúng ta thực hiện yêu cầu tới A-Parser Redis API, tạo một request_id duy nhất:

​lpush aparser_redis_api '["request-1", "Net::Whois", "default", "google.com", {}, {}]'

Sau đó, chúng ta có thể hiển thị trang cho người dùng và hiển thị trình tải trên khu vực hiển thị dữ liệu, nhờ việc không có độ trễ, phản hồi của máy chủ sẽ chỉ bị giới hạn bởi tốc độ kết nối Redis (thường trong khoảng 10ms)

A-Parser sẽ bắt đầu xử lý truy vấn ngay cả trước khi trình duyệt của người dùng nhận được nội dung đầu tiên, sau khi trình duyệt tải xong tất cả các tài nguyên và tập lệnh cần thiết, chúng ta có thể hiển thị kết quả, để làm điều này chúng ta gửi yêu cầu AJAX để lấy dữ liệu:

/get-results.php?request_id=request-1

Tập lệnh get-results.php thực hiện truy vấn chặn tới Redis với thời gian chờ 15 giây:

blpop aparser_redis_api:request-1 15

Và trả về phản hồi ngay khi nó được nhận từ A-Parser, nếu chúng ta nhận được kết quả bằng không do hết thời gian chờ, chúng ta có thể hiển thị lỗi lấy dữ liệu cho người dùng

Do đó, bằng cách gửi yêu cầu tới A-Parser khi mở trang lần đầu (/results.php), chúng ta rút ngắn thời gian chờ đợi dữ liệu cần thiết cho người dùng (/get-results.php) bằng khoảng thời gian mà trình duyệt của người dùng dành để chờ đợi nội dung, tải các tập lệnh và thực hiện yêu cầu AJAX