Elastic Open Web Crawler en tant que code
Apprenez à utiliser les actions GitHub pour gérer les configurations d'Elastic Open Crawler, de sorte que chaque fois que nous apportons des modifications au référentiel, celles-ci sont automatiquement appliquées à l'instance déployée du crawler.
Avec Elastic Open Web Crawler et son architecture pilotée par CLI, il est désormais assez simple d'avoir des configurations de crawler versionnées et un pipeline CI/CD avec des tests locaux.
Traditionnellement, la gestion des robots d'indexation était un processus manuel et sujet aux erreurs. Il s'agissait de modifier les configurations directement dans l'interface utilisateur et de se débattre avec le clonage des configurations de crawl, le retour en arrière, la gestion des versions, etc. Traiter les configurations des robots comme du code résout ce problème en offrant les mêmes avantages que ceux que nous attendons du développement de logiciels : répétabilité, traçabilité et automatisation.
Ce flux de travail facilite l'intégration de l'Open Web Crawler dans votre pipeline CI/CD pour les retours en arrière, les sauvegardes et les migrations, tâches qui étaient beaucoup plus délicates avec les Elastic Crawlers précédents, tels que l'Elastic Web Crawler ou l'App Search Crawler.
Dans cet article, nous allons apprendre à.. :
Gérer nos configurations de crawl en utilisant GitHub
Disposer d'une installation locale pour tester les pipelines avant de les déployer
Créer une configuration de production pour exécuter le robot d'exploration avec de nouveaux paramètres à chaque fois que nous apportons des modifications à notre branche principale.
Vous pouvez trouver le dépôt du projet ici. Pour l'instant, j'utilise Elasticsearch 9.1.3 et Open Web Crawler 0.4.2.
Produits requis
Bureau Docker
Instance Elasticsearch
Machine virtuelle avec accès SSH (par exemple, AWS EC2) et Docker installé.
Étapes
Structure des dossiers
Configuration du robot
Fichier Docker-compose (environnement local)
Actions Github
Tests au niveau local
Déploiement vers prod
Modifications et redéploiement
Structure des dossiers
Pour ce projet, nous aurons la structure de fichier suivante :
├── docker-compose.yml # Local elasticsearch + crawler
├── config/crawler-config.yml # Crawler config
├── .github/workflows/deploy.yml # GH Action to deploy changes
├── local.sh # Script to run our local crawlerConfiguration du robot
Sous crawler-config.yml,, nous mettrons les éléments suivants :
output_sink: elasticsearch
output_index: web-crawl-index
max_crawl_depth: 1
elasticsearch:
host: ${ES_HOST}
api_key: ${ES_API_KEY}
domains:
- url: https://web-scraping.dev
seed_urls:
- https://web-scraping.dev/product/1
- https://web-scraping.dev/product/2
- https://web-scraping.dev/product/3Il s'agit d'une recherche à partir de https://web-scraping.dev/products, un site fictif pour les produits. Nous ne parcourrons que les trois premières pages du produit. Le paramètre max_crawl_depth empêchera le robot d'exploration de découvrir d'autres pages que celles définies comme seed_urls en n'ouvrant pas les liens qu'elles contiennent.
Elasticsearch host et api_key seront alimentés dynamiquement en fonction de l'environnement dans lequel nous exécutons le script.

Fichier Docker-compose (environnement local)
Pour le site local docker-compose.yml,, nous allons déployer le crawler et un seul cluster Elasticsearch + Kibana, de sorte que nous puissions facilement visualiser nos résultats de crawling avant de les déployer en production.
services:
es01:
image: docker.elastic.co/elasticsearch/elasticsearch:9.1.3
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- ES_JAVA_OPTS=-Xms1g -Xmx1g
ports:
- "9200:9200"
networks: [esnet]
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9200"]
interval: 5s
timeout: 5s
retries: 10
kibana:
image: docker.elastic.co/kibana/kibana:9.1.3
environment:
- ELASTICSEARCH_HOSTS=http://es01:9200
ports:
- "5601:5601"
networks: [esnet]
depends_on: [es01]
crawler:
image: docker.elastic.co/integrations/crawler:0.4.2
environment:
- ES_HOST=http://es01:9200
- CRAWLER_JRUBY_OPTS=--server
container_name: crawler
volumes:
- ./config:/home/app/config
networks: [esnet]
entrypoint: ["/home/app/bin/crawler", "crawl", "/home/app/config/crawl-config-final.yml"]
stdin_open: true
tty: true
networks:
esnet:
driver: bridgeNotez que le crawler attend qu'Elasticsearch soit prêt à fonctionner.
Actions Github
Nous devons maintenant créer une action GitHub qui copiera les nouveaux paramètres et exécutera le crawler dans notre machine virtuelle à chaque poussée vers main. Ainsi, nous disposons toujours de la dernière configuration déployée, sans avoir à entrer manuellement dans la machine virtuelle pour mettre à jour les fichiers et exécuter le crawler. Nous allons utiliser AWS EC2 comme fournisseur de machines virtuelles.
La première étape consiste à ajouter l'hôte (VM_HOST), l'utilisateur de la machine (VM_USER), la clé RSA SSH (VM_KEY), l'hôte Elasticsearch (ES_HOST) et la clé API Elasticsearch (ES_API_KEY) aux secrets d'action GitHub :

De cette manière, l'action pourra accéder à notre serveur pour copier les nouveaux fichiers et exécuter le crawl.
Maintenant, créons notre fichier .github/workflows/deploy.yml:
name: Deploy
on:
push:
branches: [main]
jobs:
Deploy:
name: Deploy to EC2
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Deploy crawler
env:
HOSTNAME: ${{ secrets.VM_HOST }}
USER_NAME: ${{ secrets.VM_USER }}
PRIVATE_KEY: ${{ secrets.VM_KEY }}
ES_HOST: ${{ secrets.ES_HOST }}
ES_API_KEY: ${{ secrets.ES_API_KEY }}
run: |
# Save private key
echo "$PRIVATE_KEY" > private_key
chmod 600 private_key
# Generate final config locally
envsubst < config/crawler-config.yml > config/crawl-config-final.yml
# Copy the config folder to VM
scp -o StrictHostKeyChecking=no -i private_key -r config ${USER_NAME}@${HOSTNAME}:~/config
# SSH into VM and run crawler
ssh -o StrictHostKeyChecking=no -i private_key ${USER_NAME}@${HOSTNAME} << EOF
docker run --rm \
-v ~/config:/config \
docker.elastic.co/integrations/crawler:latest jruby \
bin/crawler crawl /config/crawl-config-final.yml
EOFCette action exécutera les étapes suivantes à chaque fois que des modifications seront apportées au fichier de configuration du crawler :
Renseigner l'hôte Elasticsearch et la clé API dans la configuration yml
Copier le dossier config sur notre VM
Se connecter via SSH à notre VM
Exécuter le crawl avec la configuration que nous venons de copier depuis le repo
Tests au niveau local
Pour tester notre crawler localement, nous avons créé un script bash qui remplit l'hôte Elasticsearch avec l'hôte local de Docker et démarre un crawl. Vous pouvez lancer ./local.sh pour l'exécuter.
#!/bin/bash
# Exit on any error
set -e
# Load environment variables
export ES_HOST="http://es01:9200"
# Generate final crawler config
envsubst < ./config/crawler-config.yml > ./config/crawl-config-final.yml
# Bring everything up
docker compose up --buildRegardons Kibana DevTools pour confirmer que le site web-crawler-index a été correctement renseigné :

Déploiement vers prod
Nous sommes maintenant prêts à pousser vers la branche principale, ce qui déploiera le crawler dans votre machine virtuelle et commencera à envoyer des logs à votre instance Serverless Elasticsearch.
git add .
git commit -m "First commit"
git pushCela déclenchera l'action GitHub, qui exécutera le script de déploiement dans la machine virtuelle et commencera l'exploration.
Vous pouvez confirmer que l'action a été exécutée en allant sur le dépôt GitHub et en visitant l'onglet "Actions" :

Modifications et redéploiement
Vous avez peut-être remarqué que le site price de chaque produit fait partie du champ "body" du document. L'idéal serait de stocker le prix dans un champ distinct afin de pouvoir utiliser des filtres.
Ajoutons cette modification au fichier crawler.yml afin d'utiliser des règles d'extraction pour extraire le prix de la classe CSS product-price:
output_sink: elasticsearch
output_index: web-crawl-index
max_crawl_depth: 1
elasticsearch:
host: ${ES_HOST}
api_key: ${ES_API_KEY}
# Index ingest pipeline to process documents before indexing
pipeline_enabled: true
pipeline: pricing-pipeline
domains:
- url: https://web-scraping.dev
seed_urls:
- https://web-scraping.dev/product/1
- https://web-scraping.dev/product/2
- https://web-scraping.dev/product/3
extraction_rulesets:
- url_filters:
- type: ends
pattern: /product/*
rules:
- action: extract
field_name: price
selector: .product-price
join_as: string
source: htmlNous constatons également que le prix comprend un signe de dollar ($), que nous devons supprimer si nous voulons exécuter des requêtes de plage. Nous pouvons utiliser un pipeline d'acquisition pour cela. Notez que nous y faisons référence dans notre nouveau fichier de configuration du crawler ci-dessus :
PUT _ingest/pipeline/pricing-pipeline
{
"processors": [
{
"script": {
"source": """
ctx['price'] = ctx['price'].replace("$","")
"""
}
}
]
}Nous pouvons exécuter cette commande dans notre cluster Elasticsearch de production. Pour celui de développement, comme il est éphémère, nous pouvons intégrer la création du pipeline dans le fichier docker-compose.yml en ajoutant le service suivant. Notez que nous avons également ajouté un depends_on au service crawler afin qu'il démarre après la création réussie du pipeline.
crawler:
image: docker.elastic.co/integrations/crawler:0.4.2
environment:
- ES_HOST=http://es01:9200
- CRAWLER_JRUBY_OPTS=--server
container_name: crawler
volumes:
- ./config:/home/app/config
networks: [esnet]
entrypoint: ["/home/app/bin/crawler", "crawl", "/home/app/config/crawl-config-final.yml"]
depends_on:
pipeline-init:
condition: service_completed_successfully
stdin_open: true
tty: true
pipeline-init:
image: curlimages/curl:latest
depends_on:
es01:
condition: service_healthy
networks: [esnet]
entrypoint: >
sh -c "
echo 'Creating ingest pipeline...';
curl -s -X PUT http://es01:9200/_ingest/pipeline/pricing-pipeline \\
-H 'Content-Type: application/json' \\
-d '{\"processors\":[{\"script\":{\"source\":\"ctx.price = ctx.price.replace(\\\"$\\\", \\\"\\\")\"}}]}';
echo 'Pipeline created!';
"Exécutons maintenant `./local.sh` pour voir les changements localement :

C'est très bien ! Poussons maintenant la modification :
git add crawler-config.yml
git commit -m "added price CSS selector"
git pushPour confirmer que tout fonctionne, vous pouvez vérifier votre Kibana de production, qui devrait refléter les changements et afficher le prix comme un nouveau champ sans le signe du dollar.
Conclusion
Elastic Open Web Crawler vous permet de gérer votre crawler en tant que code, ce qui signifie que vous pouvez automatiser l'ensemble du pipeline - du développement au déploiement - et ajouter des environnements locaux éphémères et des tests sur les données explorées de manière programmatique, pour ne citer que quelques exemples.
Vous êtes invités à cloner le dépôt officiel et à commencer à indexer vos propres données à l'aide de ce flux de travail. Vous pouvez également lire cet article pour apprendre comment effectuer une recherche sémantique sur les index produits par le crawler.




