Passer au contenu principal

Intégration d'A-Parser avec Redis : API avancée

Comparaison avec l'API HTTP

A-Parser Redis API a été conçu pour remplacer les méthodes oneRequest et bulkRequest pour une implémentation plus performante et le support de scénarios d'utilisation supplémentaires :

  • Redis agit comme serveur de requêtes et de résultats
  • possibilité de demander les résultats de manière asynchrone ou en mode bloquant
  • possibilité de connecter plusieurs scrapers (sur un seul ou sur différents serveurs) pour traiter les requêtes avec un point d'entrée unique
  • possibilité de définir le nombre de threads pour le traitement des requêtes et de consulter les logs de fonctionnement
  • possibilité d'organiser des timeouts sur les opérations
  • expiration automatique (Expire) des résultats non réclamés

Sujet de discussion sur le forum

Configuration préalable

À la différence de l'A-Parser HTTP API, pour utiliser Redis API, il est nécessaire de configurer et de lancer préalablement une tâche avec le scraper API::Server::RedisAPI::Server::Redis :

  • installer et lancer un serveur Redis (localement ou à distance)
  • créer une présélection de paramètres pour le scraper API::Server::RedisAPI::Server::Redis, indiquer :
    • Redis Host - adresse du serveur Redis, par défaut 127.0.0.1
    • Redis Port - port du serveur Redis, par défaut 6379
    • Redis Queue Key - nom de la clé pour l'échange de données avec A-Parser, par défaut aparser_redis_api, vous pouvez créer des files d'attente séparées et les traiter avec différentes tâches ou différentes instances d'A-Parser
    • Result Expire(TTL) - durée de vie du résultat en secondes, sert au contrôle automatique et à la suppression des résultats non réclamés, par défaut 3600 secondes (1 heure)
  • ajouter une tâche avec le scraper API::Server::RedisAPI::Server::Redis
    • comme requêtes, il est nécessaire d'indiquer {num:1:N}, où N doit correspondre au nombre de threads indiqué dans la tâche
    • vous pouvez également activer l'option de journalisation, ainsi il sera possible de consulter le log pour chaque requête

Exemple de configuration de tâche avec API::Server::RedisAPI::Server::Redis

Réception de la requête API

Lancement d'A-Parser avec Redis via docker-compose

Avec cette méthode de lancement, vous pouvez indiquer le nom du service au lieu de l'IP comme adresse du serveur Redis (Redis Host), dans les exemples ci-dessous c'est redis

Si A-Parser n'a jamais été lancé via docker-compose auparavant

  1. Téléchargez et décompressez la distribution (le lien à usage unique doit être préalablement récupéré dans l'Espace Membres, comme décrit ici) :
curl -O https://a-parser.com/members/onetime/ce42f308eaa577b5/aparser.tar.gz
tar zxf aparser.tar.gz
rm -f aparser.tar.gz
  1. Créez un fichier docker-compose.yml et insérez-y le contenu suivant :

    • Variante de base sans mot de passe et sans ouverture de port, Redis sera accessible uniquement à l'intérieur du réseau 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 avec mot de passe et ouverture de port, Redis sera accessible de l'extérieur, il est donc fortement recommandé d'utiliser un mot de passe
    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 VOTRE_MOT_DE_PASSE_REDIS
    ports:
    - 6379:6379

    À la place de VOTRE_MOT_DE_PASSE_REDIS, inventez et indiquez le mot de passe qui sera utilisé lors de l'authentification dans Redis.

  2. Lancez les conteneurs :

docker compose up -d

Si A-Parser a déjà été lancé via docker-compose auparavant

  1. Modifiez le fichier docker-compose.yml en ajoutant à la fin le contenu suivant :

    • Variante de base sans mot de passe et sans ouverture de port, Redis sera accessible uniquement à l'intérieur du réseau Docker
      redis:
    image: redis:latest
    restart: always
    • Variante avec mot de passe et ouverture de port, Redis sera accessible de l'extérieur, il est donc fortement recommandé d'utiliser un mot de passe
      redis:
    image: redis:latest
    restart: always
    command: redis-server --requirepass VOTRE_MOT_DE_PASSE_REDIS
    ports:
    - 6379:6379

    À la place de VOTRE_MOT_DE_PASSE_REDIS, inventez et indiquez le mot de passe qui sera utilisé lors de l'authentification dans Redis.

  2. Lancez les conteneurs :

docker compose up -d
note

Si A-Parser était déjà lancé et que sa configuration n'a pas changé, il ne sera pas redémarré, et Docker ajoutera et lancera simplement Redis.

Exécution des requêtes

Le fonctionnement de l'API Redis est basé sur les Redis Lists (listes). Les opérations sur les listes permettent d'ajouter à la file d'attente un nombre illimité de requêtes (limité par la mémoire vive), ainsi que d'obtenir les résultats en mode bloquant avec un timeout (blpop) ou en mode asynchrone (lpop).

  • tous les paramètres, sauf useproxy, proxyChecker et proxybannedcleanup, sont extraits de la présélection du scraper appelé + overrideOpts
  • les paramètres useproxy, proxyChecker et proxybannedcleanup sont récupérés depuis la présélection API::Server::RedisAPI::Server::Redis + overrideOpts

La requête est ajoutée à Redis par la commande lpush, chaque requête se compose d'un tableau [queryId, parser, preset, query, overrideOpts, apiOpts] sérialisé à l'aide de JSON :

  • parser, preset, query correspondent aux paramètres analogues de la requête API oneRequest
  • queryId - est généré avec la requête, nous recommandons d'utiliser un numéro séquentiel de votre base de données ou un bon nombre aléatoire ; ce ID permettra de récupérer le résultat
  • overrideOpts - redéfinition des paramètres pour la présélection du scraper
  • apiOpts - paramètres supplémentaires de traitement de l'API
note

Lors des requêtes via Redis, l'étape de formatage du résultat est ignorée, car tout le résultat est transmis sous forme de JSON pour un traitement logiciel ultérieur.

redis-cli

Exemple d'exécution de requêtes, vous pouvez utiliser redis-cli pour tester :

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.....

Différents cas d'utilisation

Vérification asynchrone de la présence du résultat

lpop aparser_redis_api:some_unique_id

Retournera le résultat s'il est déjà traité ou nil si la requête est encore en cours de traitement

Récupération bloquante du résultat

blpop aparser_redis_api:some_unique_id 0

Cette requête sera bloquée jusqu'à l'obtention du résultat, vous pouvez également indiquer un timeout maximum pour l'obtention du résultat, après quoi la commande retournera nil

Sauvegarde des résultats dans une file d'attente unique

Par défaut, A-Parser sauvegarde le résultat de chaque requête sous sa propre clé unique aparser_redis_api:query_id, ce qui permet d'organiser un traitement multithread en envoyant des requêtes et en recevant des résultats séparément pour chaque thread.

Dans certains cas, il est nécessaire de traiter les résultats dans un seul thread au fur et à mesure de leur arrivée. Dans ce cas, il est plus pratique de sauvegarder les résultats dans une file d'attente de résultats unique (la clé doit être différente de la clé des requêtes).

Pour cela, il est nécessaire d'indiquer la clé output_queue pour apiOpts :

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

Récupération du résultat depuis la file d'attente commune :

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

Exemple d'implémentation (cas SpySERP)

Supposons que nous créons un service SaaS qui évalue les paramètres des domaines. Pour simplifier, nous allons vérifier la date d'enregistrement du domaine.

Notre service se compose de 2 pages :

  • /index.php - page de destination (landing page) sur laquelle se trouve le formulaire de saisie du domaine
  • /results.php?domain=google.com - page avec les résultats du fonctionnement du service

Pour améliorer l'expérience utilisateur, nous voulons que les pages de notre service se chargent instantanément, et que le processus d'attente des données paraisse naturel avec l'affichage d'un loader.

Lors de la requête vers results.php, nous effectuons en premier lieu une requête vers l'API Redis d'A-Parser, en générant un request_id unique :

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

Après quoi nous pouvons afficher la page à l'utilisateur et montrer un loader sur la zone d'affichage des données. Grâce à l'absence de délais, la réponse du serveur ne sera limitée que par la vitesse de connexion à Redis (généralement dans les 10 ms).

A-Parser commencera le traitement de la requête avant même que le navigateur de l'utilisateur ne reçoive le premier contenu. Une fois que le navigateur aura chargé toutes les ressources et scripts nécessaires, nous pourrons afficher le résultat. Pour cela, nous envoyons une requête AJAX pour obtenir les données :

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

Le script get-results.php effectue une requête bloquante vers Redis avec un timeout de 15 secondes :

blpop aparser_redis_api:request-1 15

Et retourne la réponse dès qu'elle est reçue d'A-Parser. Si nous avons reçu un résultat nul par timeout, nous pouvons afficher une erreur de récupération des données à l'utilisateur.

Ainsi, en envoyant la requête à A-Parser lors de la première ouverture de la page (/results.php), nous réduisons le temps d'attente des données nécessaire pour l'utilisateur (/get-results.php) du temps que le navigateur de l'utilisateur passe à attendre le contenu, à charger les scripts et à exécuter la requête AJAX.