Przejdź do treści głównej

Integracja A-Parser z Redis: zaawansowane API

Porównanie z HTTP API

A-Parser Redis API został opracowany w celu zastąpienia metod oneRequest i bulkRequest dla bardziej wydajnej implementacji i wsparcia dodatkowych scenariuszy użycia:

  • jako serwer zapytań i wyników występuje Redis
  • możliwość odpytywania o wyniki asynchronicznie lub w trybie blokującym
  • możliwość podłączenia wielu scraperów (zarówno na jednym, jak i na różnych serwerach) do przetwarzania zapytań z jednym punktem wejścia
  • możliwość ustawienia liczby wątków do przetwarzania zapytań i przeglądania logów pracy
  • możliwość organizacji timeoutów dla operacji
  • automatyczne wygasanie (Expire) nieodebranych wyników

Temat dyskusji na forum

Przedwstępna konfiguracja

W przeciwieństwie do A-Parser HTTP API, aby korzystać z Redis API, należy wcześniej skonfigurować i uruchomić zadanie ze scraperem API::Server::RedisAPI::Server::Redis:

  • zainstalować i uruchomić serwer Redis (lokalnie lub zdalnie)
  • utworzyć preset ustawień dla scrapera API::Server::RedisAPI::Server::Redis, wskazując:
    • Redis Host - adres serwera Redis, domyślnie 127.0.0.1
    • Redis Port - port serwera Redis, domyślnie 6379
    • Redis Queue Key - nazwa klucza do wymiany danych z A-Parser, domyślnie aparser_redis_api, możesz tworzyć oddzielne kolejki i przetwarzać je różnymi zadaniami lub różnymi kopiami A-Parser
    • Result Expire(TTL) - czas życia wyniku w sekundach, służy do automatycznej kontroli i usuwania nieodebranych wyników, domyślnie 3600 sekund (1 godzina)
  • dodać zadanie ze scraperem API::Server::RedisAPI::Server::Redis
    • jako zapytania należy podać {num:1:N}, gdzie N powinno odpowiadać liczbie wątków wskazanej w zadaniu
    • możesz również włączyć opcję prowadzenia logu, dzięki czemu dostępna będzie możliwość przeglądania logu dla każdego zapytania

Przykład konfiguracji zadania z API::Server::RedisAPI::Server::Redis

Otrzymywanie zapytania API

Uruchomienie A-Parser wraz z Redis używając docker-compose

Przy takim sposobie uruchomienia jako adres serwera Redis (Redis Host) zamiast IP można podać nazwę usługi, w poniższych przykładach jest to redis

Jeśli A-Parser nie był wcześniej uruchamiany przez docker-compose

  1. Pobierz i rozpakuj dystrybucję (jednorazowy link należy wcześniej pobrać ze Strefy użytkownika, jak opisano tutaj):
curl -O https://a-parser.com/members/onetime/ce42f308eaa577b5/aparser.tar.gz
tar zxf aparser.tar.gz
rm -f aparser.tar.gz
  1. Utwórz plik docker-compose.yml i umieść w nim następującą treść:

    • Podstawowy wariant bez hasła i otwierania portu, Redis będzie dostępny tylko wewnątrz sieci 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
    • Wariant z hasłem i otwieraniem portu, Redis będzie dostępny z zewnątrz, dlatego zdecydowanie zaleca się użycie hasła
    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 TU_HASŁO_DLA_REDIS
    ports:
    - 6379:6379

    Zamiast TU_HASŁO_DLA_REDIS wymyśl i podaj hasło, które będzie używane przy autoryzacji w Redis.

  2. Uruchom kontenery:

docker compose up -d

Jeśli A-Parser był już wcześniej uruchomiony przez docker-compose

  1. Edytuj plik docker-compose.yml dodając na końcu następującą treść:

    • Podstawowy wariant bez hasła i otwierania portu, Redis będzie dostępny tylko wewnątrz sieci Docker
      redis:
    image: redis:latest
    restart: always
    • Wariant z hasłem i otwieraniem portu, Redis będzie dostępny z zewnątrz, dlatego zdecydowanie zaleca się użycie hasła
      redis:
    image: redis:latest
    restart: always
    command: redis-server --requirepass TU_HASŁO_DLA_REDIS
    ports:
    - 6379:6379

    Zamiast TU_HASŁO_DLA_REDIS wymyśl i podaj hasło, które będzie używane przy autoryzacji w Redis.

  2. Uruchom kontenery:

docker compose up -d
notatka

Jeśli A-Parser został już uruchomiony i jego konfiguracja się nie zmieniła, nie zostanie on zrestartowany, a Docker po prostu doda i uruchomi Redis.

Wykonywanie zapytań

Działanie Redis API opiera się na Redis Lists (listach), operacje na listach pozwalają dodawać do kolejki nieograniczoną liczbę zapytań (ograniczoną pamięcią RAM), a także odbierać wyniki w trybie blokującym z timeoutem (blpop) lub w trybie asynchronicznym (lpop).

  • wszystkie ustawienia, oprócz useproxy, proxyChecker i proxybannedcleanup są pobierane z presetu wywoływanego scrapera + overrideOpts
  • ustawienia useproxy, proxyChecker i proxybannedcleanup są pobierane z presetu API::Server::RedisAPI::Server::Redis + overrideOpts

Zapytanie dodaje się do Redis komendą lpush, każde zapytanie składa się z tablicy [queryId, parser, preset, query, overrideOpts, apiOpts] zserializowanej za pomocą JSON:

  • parser, preset, query odpowiadają analogicznym parametrom dla zapytania API oneRequest
  • queryId - tworzone wraz z zapytaniem, zalecamy użycie numeru porządkowego z bazy danych lub dobrego generatora losowego, na podstawie tego ID będzie można odebrać wynik
  • overrideOpts - nadpisywanie ustawień dla presetu scrapera
  • apiOpts - dodatkowe parametry przetwarzania API
notatka

Przy zapytaniach przez Redis etap formatowania wyniku jest pomijany, ponieważ cały wynik jest przekazywany w formacie JSON do dalszego przetwarzania programowego.

redis-cli

Przykład wykonywania zapytań, do testowania można użyć 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.....

Różne przypadki użycia

Asynchroniczne sprawdzanie dostępności wyniku

lpop aparser_redis_api:some_unique_id

Zwróci wynik, jeśli został już przetworzony, lub nil, jeśli zapytanie jest nadal w trakcie przetwarzania

Blokujące odbieranie wyniku

blpop aparser_redis_api:some_unique_id 0

To zapytanie zostanie zablokowane do momentu otrzymania wyniku, możesz również określić maksymalny timeout na otrzymanie wyniku, po którym komenda zwróci nil

Zapisywanie wyników do wspólnej kolejki

Domyślnie A-Parser zapisuje wynik dla każdego zapytania pod jego unikalnym kluczem aparser_redis_api:query_id, co pozwala na organizację wielowątkowego przetwarzania, wysyłając zapytania i odbierając wyniki oddzielnie dla każdego wątku

W niektórych przypadkach konieczne jest przetwarzanie wyników w jednym wątku w miarę ich napływania, w takim przypadku wygodniej jest zapisywać wyniki do wspólnej kolejki wyników (klucz musi różnić się od klucza dla zapytań)

W tym celu należy podać klucz output_queue dla apiOpts:

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

Odbieranie wyniku ze wspólnej kolejki:

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

Przykład implementacji (przypadek SpySERP)

Załóżmy, że tworzymy serwis SaaS, który dokonuje oceny parametrów domen, dla uproszczenia będziemy sprawdzać datę rejestracji domeny

Nasz serwis składa się z 2 stron:

  • /index.php - strona landing page, na której znajduje się formularz wprowadzania domeny
  • /results.php?domain=google.com - strona z wynikami działania serwisu

Dla poprawy doświadczenia użytkownika chcemy, aby strony naszego serwisu ładowały się błyskawicznie, a proces oczekiwania na dane wyglądał naturalnie i wyświetlał loader

Przy zapytaniu do results.php w pierwszej kolejności wykonujemy zapytanie do A-Parser Redis API, tworząc unikalny request_id:

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

Następnie możemy wyświetlić stronę użytkownikowi i pokazać loader w obszarze wyświetlania danych, dzięki brakowi opóźnień odpowiedź serwera będzie ograniczona tylko prędkością połączenia Redis (zazwyczaj w granicach 10ms)

A-Parser rozpocznie przetwarzanie zapytania jeszcze zanim przeglądarka użytkownika otrzyma pierwszą treść, po tym jak przeglądarka załaduje wszystkie niezbędne zasoby i skrypty, możemy wyświetlić wynik, w tym celu wysyłamy zapytanie AJAX po dane:

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

Skrypt get-results.php wykonuje blokujące zapytanie do Redis z timeoutem 15 sekund:

blpop aparser_redis_api:request-1 15

I zwraca odpowiedź natychmiast po jej otrzymaniu od A-Parser, jeśli otrzymaliśmy pusty wynik po upływie timeoutu, możemy wyświetlić użytkownikowi błąd pobierania danych

W ten sposób, wysyłając zapytanie do A-Parser przy pierwszym otwarciu strony (/results.php), skracamy niezbędny czas oczekiwania na dane dla użytkownika (/get-results.php) o czas, który przeglądarka użytkownika spędza na oczekiwaniu na treść, ładowaniu skryptów i wykonywaniu zapytania AJAX