[Amazon Bedrock] AgentCore Browser × browser-use で 競合サービスのWebページの変更を検知してSlackに通知する仕組みを作ってみました

[Amazon Bedrock] AgentCore Browser × browser-use で 競合サービスのWebページの変更を検知してSlackに通知する仕組みを作ってみました

2026.04.18

1 はじめに

製造ビジネステクノロジー部の平内(SIN)です。

競合サービスの料金改定、利用規約の変更、新機能のリリース。「あのページ、いつの間にか変わっていた」という経験は、多くの方にあるのではないでしょうか。

RSS が提供されていないページや、API が存在しないサービスの場合、定期的にブラウザで確認するしかなく、見落としなく行うのは、結構な作業になるかも知れません。

001

従来、こうした 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に到着したメッセージです。

002

2 アーキテクチャ

今回構築したシステムの全体構成は以下の通りです。

003

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 で公開しています。

https://github.com/furuya02/agentcore-browser-page-monitor

$ 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 <バケット>

004

(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.jsonruntimes[] に環境変数を追加し、ランタイム名の重複を避けるため "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のスタック一覧で確認できます。

006

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

005

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

008

(5) 権限追加

Agentのロールには、AgentCore Browser と DynamoDB の権限追加が必要です。

まずは、先のPageMonitorStackの画面でロール名を確認します。

007

<ロール名><アカウント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 通知は送信されません。

009

(2) 変更検知テスト

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

010

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

011

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) ページを開いてテキストを抽出するための具体的なブラウザ操作 ブラウザ操作

012

外側と内側のエージェントはそれぞれ独立した 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 のオブジェクト URLhttps://<バケット名>.s3.ap-northeast-1.amazonaws.com/index.html)を MONITOR_URL に指定しました。

(2) IAM 権限の追加

agentcore deploy で作成される実行ロールは、AgentCore Browser(bedrock-agentcore:StartBrowserSession 等)や DynamoDB の権限が含まれていないため、手動でポリシーを追加する必要があります。

agentcore.jsonexecutionRoleArn であらかじめ定義したロールを指定することは可能ですが、この場合、信頼ポリシーなどちゃんと設定する必要があって、自動生成の手軽さは、やや損なわれそうです。

この辺の自動化は、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 リポジトリで公開しています。

https://github.com/furuya02/agentcore-browser-page-monitor

参考リンク

この記事をシェアする

関連記事