Go

chromedpとは?GoでChromeを自動操作する使い方【v0.21対応・新API】

chromedpとは?GoでChromeを自動操作する使い方【v0.21対応・新API】

chromedpは、Chrome DevTools Protocol(CDP)でChromeやChromiumを操作するGoのライブラリです。外部のドライバは要らず、Goのコードだけでページ遷移・入力・クリック・スクリーンショット・PDF出力を書けます。2026年10月のv0.17.0からv0.21.0でAPIが全面的に書き換わり、旧Runやポインタ渡しの取得APIを使ったコードは、そのままではv0.21.0でビルドできません。この記事では、v0.21.0とGo 1.27.2で実際に動かしたコードを使って、新しい書き方・移行手順・つまずきやすいエラーを説明します。

まとめ:chromedpの要点と最新版

  • 最新版:v0.21.0(2026年10月11日)。必要なGoは1.25以上。直接依存はcdprotoだけで、Go 1.25・1.26ではJSON実装(go-json-experiment)が間接依存に入る(GOEXPERIMENT=jsonv2 指定時を除く)。
  • 書き方が変わった:値を返さない操作は chromedp.Do、値を返す操作は chromedp.Run の戻り値で受け取る。&title のようなポインタ渡しは廃止。
  • セレクタは型で指定:chromedp.ByQuery は無くなり、chromedp.CSS("#id") のように型で検索方法を選ぶ。
  • 既定はヘッドレス:画面を出すときは WithVisibleWindow()。起動したブラウザとは既定でパイプ接続する。
  • 旧コードを動かすだけなら:go get github.com/chromedp/[email protected] で旧API最後の版に固定できる。新規の開発は新APIで書く。

chromedpとは:CDPでChromeを動かすGoライブラリ

chromedpは、Goの関数呼び出しをChrome DevTools Protocolのコマンド(Page.navigate など)に変換してブラウザへ送ります。SeleniumのようにWebDriverを挟まないので、必要な外部プログラムはChrome本体だけです。公式リポジトリはMITライセンスで、スター数は1万3千を超えています(2026年10月時点)。

CDPを使うツールは他にもあり、AIエージェントにブラウザを操作させるChrome DevTools MCPの導入手順と設定も同じプロトコルの上で動きます。ブラウザ自動化の方式全体(WebDriver・CDP・拡張機能・画像認識)を比べたい場合はBrowser Automationの4つの方式と選び方が参考になります。chromedpは、このうちCDP方式をGoから使う実装です。

v0.17.0からの接続方式の変化

v0.17.0以降、chromedpが起動したブラウザとは --remote-debugging-pipe のパイプで通信します。既定ではデバッグ用のポートを開きません。WebSocketは起動済みブラウザへの接続に加え、remote.WebSocket を指定してchromedpからブラウザを起動する場合にも使えます。WebSocketを扱う処理は github.com/chromedp/chromedp/remote パッケージに分かれました。普段の使い方なら remote をインポートする必要はありません。

chromedpのバージョンと必要なGo

2026年10月3日から11日までの9日間に、v0.17.0からv0.21.0まで8本のタグが出ており、版によって必要なGoとAPIが違います。go.mod の go 行をGoモジュールプロキシから版ごとに確認した結果です。

版 公開日 必要なGo API 主な変更
v0.15.1 2026-04-01 1.26 旧 ―
v0.16.0 2026-07-14 1.26 旧 旧API最後の版
v0.17.0 2026-10-03 1.27 新 ジェネリクス化・パイプ接続
v0.18.0 2026-10-03 1.27 新 remoteを別モジュール化
v0.19.0 2026-10-04 1.27 新 PrintToPDF・ExposeFunc等
v0.20.0 2026-10-05 1.25 新 Go要件を1.25へ緩和
v0.21.0 2026-10-11 1.25 新 remoteをコアへ統合

v0.17.0〜v0.19.xのビルドにはGo 1.27以上が必要です。手元がGo 1.25・1.26でも、既定の GOTOOLCHAIN=auto では必要なツールチェーンへ自動的に切り替わる場合があります。最新のv0.21.0はGo 1.25以上で動くので、手元のGoを上げずに使えます。Go本体の版の確認方法はGo 1.27の新機能と最新バージョンの確認方法にまとめています。

chromedpのインストールと最初のプログラム

モジュールを初期化したディレクトリで次を実行します。

go mod init example.com/cdp-demo
go get github.com/chromedp/[email protected]

ページを開いてタイトルを読む最小のプログラムです。遷移のように値を返さない操作は Do、タイトルのように値を返す操作は Run に渡し、戻り値で受け取ります。

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/chromedp/chromedp"
)

func main() {
    ctx, cancel := chromedp.NewContext(context.Background())
    defer cancel()

    if err := chromedp.Do(ctx, chromedp.Navigate("https://example.com")); err != nil {
        log.Fatal(err)
    }
    title, err := chromedp.Run(ctx, chromedp.Title())
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(title)
}

Run が受け取れる操作は1つだけです。複数の操作を順に実行するなら Do(ctx, a, b, c) に並べ、値は最後に Run で読みます。

Chrome本体の探し方とExecPath

chromedpは決まった順でChromeを探します。macOSは /Applications/Chromium.app、次に /Applications/Google Chrome.app。Linuxは headless_shell・chromium・google-chrome などをPATHから探します。WindowsではChromeが無ければMicrosoft Edgeを使います(v0.19.0から)。見つからないと exec: "google-chrome": executable file not found in $PATH で止まるので、そのときは ExecPath で場所を渡します。

opts := append(chromedp.DefaultExecAllocatorOptions[:],
    chromedp.ExecPath("/usr/bin/chrome-headless-shell"),
    chromedp.WindowSize(1280, 800),
)
allocCtx, cancelA := chromedp.NewExecAllocator(context.Background(), opts...)
defer cancelA()
ctx, cancel := chromedp.NewContext(allocCtx)
defer cancel()

chromedpの基本操作:待機・取得・入力・JavaScript

よく使う操作の、v0.21.0での形です。

操作 v0.21.0の書き方 戻り値
遷移 Navigate(url) なし(Doで実行)
表示を待つ WaitVisible(CSS("#a")) なし
クリック Click(CSS("#go")) なし
入力 SendKeys(CSS("#q"), "文字") なし
テキスト取得 Text(CSS("#a")) string
JavaScript Evaluate[int]("式") 指定した型
スクリーンショット FullScreenshot(100) []byte

型付きセレクタ(CSS・ID・JSPath)

セレクタの型で検索方法が決まります。CSS は querySelector の最初の一致、CSSAll は全件、ID はid指定、JSPath はJavaScriptの式です。ただの文字列は旧APIの既定と同じ全文検索として扱われ、CSS・XPath・テキストのどれでも当たります。意図しない要素に当たるのを避けるなら、CSSセレクタは CSS(...) と明示するのが安全です。

フォーム入力とクリック

入力欄に文字を入れて送信し、結果の要素が出るまで待つ例です。手元のテストページで、送信後に q=chromedp が表示されることを確認しました。

err := chromedp.Do(ctx,
    chromedp.Navigate(url),
    chromedp.SendKeys(chromedp.CSS("#q"), "chromedp"),
    chromedp.Click(chromedp.CSS("#go")),
    chromedp.WaitVisible(chromedp.CSS("#r")),
)
if err != nil {
    log.Fatal(err)
}
result, err := chromedp.Run(ctx, chromedp.Text(chromedp.CSS("#r")))

v0.18.0から、Ctrl・Alt・Metaを付けたキー入力では文字が入力されなくなりました。ショートカットを送るコードで文字入力も期待していた場合は、修飾キーを外して送り直します。

JavaScriptの実行とnullの扱い

Evaluate は型引数で戻り値の型を指定します。v0.19.0から、JavaScriptの null を string や int で受けると ErrJSNull が返ります。以前はゼロ値がエラー無しで返っていたので、nullを許すなら *string のようなポインタ型で受けます。

n, err := chromedp.Run(ctx, chromedp.Evaluate[int]("document.querySelectorAll('h1').length"))

// null を string で受けると ErrJSNull
_, err = chromedp.Run(ctx, chromedp.Evaluate[string]("null"))
fmt.Println(errors.Is(err, chromedp.ErrJSNull)) // true

Promiseの完了を待つ場合は Evaluate に chromedp.EvalAwaitPromise を渡します。

chromedpによる動的ページ(SPA)の取得と待機条件

chromedpの要素操作には自動待機があります。Text は対象要素が準備できるまで、Click と SendKeys は対象要素が表示されるまで待ちます。800ミリ秒後に要素を描画するテストページで、WaitVisible を挟まずに10秒の制限時間で Text を呼ぶと、約0.9秒後に描画後のテキストを取得できました。

ctx, cancel = context.WithTimeout(ctx, 10*time.Second)
defer cancel()

if err := chromedp.Do(ctx, chromedp.Navigate(url)); err != nil { // url は検証ページのURL
    log.Fatal(err)
}
// #app .item が描画されるまで Text が待つ
text, err := chromedp.Run(ctx, chromedp.Text(chromedp.CSS("#app .item")))

同じページで制限時間を300ミリ秒にすると、要素が現れる前に context deadline exceeded で失敗しました。失敗の原因は待機の有無ではなく制限時間です。待つのは要素の存在と表示までなので、「一覧の件数が増え終わった」「値が更新された」といったアプリ固有の完了は、Poll で条件式を指定するか、WaitVisible で完了後にだけ出る要素を待ちます。

静的なHTMLならブラウザを使わずHTTPで取得するほうが軽く、GoのスクレイピングフレームワークCollyの設定はCollyの運用設定|robots.txt・レート制限・文字化けを実測で解説で扱っています。収集してよいか、利用規約やrobots.txtをどう扱うかはスクレイピングとクローリング・APIの違いと法務の判断を確認してください。

chromedpのスクリーンショット・PDF出力と形式指定

ページ全体は FullScreenshot、表示範囲だけなら CaptureScreenshot、要素だけなら Screenshot(CSS(...)) を使います。FullScreenshot の引数は画質で、ソースでは100のときPNG、それ以外はJPEGになります。出力の先頭バイトを確かめたところ、100はPNG(89 50 4E 47)、90はJPEG(FF D8 FF)でした。

png, err := chromedp.Run(ctx, chromedp.FullScreenshot(100))
if err != nil {
    log.Fatal(err)
}
if err := os.WriteFile("page.png", png, 0o644); err != nil {
    log.Fatal(err)
}

pdf, err := chromedp.Run(ctx, chromedp.PrintToPDF(
    chromedp.PDFPaper(chromedp.PaperA4),
    chromedp.PDFPrintBackground(),
))
if err != nil {
    log.Fatal(err)
}
if err := os.WriteFile("page.pdf", pdf, 0o644); err != nil {
    log.Fatal(err)
}

PrintToPDF はv0.19.0で追加された操作で、用紙・余白・倍率・ページ範囲・ヘッダーとフッターをオプションで指定できます。PDFPrintBackground は関数なので () が必要です。付け忘れると型エラーになります。同じ版で、ページからGoの関数を呼べる ExposeFunc、コンソール出力と未捕捉の例外をまとめて読む Console、ドラッグ操作の DragAndDrop、タップ操作の Tap も入りました(v0.19.0のリリースノート)。

chromedpのヘッドレス・画面表示・headless-shell

chromedpは既定でヘッドレス起動します。DefaultExecAllocatorOptions に Headless が入っているので、ヘッドレスにするための指定は要りません。デバッグで画面を見たいときは、v0.17.0から追加された WithVisibleWindow() を使います。

ctx, cancel := chromedp.NewContext(context.Background(), chromedp.WithVisibleWindow())
defer cancel()

旧来の Flag("headless", false) では --hide-scrollbars や --mute-audio が残っていました。WithVisibleWindow はこれらを外し、ウィンドウを最大化して開きます。コードを変えずに切り替えるなら、環境変数 CHROMEDP_VISIBLEWINDOW でも同じ動きになります。Linuxで画面(ディスプレイ)が無い環境では、ウィンドウを開けない旨のエラーが返ります。

サーバーやCIでは、Chrome一式の代わりにヘッドレス専用の chrome-headless-shell を使うと軽く済みます。chromedpチームはDocker Hubのchromedp/headless-shellでこれを配布しており、stable・beta・dev のタグと版番号のタグがあります(2026年10月27日に更新)。Linuxの探索順は headless_shell から始まるので、このイメージの中で動かすと ExecPath を書かずに見つかります。

旧APIからv0.21.0へ移行する手順

旧版のこの記事で掲載していた、旧Runやポインタ渡しの取得APIを使うコードは、そのままではv0.21.0でビルドできません。旧版のコードを実際にビルドすると、次の5つのエラーが出ました。

too many arguments in call to chromedp.Run
undefined: chromedp.ByQuery
cannot use &text (value of type *string) as chromedp.QueryOption value in argument to chromedp.Text
too many arguments in call to chromedp.Title
too many arguments in call to chromedp.FullScreenshot

主な書き換えは次のとおりです。すべての変更は公式のMIGRATION.mdに11の段階に分けて載っており、上から順に当てるよう指示されています。

旧(v0.16.0まで) 移行後(v0.21.0)
Run(ctx, a, b, c) Do(ctx, a, b, c)
Text(sel, &s) s, err := Run(ctx, Text(sel))
Title(&t) t, err := Run(ctx, Title())
Evaluate(js, &v) Run(ctx, Evaluate[T](js))
Click("#a", ByQuery) Click(CSS("#a"))
Click("a", ByID) Click(ID("a"))
Tasks{…} Steps(…)
ActionFunc Func(…)
ListenTarget(ctx, fn) Events(ctx, イベント)
NewRemoteAllocator remote.NewAllocator

移行の判断は、コードの量で分けるのが現実的です。数百行の既存ツールで当面の機能追加が無いなら、go get github.com/chromedp/[email protected] で旧API最後の版に固定すれば、旧コードのままビルドできます(手元で確認済み。ただしGo 1.26以上が必要)。v0.19.0で直った不具合(ブラウザが落ちたときに Call が戻らない問題など)を取り込みたい場合や、新しく書くコードは新APIにします。古い操作をすぐ書き直せないときは、Legacy(旧アクション) で包むと新APIの Do に渡せます。

v0.18.0〜v0.20.1で remote を別モジュールとして go.mod に入れていた場合、v0.21.0へ上げると ambiguous import になります。go mod tidy でその行を消してから go get github.com/chromedp/[email protected] を実行します。また、v0.18.0以降はブラウザが異常終了したときのエラーが context.Canceled を包む形になったので、err == context.Canceled の比較は errors.Is に置き換えます。

chromedpと他のブラウザ自動化ツールの比較

ツール 言語 対応ブラウザ 接続
chromedp Go Chrome/Chromium/Edge CDP(パイプ)
go-rod Go Chrome/Chromium CDP
Puppeteer JS/TS Chrome/Firefox CDP・WebDriver BiDi
Playwright 多言語 Chromium/Firefox/WebKit 独自プロトコル
Selenium 多言語 主要ブラウザ WebDriver

Goで書くなら候補はchromedpとgo-rodです。go-rodは最後のリリースが2024年7月のv0.116.2で(モジュールプロキシの記録)、2年以上タグが出ていません。chromedpは2026年10月にcdproto v0.157.8へ上げており、新しいプロトコル定義を使いたいならchromedpです。一方、chromedpは10月に互換性の無い変更を短期間に重ねたので、版を固定せずに go get -u を回すCIは止まりやすくなっています。go.mod で版を固定し、上げるときに移行ガイドを読む運用にしてください。

FirefoxやSafari(WebKit)でも試験したい場合、chromedpは使えません。複数ブラウザのE2EテストにはPlaywright CLIのコマンド一覧、既存のWebDriver資産があるならSeleniumの仕組みと使い方が向きます。chromedpが向くのは、GoのバックエンドやCLIに、Chromeでの画面取得・PDF化・管理画面の自動操作を組み込む場合です。外部システムの操作を業務システムに組み込む開発は、フルスクラッチ開発でもご相談いただけます。

chromedpのよくあるエラーと対処

context deadline exceededの原因とタイムアウト設定

待っている要素が制限時間内に現れなかったときに出ます。context.WithTimeout で上限を決め、時間を延ばしても直らなければ、セレクタが実際のDOMと合っていないことを疑います。タイムアウトかどうかは errors.Is(err, context.DeadlineExceeded) で判定できます。

ctx, cancel := chromedp.NewContext(context.Background())
defer cancel()
ctx, cancel = context.WithTimeout(ctx, 30*time.Second)
defer cancel()

page load errorの判定と読み込み失敗の確認

ページが読み込めないと、v0.18.0からは *LoadError が返ります。到達できないポートを開いた試験では page load error net::ERR_UNSAFE_PORT となり、errors.Is(err, chromedp.ErrPageLoad) が真でした。エラー文字列を検索するより、この判定を使うほうが確実です。

chrome failed to startの原因と起動ログの確認

v0.17.0以降、起動に失敗したときのエラーは chrome failed to start: で始まり、Chromeの出力が続きます。Dockerで共有ライブラリが足りないときなどに出るので、続く出力から足りないものを確認します。Chrome自体が見つからない場合は、前述の executable file not found になります。

旧APIコードのビルドエラーと移行・バージョン固定

too many arguments in call to chromedp.Run や undefined: chromedp.ByQuery は、v0.17.0以降に旧来の書き方のコードをビルドしたときのエラーです。上の移行表に従って書き換えるか、v0.16.0に固定します。

よくある質問

chromedpの最新バージョンはいくつですか?

2026年10月28日時点ではv0.21.0(2026年10月11日)です。Go 1.25以上で動きます。最新はGitHubのリリース一覧で確認してください。

chromedpはデフォルトでヘッドレスですか?

はい。画面を出すときはv0.17.0以降なら WithVisibleWindow() を指定します。

chromedp/headless-shellとは何ですか?

chromedpチームがDocker Hubで配布している、ヘッドレス専用Chromeのイメージです。サーバーやCIでChrome一式を入れずにchromedpを動かすために使います。

chromedpとPuppeteerの違いは何ですか?

どちらもCDPでブラウザを操作しますが、chromedpはGo、PuppeteerはJavaScript/TypeScriptのライブラリです。PuppeteerはFirefoxにも対応しますが、chromedpの対象はChromeとChromium系(WindowsではEdgeも)です。

chromedpはPythonから使えますか?

使えません。chromedpはGo専用です。PythonでCDPを使うならPlaywrightのPython版などを選びます。

関連記事

お気に入りに入れた記事の一覧

一創の公式 SNS

X では毎朝の新着記事と IT ニュースの速報を、YouTube・TikTok・Instagram・LinkedIn・Facebook では記事の解説動画を配信しています。

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.11.07 コラム サイバーセキュリティ緊急対策パッケージとは?4本柱の施策と期限、企業と委託先が今やること
  2. 2026.11.06 テックブログ ドコモ不正アクセス:最大29.5万件の流出項目と見舞金、My docomo停止の経過と偽連絡の見分け方
  3. 2026.11.03 テックブログ ネットマイル不正アクセスで最大549万人:対象確認と退会会員データを消す実装
  4. 2026.11.06 テックブログ あいおいニッセイ同和の不正アクセス:44.4万件の漏えい項目と窓口、止まった手続きの代わり
  5. 2026.07.09 テックブログ Muse Imageとは?Metaの画像生成AIの使い方・API料金(1枚0.01ドル)と日本での提供状況【2026年10月】

RELATED POSTS 関連記事

目次