Elastic Open Web Crawler をコードとして
GitHub Actions を使用して Elastic Open Crawler の構成を管理する方法を学びます。これにより、リポジトリに変更をプッシュするたびに、その変更がクローラーのデプロイされたインスタンスに自動的に適用されます。
Elastic Open Web Crawlerとその CLI 駆動型アーキテクチャを使用すると、バージョン管理されたクローラー構成とローカル テストを備えた CI/CD パイプラインを実現するのが非常に簡単になります。
従来、クローラーの管理は手動で行われ、エラーが発生しやすいプロセスでした。これには、UI で直接構成を編集することや、クロール構成の複製、ロールバック、バージョン管理などに苦労することが含まれていました。クローラー構成をコードとして扱うことで、ソフトウェア開発で期待されるのと同じ利点(再現性、追跡可能性、自動化)が得られ、この問題が解決されます。
このワークフローにより、ロールバック、バックアップ、移行などのタスクを CI/CD パイプラインに Open Web Crawler を簡単に組み込むことができるようになります。これらのタスクは、Elastic Web Crawler や App Search Crawler などの以前の Elastic Crawler では非常に困難でした。
この記事では、次の方法を学習します。
GitHubを使用してクロール設定を管理する
デプロイ前にパイプラインをテストするためのローカルセットアップを用意する
メインブランチに変更をプッシュするたびに、新しい設定でウェブクローラーを実行するための本番環境設定を作成します。
プロジェクトのリポジトリはこちらです。執筆時点では、Elasticsearch 9.1.3とOpen Web Crawler 0.4.2を使用しています。
要件
Dockerデスクトップ
Elasticsearchインスタンス
SSH アクセス(AWS EC2 など)と Docker がインストールされた仮想マシン
ステップ
フォルダ構造
クローラー構成
Docker-compose ファイル (ローカル環境)
Githubアクション
ローカルテスト
本番環境へのデプロイ
変更と再展開
フォルダ構造
このプロジェクトでは、次のファイル構造になります。
├── 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クローラー構成
crawler-config.yml,の下に次の内容を入力します。
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これは、製品の模擬サイトであるhttps://web-scraping.dev/productsからクロールします。最初の 3 つの製品ページのみをクロールします。max_crawl_depth設定により、クローラーはseed_urlsとして定義されたページよりも多くのページを検出することがなくなり、それらのページ内のリンクを開かなくなります。
Elasticsearch hostとapi_keyは、スクリプトを実行している環境に応じて動的に設定されます。

Docker-compose ファイル (ローカル環境)
ローカルdocker-compose.yml,には、クローラーと単一の Elasticsearch クラスター + Kibana をデプロイして、本番環境にデプロイする前にクロール結果を簡単に視覚化できるようにします。
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: bridgeElasticsearch の実行準備ができるまでクローラーが待機する方法に注意してください。
Githubアクション
ここで、新しい設定をコピーし、メインにプッシュするたびに仮想マシンでクローラーを実行する GitHub アクションを作成する必要があります。これにより、手動で仮想マシンにアクセスしてファイルを更新し、クローラーを実行する必要がなくなり、常に最新の構成が展開されます。仮想マシンプロバイダーとして AWS EC2 を使用します。
最初のステップは、ホスト ( VM_HOST )、マシン ユーザー ( VM_USER )、SSH RSA キー ( VM_KEY )、Elasticsearch ホスト ( ES_HOST )、Elasticsearch API キー ( ES_API_KEY ) を GitHub Action シークレットに追加することです。

この方法により、アクションはサーバーにアクセスして新しいファイルをコピーし、クロールを実行できるようになります。
それでは、 .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
EOFこのアクションは、クローラー構成ファイルに変更をプッシュするたびに、次の手順を実行します。
yml config に Elasticsearch ホストと API キーを入力します。
configフォルダをVMにコピーします
SSH経由でVMに接続します
リポジトリからコピーした設定でクロールを実行します
ローカルテスト
クローラーをローカルでテストするために、Docker からローカルのものを Elasticsearch ホストに入力してクロールを開始する bash スクリプトを作成しました。./local.shを実行して実行できます。
#!/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 --buildKibana DevTools を見て、 web-crawler-indexが正しく入力されていることを確認しましょう。

本番環境へのデプロイ
これで、メイン ブランチにプッシュする準備が整いました。これにより、仮想マシンにクローラーがデプロイされ、Serverless Elasticsearch インスタンスにログの送信が開始されます。
git add .
git commit -m "First commit"
git pushこれにより、GitHub アクションがトリガーされ、仮想マシン内でデプロイ スクリプトが実行され、クロールが開始されます。
アクションが実行されたかどうかを確認するには、GitHub リポジトリにアクセスして「アクション」タブにアクセスします。

変更と再展開
お気づきかもしれませんが、各製品のpriceはドキュメントの本文フィールドの一部です。価格を別のフィールドに保存して、それに対してフィルターを実行できるようにするのが理想的です。
抽出ルールを使用してproduct-price CSS クラスから価格を抽出するために、 crawler.ymlファイルに次の変更を追加してみましょう。
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また、価格にはドル記号 ( $ ) が含まれていますが、範囲クエリを実行する場合はこれを削除する必要があります。そのために、取り込みパイプラインを使用できます。上記の新しいクローラー構成ファイルでこれを参照していることに注意してください。
PUT _ingest/pipeline/pricing-pipeline
{
"processors": [
{
"script": {
"source": """
ctx['price'] = ctx['price'].replace("$","")
"""
}
}
]
}このコマンドは本番環境の Elasticsearch クラスターで実行できます。開発用の場合は一時的なものなので、次のサービスを追加することで、パイプライン作成部分をdocker-compose.ymlファイルにすることができます。パイプラインが正常に作成された後にクローラー サービスが起動するように、 depends_onもクローラー サービスに追加されていることに注意してください。
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!';
"次に、 `./local.sh`を実行してローカルで変更を確認してみましょう。

素晴らしい!変更をプッシュしてみましょう。
git add crawler-config.yml
git commit -m "added price CSS selector"
git pushすべてが機能していることを確認するには、本番環境の Kibana をチェックします。変更が反映され、価格がドル記号なしの新しいフィールドとして表示されるはずです。
まとめ
Elastic Open Web Crawler を使用すると、クローラーをコードとして管理できるため、開発からデプロイメントまでのパイプライン全体を自動化したり、一時的なローカル環境を追加したり、クロールされたデータに対してプログラムでテストを実行したりすることができます。
公式リポジトリのクローンを作成し、このワークフローを使用して独自のデータのインデックス作成を開始してください。クローラーによって生成されたインデックスに対してセマンティック検索を実行する方法については、この記事を読むこともできます。




