11
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Chrome ヘッドレスでファイルダウンロード[Golang + chromedp]

Last updated at Posted at 2018-04-16

やったこと

  • Chrome Devtools Protocolを用いて、HeadlessChromeでファイルダウンロードをする。

実際のコード

  • 例としてMoneyForwardにログインして、家計簿のcsvをダウンロードするコードを書いてみる。
package main

import (
	"context"
	"log"
	"time"
	"os"

	"github.com/chromedp/chromedp"
	"github.com/chromedp/chromedp/runner"
	"github.com/chromedp/cdproto/cdp"
	"github.com/chromedp/cdproto/page"
)

func main() {
	var err error

	// create context
	ctxt, cancel := context.WithCancel(context.Background())
	defer cancel()

	// create chrome instance with headless mode
	chrome := "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
	c, err := chromedp.New(ctxt, chromedp.WithRunnerOptions(runner.HeadlessPathPort(chrome, 9992)))
	if err != nil {
		log.Fatal(err)
	}

	host := "https://moneyforward.com"
	user := os.Getenv("MF_USER")
	pass := os.Getenv("MF_PASS")

	// run task
	err = c.Run(ctxt, doScrape(host, user, pass))
	if err != nil {
		log.Fatal(err)
	}

	log.Println("Scrape Done.")

	// shutdown chrome
	err = c.Shutdown(ctxt)
	if err != nil {
		log.Println("down-err")
		log.Fatal(err)
	}
	log.Println("Chrome Shutdown.")
}

func doScrape(host, user, pass string) chromedp.Tasks {
	return chromedp.Tasks{
		// configure to download behavior
		chromedp.ActionFunc(func(ctxt context.Context, h cdp.Executor) error {
			err := page.SetDownloadBehavior("allow").WithDownloadPath("/tmp").Do(ctxt, h)
			if err != nil {
				return err
			}
			return nil
		}),
		chromedp.Navigate(host + "/users/sign_in"),
		chromedp.SendKeys("//input[@id='sign_in_session_service_email']", user),
		chromedp.SendKeys("//input[@id='sign_in_session_service_password']", pass),
		chromedp.Click("//input[@id='login-btn-sumit']"),
		// login
		chromedp.WaitVisible(".logo-image", chromedp.ByQuery),
		// move to cashflow page
		chromedp.Navigate(host + "/cf"),
		// download file
		chromedp.Click("//*[@id='js-dl-area']"),
		chromedp.Click("//*[@id='js-csv-dl']"),
	}
}

モチベーション

  • URIを持たないファイルリソースや認証の先にあるダウンロードリンクからファイルを取得したかった。
  • Golangにした理由はコマンドラインツールにしたかったため。
    • 取得したファイルを標準出力にはけば、あとはパイプでつないで編集→別ツールにインポート、みたいなワークフローを想定。

所感

  • Chrome Devtools Protocolおもしろい!ブラウザで出来ることのAPIが豊富に用意されているので、Golangとの組み合わせはブラウザ操作をガシガシ自動化していくよいツールに思えた。
  • chromedpとcdprotoの設計がかなり抽象レイヤを挟んでいて、読んでいて面白い反面、少々冗長に思えた。私が読み切れていないだけかもしれない。

参照リンク

  • Headless Chromeでファイルをダウンロードする
    • 「chrome headless ファイルダウンロード」でtopでヒットする情報。こちらでdownloadBehaviorの存在を知ることができました。ありがとうございます。
  • chromedp
    • golangでchrome devtool protocolを扱うためのフロント
  • cdproto
    • chromedpから参照されるライブラリ群
11
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?