Vai al contenuto principale

Integrazione di A-Parser con Redis: API avanzata

Confronto con l'API HTTP

A-Parser Redis API è stato sviluppato per sostituire i metodi oneRequest e bulkRequest per un'implementazione più performante e per supportare scenari di utilizzo aggiuntivi:

  • Redis funge da server per richieste e risultati
  • possibilità di richiedere i risultati in modo asincrono o in modalità bloccante
  • possibilità di collegare più scraper (sia sullo stesso server che su server diversi) per elaborare le richieste con un unico punto di ingresso
  • possibilità di impostare il numero di thread per l'elaborazione delle richieste e visualizzare i log di lavoro
  • possibilità di organizzare timeout sulle operazioni
  • Expire automatico dei risultati non richiesti

Tema di discussione sul forum

Configurazione preliminare

A differenza di A-Parser HTTP API, per utilizzare Redis API è necessario configurare e avviare preventivamente un'attività con lo scraper API::Server::RedisAPI::Server::Redis:

  • installare e avviare il server Redis (localmente o in remoto)
  • creare un preset di impostazioni per lo scraper API::Server::RedisAPI::Server::Redis, specificando:
    • Redis Host - indirizzo del server Redis, predefinito 127.0.0.1
    • Redis Port - porta del server Redis, predefinito 6379
    • Redis Queue Key - nome della chiave per lo scambio di dati con A-Parser, predefinito aparser_redis_api, è possibile creare code separate ed elaborarle con task diversi o diverse istanze di A-Parser
    • Result Expire(TTL) - tempo di vita del risultato in secondi, serve per il controllo automatico e la rimozione dei risultati non richiesti, predefinito 3600 secondi (1 ora)
  • aggiungere un'attività con lo scraper API::Server::RedisAPI::Server::Redis
    • come query è necessario indicare {num:1:N}, dove N deve corrispondere al numero di thread specificato nel task
    • è inoltre possibile attivare l'opzione di logging, in modo da poter visualizzare il log per ogni richiesta

Esempio di configurazione dell'attività con API::Server::RedisAPI::Server::Redis

Ricezione della richiesta API

Avvio di A-Parser insieme a Redis utilizzando docker-compose

Con questo metodo di avvio, come indirizzo del server Redis (Redis Host) è possibile indicare il nome del servizio invece dell'IP, negli esempi seguenti è redis

Se A-Parser non è mai stato avviato tramite docker-compose

  1. Scaricare ed estrarre la distribuzione (il link monouso deve essere preventivamente prelevato dall'Area membri, come descritto qui):
curl -O https://a-parser.com/members/onetime/ce42f308eaa577b5/aparser.tar.gz
tar zxf aparser.tar.gz
rm -f aparser.tar.gz
  1. Creare il file docker-compose.yml e inserire il seguente contenuto:

    • Variante base senza password e apertura porta, Redis sarà accessibile solo all'interno della rete 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
    • Variante con password e apertura porta, Redis sarà accessibile dall'esterno, pertanto si raccomanda vivamente di utilizzare una password
    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 QUI_PASSWORD_PER_REDIS
    ports:
    - 6379:6379

    Al posto di QUI_PASSWORD_PER_REDIS inventate e indicate la password che verrà utilizzata per l'autorizzazione in Redis.

  2. Avviare i container:

docker compose up -d

Se A-Parser è già stato avviato tramite docker-compose

  1. Modificare il file docker-compose.yml aggiungendo alla fine il seguente contenuto:

    • Variante base senza password e apertura porta, Redis sarà accessibile solo all'interno della rete Docker
      redis:
    image: redis:latest
    restart: always
    • Variante con password e apertura porta, Redis sarà accessibile dall'esterno, pertanto si raccomanda vivamente di utilizzare una password
      redis:
    image: redis:latest
    restart: always
    command: redis-server --requirepass QUI_PASSWORD_PER_REDIS
    ports:
    - 6379:6379

    Al posto di QUI_PASSWORD_PER_REDIS inventate e indicate la password che verrà utilizzata per l'autorizzazione in Redis.

  2. Avviare i container:

docker compose up -d
nota

Se A-Parser è già stato avviato e la sua configurazione non è cambiata, non verrà riavviato, e Docker aggiungerà e avvierà semplicemente Redis.

Esecuzione delle richieste

Il funzionamento della Redis API si basa sulle Redis Lists (liste); le operazioni sulle liste consentono di aggiungere alla coda un numero illimitato di richieste (limitato dalla memoria RAM), nonché di ottenere i risultati in modalità bloccante con timeout (blpop) o in modalità asincrona (lpop).

  • tutte le impostazioni, eccetto useproxy, proxyChecker e proxybannedcleanup, vengono prese dal preset dello scraper chiamato + overrideOpts
  • le impostazioni useproxy, proxyChecker e proxybannedcleanup vengono prese dal preset API::Server::RedisAPI::Server::Redis + overrideOpts

La richiesta viene aggiunta a Redis con il comando lpush, ogni richiesta consiste in un array [queryId, parser, preset, query, overrideOpts, apiOpts] serializzato tramite JSON:

  • parser, preset, query corrispondono agli analoghi per la richiesta API oneRequest
  • queryId - viene generato insieme alla richiesta, consigliamo di utilizzare un numero progressivo dal vostro database o un buon valore casuale; tramite questo ID sarà possibile ottenere il risultato
  • overrideOpts - sovrascrittura delle impostazioni per il preset dello scraper
  • apiOpts - parametri aggiuntivi di elaborazione API
nota

Nelle richieste tramite Redis, la fase di formattazione del risultato viene saltata, poiché l'intero risultato viene trasmesso sotto forma di JSON per un'ulteriore elaborazione programmatica.

redis-cli

Esempio di esecuzione delle richieste, per il test è possibile utilizzare 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.....

Casi d'uso

Verifica asincrona della presenza del risultato

lpop aparser_redis_api:some_unique_id

Restituirà il risultato se è già stato elaborato o nil se la richiesta è ancora in fase di elaborazione

Ottenimento bloccante del risultato

blpop aparser_redis_api:some_unique_id 0

Questa richiesta rimarrà bloccata fino al momento della ricezione del risultato; è inoltre possibile specificare un timeout massimo per la ricezione del risultato, dopodiché il comando restituirà nil

Salvataggio dei risultati in un'unica coda

Per impostazione predefinita, A-Parser salva il risultato per ogni richiesta sotto la propria chiave univoca aparser_redis_api:query_id, il che consente di organizzare un'elaborazione multithreading, inviando richieste e ricevendo risultati separatamente per ogni thread

In alcuni casi è necessario elaborare i risultati in un unico thread man mano che arrivano; in questo caso è più comodo salvare i risultati in un'unica coda dei risultati (la chiave deve essere diversa dalla chiave per le richieste)

Per fare ciò, è necessario specificare la chiave output_queue per apiOpts:

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

Ottenimento del risultato dalla coda comune:

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

Esempio di implementazione (caso SpySERP)

Supponiamo di creare un servizio SaaS che effettua la valutazione dei parametri dei domini; per semplicità controlleremo la data di registrazione del dominio

Il nostro servizio è composto da 2 pagine:

  • /index.php - landing page, sulla quale si trova il modulo di inserimento del dominio
  • /results.php?domain=google.com - pagina con i risultati del lavoro del servizio

Per migliorare l'esperienza utente, vogliamo che le pagine del nostro servizio si carichino istantaneamente e che il processo di attesa dei dati sembri naturale e mostri un loader

Alla richiesta a results.php, eseguiamo prima di tutto una richiesta all'API Redis di A-Parser, generando un request_id univoco:

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

Dopodiché possiamo mostrare la pagina all'utente e visualizzare un loader nell'area di visualizzazione dei dati; grazie all'assenza di ritardi, la risposta del server sarà limitata solo dalla velocità di connessione a Redis (solitamente entro i 10 ms)

A-Parser inizierà l'elaborazione della richiesta ancora prima che il browser dell'utente riceva il primo contenuto; dopo che il browser avrà caricato tutte le risorse e gli script necessari, potremo visualizzare il risultato, inviando per questo una richiesta AJAX per ottenere i dati:

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

Lo script get-results.php esegue una richiesta bloccante a Redis con un timeout di 15 secondi:

blpop aparser_redis_api:request-1 15

E restituisce la risposta non appena viene ricevuta da A-Parser; se abbiamo ottenuto un risultato nullo per timeout, possiamo mostrare un errore di ricezione dati all'utente

In questo modo, inviando la richiesta ad A-Parser alla prima apertura della pagina (/results.php), riduciamo il tempo di attesa dei dati necessario per l'utente (/get-results.php) del tempo che il browser dell'utente impiega per attendere il contenuto, caricare gli script ed eseguire la richiesta AJAX