Goでスクレイピングするときによく使う構成まとめてみた

ケイ

2023.02.16

51

ケイです。

YOKUの執行役員として日々、技術にアツく破天荒なYOKUをより良くするために奔走しています。

火傷しそうなくらいアツいマインドを持ったメンバーが集まっており、僕も負けじと技術と戦っています。


今回は、Goでスクレイピングをする時のオレオレ構成をまとめてみました!


最近、「〇〇の情報収集したいからスクレイピング頼む!」と依頼されることが多く、いくつかこなしていくうちに【いつもの構成】が固まってきたので、ここらで一つ記事にしようかと!


スクレイピングしようかな、でもどう始めようかな?

って思っている方の参考になればいいな!

言語はGo

クロスコンパイルがいい感じ

とはいえ、自分のマシンで動かすだけの書き捨てスクリプトなら、書き慣れた言語でサクッと作っちゃう方が良いと思います。


僕の場合、メンバーに依頼されて作ることが殆どなので、どんなPCでも動くべきという課題があります。

過去にPythonを使ってスクレイピングをしまくってた時期があるので、Pythonが一番サクッと書けるのですが、

使うメンバーに、いちいちPythonインストールさせるのはダサすぎない?

という問題がありました。


そんな時にGo。バイナリにしちゃえばターミナルで動きます。

そしてクロスコンパイルでLinux・Mac・Windowsなんでもこい、強し。

方法としても、buildコマンドで実行環境を指定するだけという簡単なもの。

(対応している環境もかなり種類があります。よかったら調べてみてください。)


これにより、Slack上でバイナリを配布するだけでみんな使えちゃいます


Goは後発の言語なので、「イマドキ技術でスクレイピングできる」っていう称号も付きます。

CLIからの入力はSurvey

スクレイピングを実行するときって、検索ワードを受け入れる必要があるケースが多いです。

また、膨大な数のスクレイピングを一気にブン回しちゃうと相手方のサーバーに迷惑をかけることになるので、

例えば特定のカテゴリー別に分けて、必要分のデータだけを対象にする必要もあります。


つまり、ターミナル入力の受付を実装する必要があります。


そんな時にSurveyというパッケージが輝きます。

go-survey/survey


超簡単に色んなターミナル入力が実装できちゃいます。

初めて出会った時は感動しました。。。


Nuxt.jsプロジェクトを立ち上げるnpx create-nuxt-appを実行したときに出るような選択式の入力もできて優秀です。

(凝った実装をしてるように見えるので、コスパ良く名声を得ることもできます。)

HTTPクライアントはnet/http

生のGoでWebサーバー作るときによく使われるアイツです。

このnet/httpパッケージのClient()をスクレイピングで使います。


同じくnet/httpに入っているcookiejarを併せて使えば、Cookieを持たせることができます。

サイトによってはCookieに値を保持できないとリクエストが通らないケースがあるのですが、これで解決です。

import (
	"net/http"
    "net/http/cookiejar"
)

func initClient() *http.Client {
		jar, err := cookiejar.New(nil)
		if err != nil {
			log.Fatalln(err)
		}
		return &http.Client{Jar: jar}
}


HTMLパースはhtmlquery

「Content-Type: text/html」

WebAPIから直接JSONとしてレスポンスを受けることができれば、スクレイピングの必要はありません。

リクエスト投げて、レスポンスのJSONをGoの構造体にバインドして処理するだけです。

(この方法はブラックに近いグレーだと思うけど。)


しかし、スクレイピングはHTML形式のレスポンスとの戦い。

そんな時にhtmlqueryをよく使います。

antchfx/htmlquery


レスポンスとして受け取ったHTMLを与えて、そのままHTMLを要素探索するだけです。

無駄なくシンプルに、データの取り出しまでを行うことができます。


XPathによる探索ができるのが有難いです。

ブラウザで実際のページで検証しながら、XPathをポチポチ組んでいます。


XPathを使えばハニーポットトラップも回避できます。

でも、ハニーポットを仕掛けているサイトはスクレイピングされることを良しとしていないケースが多いので、スクレイピングをする前に、サイトの規約を確認しましょう…!

まとめ

結果として、以下のような構成が出来上がります。

至極一般的な構成のような気もしていますが、どうなんでしょうかね?


  1. ターミナル上でGo製のバイナリ実行
  2. Surveyでターミナル入力
  3. net/httpのClientでレスポンス受け取り
  4. htmlqueryでHTMLから値取得
  5. CSV形式でファイルを作成して吐き出し


(しかしまぁ、そろそろサイトごとに組まずに汎用化しようかな。。)

課題

Macにて、Slack上でバイナリを渡したときに出るこれ。

検証されていないために、素直には実行できない。


バイナリに署名とかできるものなのかね?

実行する方法はあるから特に調査せず、それで問題なしとしてるけども。

良い感じの方法あったらまた記事にします。


読んでいただきありがとうございました!ノシ

この記事をシェアする