![[Amazon Bedrock] AgentCore Browser × browser-use で 競合サービスのWebページの変更を検知してSlackに通知する仕組みを作ってみました](https://devio2024-media.developers.io/image/upload/f_auto,q_auto,w_3840/v1776473949/user-gen-eyecatch/jphjxhkgzwstku97zkhg.png)
[Amazon Bedrock] AgentCore Browser × browser-use で 競合サービスのWebページの変更を検知してSlackに通知する仕組みを作ってみました
1 はじめに
製造ビジネステクノロジー部の平内(SIN)です。
競合サービスの料金改定、利用規約の変更、新機能のリリース。「あのページ、いつの間にか変わっていた」という経験は、多くの方にあるのではないでしょうか。
RSS が提供されていないページや、API が存在しないサービスの場合、定期的にブラウザで確認するしかなく、見落としなく行うのは、結構な作業になるかも知れません。

従来、こうした Web ページの監視には HTML スクレイピングや Headless ブラウザ(Playwright / Selenium など)が使われていましたが、色々と課題がありました。
- CSS セレクタや XPath を事前に調査して指定する必要がある
- ページ構造が変わるとセレクタが壊れるため、常にメンテナンスが必要
- ブラウザ等の環境を用意する必要がある
しかし、AgentCore Browser を使うことで、これらの課題を根本的に解決できます。CSS セレクタを一切書かずに、自然言語で指示するだけで、AI がページの DOM を解析してテキストを抽出します。ページ構造が変わっても、AI が柔軟に対応するためメンテナンスが不要です。
| 観点 | HTML スクレイピング | Headless ブラウザ | AgentCore Browser |
|---|---|---|---|
| セレクタの事前調査 | 必要 | 必要 | 不要 |
| ページ構造変更時 | 修正必要 | 修正必要 | AI が自動対応 |
| JavaScript ページ | 非対応 | 対応 | 対応 |
| ブラウザ環境の管理 | 不要 | 自前管理 | AWS マネージド |
今回は、Amazon Bedrock AgentCore Browser と browser-use を使用して、Web ページを定期的に監視し、変更があった場合に Slack に通知するシステムを作ってみました。
下記は、上記の競合ページが変化した時にSlackに到着したメッセージです。

2 アーキテクチャ
今回構築したシステムの全体構成は以下の通りです。

EventBridge が1日1回 Lambda をトリガーし、Lambda は AgentCore Runtime 上のエージェントを呼び出します。エージェントは4つのツールを使って、ページ取得・差分比較・保存・通知を自律的に実行します。
主なコンポーネントは以下の通りです。
| コンポーネント | 役割 |
|---|---|
| EventBridge | 1日1回の定期トリガー |
| Lambda | AgentCore Runtime を呼び出すトリガー |
| AgentCore Runtime | Strands Agent によるエージェント実行環境 |
| AgentCore Browser | AWS マネージドのブラウザ環境でページを取得 |
| Amazon Bedrock (Claude) | LLM による判断・テキスト抽出 |
| DynamoDB | 前回のページ内容を保存 |
| Slack | 変更の通知先 |
エージェントは2つの LLM を使い分けています。Strands Agent のオーケストレーション(ツール選択・差分比較)には BedrockModel を、AgentCore Browser でのブラウザ操作には ChatAWSBedrock を使用しています。
3 構築
サンプルコードは GitHub で公開しています。
$ git clone https://github.com/furuya02/agentcore-browser-page-monitor.git
$ cd agentcore-browser-page-monitor
(1) 監視対象ページの準備
最初に、監視対象となるサンプルの料金ページを S3 にデプロイします。
(ここでは、バケット名をagentcore-browser-page-monitor-20260416としていますが、自由に決定してください)
cd target-page
./deploy.sh <バケット名>

(2) AgentCore プロジェクトの作成
agentcore create でプロジェクトを作成すると、pagemonitor/ ディレクトリが生成されます。この中のエージェントコードを、リポジトリの src/ にあるコードで上書きします。
agentcore-browser-page-monitor/
├── src/ ← このコードを生成されたpagemonitorに上書きする
│ ├── main.py
│ ├── model/load.py
│ └── pyproject.toml
├── pagemonitor/ ← agentcore create で生成される
│ ├── app/pagemonitor/
│ │ ├── main.py
│ │ ├── model/load.py
│ │ └── pyproject.toml
│ └── agentcore/
│ ├── agentcore.json
│ └── cdk/
├── cdk/ ← 周辺インフラ(Lambda, EventBridge, DynamoDB)
└── target-page/ ← 監視対象ページ
$ agentcore create --name pagemonitor --defaults --build CodeZip --output-dir .
$ cd pagemonitor
# リポジトリのエージェントコードで上書き
$ cp -f ../src/main.py app/pagemonitor/main.py
$ cp -f ../src/model/load.py app/pagemonitor/model/load.py
$ cp -f ../src/pyproject.toml app/pagemonitor/pyproject.toml
# 不要な生成ファイルを削除
$ rm -rf app/pagemonitor/mcp_client
(3) Slack Incoming Webhook の準備
Slack で Incoming Webhooks を有効化し、通知先チャンネルを指定して Webhook URL(https://hooks.slack.com/services/...)を発行します。発行された URL は次の手順で SLACK_WEBHOOK_URL に設定します。
参考 Slack Incoming Webhook セットアップ手順
(4) 環境変数設定とデプロイ
agentcore/agentcore.json の runtimes[] に環境変数を追加し、ランタイム名の重複を避けるため "name" を "pagemonitor" から "agent" に変更します。
"runtimes": [
{
"name": "agent",
"build": "CodeZip",
"entrypoint": "main.py",
"codeLocation": "app/pagemonitor/",
"runtimeVersion": "PYTHON_3_13",
"networkMode": "PUBLIC",
"protocol": "HTTP",
"envVars": [
{"name": "DYNAMODB_TABLE", "value": "PageMonitorState"},
{"name": "SLACK_WEBHOOK_URL", "value": "<Webhook URL>"},
{"name": "MONITOR_URL", "value": "https://<バケット名>.s3.ap-northeast-1.amazonaws.com/index.html"}
]
}
]
デプロイを実行します。
$ agentcore deploy
agentcore deployでデプロイされたPageMonitorStackは、Cloudformationのスタック一覧で確認できます。

エージェントは、AgentCoreのランタイムに一覧されます。

一覧から Agent を選択すると詳細画面が開き、Runtime ARN が確認できます。後続の CDK デプロイで使用するのでコピーして控えておきます。

(5) 権限追加
Agentのロールには、AgentCore Browser と DynamoDB の権限追加が必要です。
まずは、先のPageMonitorStackの画面でロール名を確認します。

<ロール名> と <アカウントID>(AWS アカウントのID)を置き換え、以下のコマンドで権限を追加します。
# AgentCore Browser の権限を追加
$ aws iam put-role-policy \
--role-name "<ロール名>" \
--policy-name "AgentCoreBrowserAccess" \
--policy-document '{
"Version": "2012-10-17",
"Statement": [{"Effect": "Allow", "Action": "bedrock-agentcore:*", "Resource": "*"}]
}'
# DynamoDB の権限を追加
$ aws iam put-role-policy \
--role-name "<ロール名>" \
--policy-name "DynamoDBPageMonitorAccess" \
--policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["dynamodb:GetItem", "dynamodb:PutItem"],
"Resource": "arn:aws:dynamodb:ap-northeast-1:<アカウントID>:table/PageMonitorState"
}]
}'
(6) インフラの構築(CDK)
Lambda、EventBridge、DynamoDB は CDK でデプロイします。
cd ../cdk
pnpm install
pnpm cdk deploy --parameters AgentCoreRuntimeArn=<Runtime ARN>
以下のリソースが作成されます。
| リソース | 名前 | 役割 |
|---|---|---|
| Lambda | page-monitor-trigger |
AgentCore Runtime を呼び出すトリガー |
| EventBridge Rule | 1日1回 | Lambda の定期実行スケジュール |
| DynamoDB Table | PageMonitorState |
前回のページ内容を保存 |
| IAM Role | 自動生成 | Lambda の実行ロール(bedrock-agentcore:InvokeAgentRuntime 権限付き) |
Lambda は AgentCore Runtime を呼び出すだけの薄いトリガーです。エージェントのロジックは全て AgentCore Runtime 側に配置されています。
def handler(event, context):
config = Config(read_timeout=600, connect_timeout=60)
client = boto3.client("bedrock-agentcore", region_name="ap-northeast-1", config=config)
client.invoke_agent_runtime(
agentRuntimeArn=RUNTIME_ARN,
payload=json.dumps({}).encode(),
contentType="application/json",
accept="application/json",
)
4 動作確認
(1) 初回実行
Lambda のテストコンソールから {} を送信して実行します。初回実行ではページ内容が DynamoDB に保存され、Slack 通知は送信されません。

(2) 変更検知テスト
target-page/index.html の料金を変更して S3 に再デプロイし、再度 Lambda を実行すると、変更内容が Slack に通知されます。

DynamoDBには、最後に確認した状態が保存されています。

5 エージェントコード(main.py)の解説
エージェントは Strands Agents フレームワークで構築されており、4つのツールを持っています。さらに、ブラウザ操作のために内部で browser-use のエージェントを呼び出す、2層構造になっています。
詳しい実装は下記のリポジトリを参照してください。
- src/main.py — エージェント本体のコード(4つのツール + エントリポイント)
- docs/browser-use.md — AgentCore Browser × browser-use の詳解ドキュメント
(1) 2層のオーケストレーション構造
| 層 | フレームワーク | 役割 | 判断するもの |
|---|---|---|---|
| 外側 | Strands Agent | 4つのツールをどの順序で呼ぶか、変更の有無をどう判断するか、通知するかどうか | 業務ロジック |
| 内側 | browser-use Agent(BrowserUseAgent) | ページを開いてテキストを抽出するための具体的なブラウザ操作 | ブラウザ操作 |

外側と内側のエージェントはそれぞれ独立した LLM を持ち、別々の判断ループを回しています。
(2) browse_page ツール
AgentCore Browser を使って Web ページのテキスト情報を抽出する、このシステムの中核となるツールです。内側のオーケストレーションを担う BrowserUseAgent はここで生成します。
@tool
async def browse_page(url: str) -> str:
client = BrowserClient(region=AWS_REGION)
bu_session = None
try:
client.start()
ws_url, headers = client.generate_ws_headers()
profile = BU_BrowserProfile(headers=headers, timeout=180000,
enable_default_extensions=False)
bu_session = BU_BrowserSession(cdp_url=ws_url, browser_profile=profile)
await bu_session.start()
bedrock_chat = ChatAWSBedrock(
model=LLM_MODEL_ID,
aws_region=AWS_REGION,
session=boto3.Session(region_name=AWS_REGION),
)
browser_agent = BrowserUseAgent(
task=f"ページの全テキスト情報を構造化して抽出してください。\nURL: {url}",
llm=bedrock_chat,
browser_session=bu_session,
)
result = await browser_agent.run()
return str(result)
finally:
# ... セッションのクリーンアップ
BrowserClient が AgentCore Browser のセッションを管理し、WebSocket 経由で AWS マネージドのブラウザに接続します。BrowserUseAgent は自然言語の指示に従ってページを操作し、テキストを抽出します。
LLM には browser_use.llm.aws.chat_bedrock.ChatAWSBedrock を使用しています。browser-use で AWS Bedrock を LLM として利用する場合、browser-use 0.12.6 では組み込みの ChatAWSBedrock を使用します(browser-use 公式ドキュメント - Supported Models 参照)。
from browser_use.llm.aws.chat_bedrock import ChatAWSBedrock
(3) システムプロンプト
外側の Strands Agent の行動は、以下のシステムプロンプトで制御しています。
SYSTEM_PROMPT = """あなたは Web ページの変更を監視するエージェントです。
1. browse_page で指定 URL のページ内容を取得
2. get_previous_content で前回の内容を取得
3. 比較: 初回→通知不要 / 変更なし→報告 / 変更あり→要約
4. save_content で保存
5. 変更時のみ notify_slack で通知
"""
ツールの呼び出し順序を指示しつつ、変更の有無の判断や通知メッセージの生成は AI に任せています。初回実行時は前回データがないため通知をスキップし、変更がある場合のみ差分を要約して Slack に送信するという判断を、エージェントが自律的に行います。
6 気になった所
検証中にいくつか気になった点がありましたので、少し紹介させてください。
(1) HTTP URL のブロック
AgentCore Browser のリモートブラウザは HTTP URL をブロックする(net::ERR_BLOCKED_BY_CLIENT)ため注意が必要です。
当初、S3のWebページにHTTPでアクセスしていてうまく動作できませんでした。
最終的には、HTTPS でアクセスできる S3 のオブジェクト URL(https://<バケット名>.s3.ap-northeast-1.amazonaws.com/index.html)を MONITOR_URL に指定しました。
(2) IAM 権限の追加
agentcore deploy で作成される実行ロールは、AgentCore Browser(bedrock-agentcore:StartBrowserSession 等)や DynamoDB の権限が含まれていないため、手動でポリシーを追加する必要があります。
agentcore.json の executionRoleArn であらかじめ定義したロールを指定することは可能ですが、この場合、信頼ポリシーなどちゃんと設定する必要があって、自動生成の手軽さは、やや損なわれそうです。
この辺の自動化は、agentcore create で生成される CDK のコード等を編集することで対応できそうですが、色々工夫が必要そうです。
(3) Lambda の ReadTimeoutError
AgentCore Runtime のエージェントの処理(ブラウザ操作 + LLM 推論)は、やや時間を要するため、boto3 のデフォルト読み取りタイムアウト(60秒)では、 ReadTimeoutError が発生してしまいました。
今回は、Config(read_timeout=600) を設定しました。
7 最後に
Amazon Bedrock AgentCore Browser と browser-use を使って、Web ページの変更を自動検知して Slack に通知するシステムを構築しました。
従来のスクレイピングと比較した場合の最大の違いは、CSS セレクタのメンテナンスが不要な点です。ページ構造が変わっても AI が柔軟に対応するため、一度構築すれば、殆どメンテナンスフリーで運用できると思います。
AgentCore Browser は「API がないサイトの情報をセレクタなしで自動取得できる」という点で、今回の料金ページ監視以外にも幅広い応用が考えられます。
| ユースケース | 監視対象 | 検知したいこと |
|---|---|---|
| 競合の料金改定 | SaaS の Pricing ページ | プラン・価格の変更 |
| 規約変更の検知 | 利用規約・プライバシーポリシー | 文言の追加・削除 |
| 採用動向の把握 | 競合の採用ページ | 新しいポジションの追加 |
| 法改正のモニタリング | 官公庁の通達ページ | 新しい通達・ガイドラインの公開 |
| 在庫・入荷の監視 | EC サイトの商品ページ | 在庫状況・価格の変化 |
いずれのケースでも、監視対象の URL を変更するだけで対応できます。ページ構造がサイトリニューアル等で変わっても、AI が自動的に適応するため、メンテナンスの手間がかかりません。
サンプルコードは以下の GitHub リポジトリで公開しています。










