Blog

Elastic Open Web Crawler als Code

Erfahren Sie, wie Sie GitHub Actions verwenden, um Elastic Open Crawler-Konfigurationen zu verwalten, sodass Änderungen, die wir in das Repository übertragen, automatisch auf die bereitgestellte Instanz des Crawlers angewendet werden.

Mit Elastic Open Web Crawler und seiner CLI-gesteuerten Architektur lassen sich versionierte Crawler-Konfigurationen und eine CI/CD-Pipeline mit lokalen Tests jetzt recht einfach realisieren.

Traditionell war die Verwaltung von Webcrawlern ein manueller, fehleranfälliger Prozess. Dabei ging es um das direkte Bearbeiten von Konfigurationen in der Benutzeroberfläche sowie um das Klonen von Crawl-Konfigurationen, das Zurücksetzen von Einstellungen, die Versionsverwaltung und vieles mehr. Die Behandlung von Crawler-Konfigurationen als Code löst dieses Problem, indem sie die gleichen Vorteile bietet, die wir von der Softwareentwicklung erwarten: Wiederholbarkeit, Nachvollziehbarkeit und Automatisierung.

Dieser Workflow erleichtert es, den Open Web Crawler in Ihre CI/CD-Pipeline für Rollbacks, Backups und Migrationen einzubinden – Aufgaben, die mit früheren Elastic Crawlern wie dem Elastic Web Crawler oder dem App Search Crawler wesentlich schwieriger waren.

In diesem Artikel erfahren Sie, wie Sie:

  • Verwalten Sie unsere Crawl-Konfigurationen mit GitHub.

  • Eine lokale Testumgebung für Pipelines vor der Bereitstellung einrichten

  • Wir erstellen eine Produktionsumgebung, um den Webcrawler jedes Mal mit neuen Einstellungen auszuführen, wenn wir Änderungen an unseren Hauptzweig übertragen.

Das Projekt-Repository finden Sie hier. Zum Zeitpunkt der Erstellung dieses Dokuments verwende ich Elasticsearch 9.1.3 und Open Web Crawler 0.4.2.

Voraussetzungen

  • Docker Desktop

  • Elasticsearch-Instanz

  • Virtuelle Maschine mit SSH-Zugriff (z. B. AWS EC2) und installiertem Docker

Schritte

  1. Ordnerstruktur

  2. Raupenkonfiguration

  3. Docker-Compose-Datei (lokale Umgebung)

  4. GitHub Actions

  5. Lokale Tests

  6. Bereitstellung in der Produktionsumgebung

  7. Änderungen vornehmen und erneut bereitstellen

Ordnerstruktur

Für dieses Projekt werden wir folgende Dateistruktur verwenden:

├── 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 crawler

Raupenkonfiguration

Unter crawler-config.yml, wird Folgendes eingetragen:

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/3

Dies führt einen Crawl von https://web-scraping.dev/products durch, einer simulierten Website für Produkte. Wir werden nur die ersten drei Produktseiten durchsuchen. Die Einstellung max_crawl_depth verhindert, dass der Crawler mehr Seiten als die als seed_urls definierten Seiten entdeckt, indem er die darin enthaltenen Links nicht öffnet.

Elasticsearch host und api_key werden dynamisch befüllt, abhängig von der Umgebung, in der das Skript ausgeführt wird.

Die Produktseite für „Schokoladenbox“ von der Domain web-scraping.dev, einer Testseite für Web-Scraping. Auf der Seite werden der Produkttitel, das Bild, die Beschreibung sowie die HTML-Elemente für Preis- und Kaufbuttons angezeigt.

Docker-Compose-Datei (lokale Umgebung)

Für die lokale Umgebung docker-compose.yml, werden wir den Crawler und einen einzelnen Elasticsearch-Cluster + Kibana bereitstellen, damit wir unsere Crawling-Ergebnisse vor der Bereitstellung in der Produktionsumgebung einfach visualisieren können.

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: bridge

Beachten Sie, wie der Crawler wartet, bis Elasticsearch bereit ist, ausgeführt zu werden.

GitHub Actions

Nun müssen wir eine GitHub-Aktion erstellen, die die neuen Einstellungen kopiert und den Crawler bei jedem Push auf den Hauptzweig in unserer virtuellen Maschine ausführt. Dadurch wird sichergestellt, dass wir immer die aktuellste Konfiguration im Einsatz haben, ohne manuell in die virtuelle Maschine eingreifen zu müssen, um Dateien zu aktualisieren und den Crawler auszuführen. Wir werden AWS EC2 als Anbieter virtueller Maschinen verwenden.

Der erste Schritt besteht darin, den Host (VM_HOST), den Maschinenbenutzer (VM_USER), den SSH-RSA-Schlüssel (VM_KEY), den Elasticsearch-Host (ES_HOST) und den Elasticsearch-API-Schlüssel (ES_API_KEY) zu den GitHub Action Secrets hinzuzufügen:

Eine Konfigurationsseite für „Aktionen, Geheimnisse und Variablen“, auf der Repository-Geheimnisse wie VM_HOST, VM_KEY und VM_USER über eine webbasierte Oberfläche angezeigt werden.

Auf diese Weise kann die Aktion auf unseren Server zugreifen, um die neuen Dateien zu kopieren und den Crawl auszuführen.

Nun erstellen wir unsere .github/workflows/deploy.yml -Datei:

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
          EOF

Diese Aktion führt jedes Mal die folgenden Schritte aus, wenn wir Änderungen an der Crawler-Konfigurationsdatei vornehmen:

  1. Tragen Sie den Elasticsearch-Host und den API-Schlüssel in die YAML-Konfiguration ein.

  2. Kopieren Sie den Konfigurationsordner auf unsere VM

  3. Stellen Sie über SSH eine Verbindung zu unserer VM her.

  4. Führen Sie den Crawl mit der Konfiguration aus, die wir gerade aus dem Repository kopiert haben.

Lokale Tests

Um unseren Crawler lokal zu testen, haben wir ein Bash-Skript erstellt, das den Elasticsearch-Host mit dem lokalen Docker-Repository befüllt und einen Crawl startet. Sie können ./local.sh eingeben, um es auszuführen.

#!/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 --build

Schauen wir uns die Kibana DevTools an, um zu bestätigen, dass web-crawler-index korrekt befüllt wurde:

Kibana DevTools-Code zur Bestätigung, dass der Webcrawler-Index korrekt eingerichtet ist.

Bereitstellung in der Produktionsumgebung

Jetzt sind wir bereit, die Änderungen auf den Hauptzweig zu übertragen. Dadurch wird der Crawler in Ihrer virtuellen Maschine bereitgestellt und beginnt, Protokolle an Ihre Serverless Elasticsearch-Instanz zu senden.

git add .
git commit -m "First commit"
git push

Dadurch wird die GitHub-Aktion ausgelöst, die das Bereitstellungsskript innerhalb der virtuellen Maschine ausführt und mit dem Crawling beginnt.

Sie können die Ausführung der Aktion überprüfen, indem Sie zum GitHub-Repository gehen und den Tab „Aktionen“ aufrufen:

Die Aktionen werden im EC2-Tab eines GitHub-Repositorys bereitgestellt.

Änderungen vornehmen und erneut bereitstellen

Vielleicht ist Ihnen aufgefallen, dass die price jedes Produkts Teil des Body-Felds des Dokuments ist. Ideal wäre es, den Preis in einem separaten Feld zu speichern, damit wir Filter darauf anwenden können.

Fügen wir diese Änderung zur Datei crawler.yml hinzu, um Extraktionsregeln zu verwenden, mit denen der Preis aus der CSS-Klasse product-price extrahiert werden kann:

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: html

Wir sehen auch, dass der Preis ein Dollarzeichen ($) enthält, das wir entfernen müssen, wenn wir Bereichsabfragen ausführen wollen. Dafür können wir eine Ingest-Pipeline verwenden. Beachten Sie, dass wir in unserer neuen Crawler-Konfigurationsdatei oben darauf verweisen:

PUT _ingest/pipeline/pricing-pipeline
{
  "processors": [
    {
      "script": {
        "source": """
                ctx['price'] = ctx['price'].replace("$","")
            """
      }
    }
  ]
}

Wir können diesen Befehl in unserem Elasticsearch-Produktionscluster ausführen. Da die Entwicklungsversion ephemer ist, können wir die Pipeline-Erstellung in die docker-compose.yml -Datei integrieren, indem wir den folgenden Dienst hinzufügen. Beachten Sie, dass wir dem Crawler-Dienst auch eine depends_on hinzugefügt haben, damit er erst startet, nachdem die Pipeline erfolgreich erstellt wurde.

 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!';
        "

Führen wir nun `./local.sh` aus, um die Änderung lokal zu sehen:

Führen Sie `./local.sh` aus, um die Preisänderung lokal zu sehen.

Großartig! Jetzt lasst uns die Veränderung vorantreiben:

git add crawler-config.yml
git commit -m "added price CSS selector"
git push

Um sicherzustellen, dass alles funktioniert, können Sie Ihre Produktions-Kibana-Datei überprüfen. Dort sollten die Änderungen sichtbar sein und der Preis als neues Feld ohne Dollarzeichen angezeigt werden.

Fazit

Mit dem Elastic Open Web Crawler können Sie Ihren Crawler als Code verwalten. Das bedeutet, dass Sie die gesamte Pipeline – von der Entwicklung bis zur Bereitstellung – automatisieren und beispielsweise ephemere lokale Umgebungen und Tests anhand der gecrawlten Daten programmatisch hinzufügen können.

Sie sind eingeladen, das offizielle Repository zu klonen und mit der Indizierung Ihrer eigenen Daten mithilfe dieses Workflows zu beginnen. In diesem Artikel erfahren Sie auch, wie Sie eine semantische Suche auf den vom Crawler erzeugten Indizes durchführen.

Zugehörige Inhalte

Anzeigen von Feldern in einem Elasticsearch-Index

Kofi Bartlett

Wie man Daten über Kafka in Elasticsearch einliest

Andre Luiz

Ruby-Skripting in Logstash

Dai Sugimori

Indexvorlagen in Elasticsearch: Wie man zusammensetzbare Vorlagen verwendet

Kofi Bartlett

Wie man Felder eines Elasticsearch-Index anzeigt

JD Armada

Sind Sie bereit, hochmoderne Sucherlebnisse zu schaffen?

Eine ausreichend fortgeschrittene Suche kann nicht durch die Bemühungen einer einzelnen Person erreicht werden. Elasticsearch wird von Datenwissenschaftlern, ML-Ops-Experten, Ingenieuren und vielen anderen unterstützt, die genauso leidenschaftlich an der Suche interessiert sind wie Sie. Lasst uns in Kontakt treten und zusammenarbeiten, um das magische Sucherlebnis zu schaffen, das Ihnen die gewünschten Ergebnisse liefert.

Probieren Sie es selbst aus