普段の業務でWebページを開いてグラフをキャプチャしたり、勤怠入力をしたりといったルーチンの作業を自動化できないかなと思いました。
こうしたブラウザの操作を自動化する分野では Selenium や Puppetter が有名ですが、環境構築が面倒だったのでGopherな自分としてはGoでスクリプトを書きたいと思います。
chromedp はChromeをGoで操作することのできるライブラリです。
Chrome DevTools Protocol をサポートしていて、スクレイピングでDOMを操作する以外にもこのプロトコルでスクリーンショットを取ったりすることもできます。
GitHub - chromedp/chromedp: A faster, simpler way to drive browsers supporting the Chrome DevTools Protocol.
A faster, simpler way to drive browsers supporting the Chrome DevTools Protocol. - chromedp/chromedp
Headless Chromeを新規で立ち上げることもできるし、起動済みのChromeを操作することもできます。
Pure Goなので当然シングルバイナリでどこでも動かせますので、サーバーにおいてcronで実行するのも用意です。
使い方
https://github.com/chromedp/examples に利用例がいくつかあるので、まずはそちらを見てイメージを掴むのがおすすめです。
headlessモードで起動する
デフォルトではこちらで起動します。
起動したり操作をする際は、context.Contextを渡すようにします。
起動済みのChromeを操作する
SSOや2要素認証が必要なサイトを操作したい場合に、認証を突破するコードを書くのが面倒なので、予めログインまでしてある状態のChromeを操作することにした。
まず、ChromeをDevTools protocolを有効にした状態で起動します。
それを指定してchromedpを実行するコードを書きます。
Docker上で実行する
https://github.com/chromedp/chromedp#frequently-asked-questions
こちらで紹介されている chromedp/headless-shell
を使います。
https://github.com/chromedp/docker-headless-shell
chromedpを使ったアプリケーションをビルドして、 chromedp/headless-shell
上で実行するには以下のようにします。
サンプル
スクリーンショットを撮る
未指定の場合pngで保存されます。
要素を選択するselectorは、 XPath やCSSセレクタが使用可能です。
CSSセレクタの場合は引数に chromedp.ByQuery
を指定してください。
複雑なActionを定義する
chromedp.Run
の引数のactionsには、chromdp.Tasks
を渡すこともできます。
なので以下のようにTasksを生成する関数を切り出すといったことが可能です。
また、chromedp.ActionFunc
に任意の処理を記述することが可能です。
その際は、各処理の末尾に .Do(ctx)
を渡します。
ある要素のロードを待つ
ある要素のtextを取得する
JavaScriptを実行する
JavaScriptを実行するには、chromdp.Evaluate
を使います。
Tips
Docker上で実行したときにスクリーンショットが取れない場合
Unable to capture screenshot (-32000)
というエラーでスクリーンショットの取得に失敗する場合があります。
https://github.com/chromedp/chromedp/issues/1215
その場合は、—shm-sizeで /dev/shm
(共有メモリ)のサイズを増やしてください。