🌀

「ブラウザ操作自動化くん」(車輪の再発明):社内AIハッカソン開発レポート

に公開

この記事は「Hacobell Developers Advent Calendar」3日目の記事です。
前日の堀崎さんの記事「定型作業をAIで効率化する「ブックマークレット自動作成くん」:社内AIハッカソン開発レポート」の続編となっています。こちらもぜひ合わせてご覧ください。

はじめに

本題に入る前に、少しだけ背景を紹介させてください。 先日ハコベルでは、社内「1Day AIハッカソン」を開催しました。
https://note.com/hacobell/n/n5fa4579fbffc

朝イチでチームビルディングをして、夕方には成果発表というタイトなスケジュールの中で、私のチームは「ブラウザ上の定型作業を誰でも簡単に自動化できるツールの開発」に挑みました。本記事は、その開発後半戦の技術的な奮闘記です。

ブックマークレット生成の限界

1Dayハッカソン終了の2時間ほど前、私のチームは短い時間の中で「自然言語でブックマークレットを生成する」というアイデアを形にできて安堵していました。しかし同時に、自動化できる操作には限界があることにも気付いていました。

HTMLと自然言語の指示からブックマークレットを生成するという仕様の性質上、自動化は一時的な画面内の操作にとどまってしまいます。
多くの業務フローは Aページで操作 → Bページへ遷移 → Cボタンを押す のような連続的な操作が含まれているため、より実践的な機能を提供するには追加の開発が必要でした。

技術的な壁と方針転換

そこで私たちは方針転換を迫られました。ここでの技術的な意思決定は、大きく2つのステップを経ています。

1. ページ遷移の壁:拡張機能へのシフト

ブックマークレットはページ遷移が発生すると実行コンテキストが失われてしまいます。連続的な操作を自動化するためには、ページが切り替わっても生存し続けるコンテキストが必要です。 そこで、ブラウザのバックグラウンドで動作可能な「Chrome拡張機能でDOMを操作する」方針にシフトしました。

2. CSPの壁:独自エンジンの実装へ

拡張機能化にあたり、最初は無邪気に「生成AIで操作用JavaScriptを生成して実行すればいいいのでは?」と考えました。しかし、このアイデアはすぐに没になります。ほとんどのWebサイトではCSP(Content Security Policy)によって守られており、外部から注入されたスクリプトの実行は禁じられているからです。
ここで、最終的には「ブラウザ操作エンジンをChrome拡張機能上で独自実装するしかない」という結論に至ります。JSをそのまま実行するのではなく、JSONなどで定義された「操作手順」を読み込み、あらかじめ拡張機能内に実装しておいたDOM操作関数を呼び出すという仕組みです。

独自エンジンの実装

ひと昔前であれば、小一時間で以下の機能を実装する芸当など到底できなかったでしょう。

  • 拡張機能でユーザー操作をレコードしてjson出力
  • jsonを入力としてDOMを操作する実行エンジン

しかし、今ならClaude Codeをはじめとするコーディングエージェントがいます。
このハッカソンは、開発プロセスにおけるAIの利活用も目的であったため、「残り時間でどこまで実装できるか」という技術的な挑戦も含めて、この課題に取り組むことにしました。

結果としてはさすがClaude Code、レコード機能と実行エンジンを、デモができるレベルまで爆速で実装してくれました。
例えば google.comhogeと検索する操作を自動化するときは、以下のように使います。

① Chromeのdebugger API[1]を使って画面のキャプチャを開始。clickやnavigateなどのイベントを検知します。

② 停止ボタンを押すと、以下のようなjsonが出力されます

{
  "title": "Recording 2025-11-25T09:56:53.793Z",
  "steps": [
    {
      "type": "click",
      "target": "main",
      "selectors": [
        [
          "#APjFqb"
        ],
        [
          "[aria-label=\"検索\"]"
        ],
        [
          "div.L3eUgb:nth-child(3) > div.o3j99.ikrT4e.om7nvf:nth-child(5) > form:nth-child(3) > div:nth-child(1) > div.A8SBwf.sbfc.emcav:nth-child(1) > div.RNNXgb:nth-child(2) > div.SDkEP:nth-child(1) > div.a4bIc:nth-child(2) > textarea.gLFyf:nth-child(3)"
        ],
        [
          "xpath///*[@id=\"APjFqb\"]"
        ]
      ],
      "offsetX": 1167,
      "offsetY": 408,
      "button": "primary"
    },
    {
      "type": "change",
      "target": "main",
      "selectors": [
        [
          "#APjFqb"
        ],
        [
          "[aria-label=\"検索\"]"
        ],
        [
          "div.L3eUgb:nth-child(3) > div.o3j99.ikrT4e.om7nvf:nth-child(5) > form:nth-child(3) > div:nth-child(1) > div.A8SBwf.sbfc.emcav:nth-child(1) > div.RNNXgb:nth-child(2) > div.SDkEP:nth-child(1) > div.a4bIc:nth-child(2) > textarea.gLFyf:nth-child(3)"
        ],
        [
          "xpath///*[@id=\"APjFqb\"]"
        ]
      ],
      "value": "hoge"
    },
    {
      "type": "navigate",
      "url": "https://www.google.com/search?q=hoge&..."
    }
  ]
}

③ 実行ボタンを押すと、jsonを解析して自動でブラウザを操作します。

ワークフローにするとこんな感じです
①と②でrecordしてjsonを出力するまで

③実行エンジンでの実行(複数ページ)

実装のポイントは以下の3点です。

  • イベントリスナーによる記録: mousedown, keydown などのイベントを拡張機能側でキャプチャし、対象要素のセレクタ(XPathやCSSセレクタ)とアクションの種類を記録します。
  • JSONによる中間表現: 操作内容をJSONとして保持することで、将来的にLLMが「操作JSON」を直接生成する発展性も持たせています。
  • 独自実行エンジンの実装: CSPに抵触しないよう、evalなどは使用せず、拡張機能のContent ScriptがJSONをパースし、document.querySelectorで要素を特定してclick()メソッドやdispatchEventを発火させる仕組みを構築しました。

まとめ

正直に言えば、完成したプロトタイプはページ遷移のタイムラグ(Wait処理)の調整が甘かったり、複雑なDOM構造では要素が取得できなかったりと、まだ実用に耐えられる品質ではありません。 また、前述の通り「それ、Chrome DevToolsでできるよ」という機能でもあります。
しかし、「操作エンジンの独自実装」というヘビーなタスクを、わずか1〜2時間で形にできたこと。これが最大の収穫だったと感じています。

明日は、坂東さんからSlackのHuddle運用についての記事が公開される予定です!お楽しみに!

脚注
  1. https://developer.chrome.com/docs/extensions/reference/api/debugger?hl=ja ↩︎

Hacobell Developers Blog

Discussion