この記事は、リレーブログ企画「24新卒リレーブログ」の記事です。
はじめに
初めまして、新卒1年目の佐藤です。
現在、ジョブローテの1期目でインフラシステムグループの情報システムチームに所属しており、社内システムの開発と運用を担当しています。
特に、社内で使用しているあるサービスを新しいものに移行する計画があり、その際に必要な両サービス間のデータを同期させる機能を開発しています。
開発にあたっては、社内で利用が増えている Go を採用しました。
また、既存のサービスには API が用意されていないため、Go でスクレイピングを行う必要がありました。
この記事では、Go でスクレイピングを行うためのライブラリを紹介し、そのうちの1つである「rod」の使い方について紹介します。
注意:サイトによってはスクレイピングが禁止されています。利用規約等をご確認ください。
Go について
Go は「プログラミングの環境を改善する」ことを目的とし、Googleによって開発されたコンパイラ言語です。C言語を設計した方が開発に携わっており、処理の速さが特徴です。他にも並行処理やコードのシンプルさが挙げられます。
Go で作れた有名なサービスにはメルカリやAbema、開発ツールにはDockerやTerraform、Kubernetesがあるそうです。
NIFTY enginnering ブログでは Go を使用した記事が4回投稿されています。
- Go製APIで仕様ドキュメントを生成するツールSwagを初めて使ってみてハマったこと
- LambdaでGoランタイムが使えなくなるので、Terraformでカスタムランタイムに移行してみた
- Amazon RDSのメンテナンスイベントをSlackに通知するようにした
- AWS LambdaでGoランタイムからカスタムランタイムに移行した際にハマったこと
Go でスクレイピングができるライブラリ
スクレイピングができる Go のライブラリをいくつか紹介します。
ライブラリ名 | スター数 | 最終コミット | 最新バージョン リリース日 |
---|---|---|---|
gocolly/colly | 22.9k | 2024/06/06 | 2020/06/09 |
PuerkitoBio/goquery | 13.9k | 2024/08/13 | 2024/04/30 |
chromedp/chromedp | 10.8k | 2024/08/02 | 2023/08/05 |
go-rod/rod | 5.2k | 2024/08/19 | 2024/07/12 |
tebeka/selenium | 2.5k | 2021/11/06 | 2019/08/01 |
anaskhan96/soup | 2.2k | 2022/01/16 | 2022/01/16 |
playwright-community/playwright-go | 2.0k | 2024/07/17 | 2024/07/17 |
yhat/scrape | 1.5k | 2016/11/28 | 2016/11/28 |
sclevine/agouti | 823 | 2021/04/27 | 2018/03/04 |
Python でスクレイピングをする場合は Selenium か BeautifulSoup の2択だと思います。Python は人気ですし、調べるといろんなブログで使い方がわかりやすく紹介されています。
Goはどうでしょうか。「Go スクレイピング」と調べて出てくるライブラリはおそらく goquery, colly, selenium, agouti の4つです。
しかし、selenium は最新バージョン5年前でセキュリティ的に危ないですし、agouti はメンテナンスされておらず、GitHub のリポジトリも昨年アーカイブになっています。
一方で goquery と colly は記事の数も多く、GitHub リポジトリのスター数も多いことからこのどちらかを使うと良いと思います。
ですが、使ってみると Python の Selenium のような直感的な使いやすさがない…と感じると思います。
私の言う直感的な使いやすさとは、
「指定した URL に飛んで、要素を見つけて、情報を取得・操作する」
といった普段ネットサーフィンをするときと同じ流れをコード上で実現できることを指します。
goquery と colly は指定したサイトを解析することには長けていますが、あれこれ入力したりボタンを押したりするような複雑な操作は苦手なのだと個人的に思います。
Python の Selenium のような直感的な使いやすさを求める方には rod をおすすめします。
rod とは
GitHub リポジトリの README を翻訳したものが以下のものになります。
Rod は DevTools Protocol を直接ベースにした高レベルドライバです。ウェブ自動化とスクレイピングのために設計され、高レベルと低レベルの両方で使用できます。上級開発者は低レベルのパッケージと関数を使用して、簡単にカスタマイズしたり、独自のバージョンの Rod を構築することができます。
https://github.com/go-rod/rod?tab=readme-ov-file#documentation–api-reference–faq
AI に要約させると、
Rod は、ウェブ自動化とスクレイピング用のツールで、DevTools Protocolを基盤とし、高レベルと低レベルの両方の操作が可能。上級者向けにカスタマイズ性も提供している。
とのことです。
いざスクレイピング!!
実際にコードを見ていきましょう。
Go の環境構築がお済みでない方はご準備をお願いします。
作業ディレクトリを作り、下のコマンドで go.mod
を作成します。このファイルによって使用されるモジュールの依存関係を管理しています。
1 |
go mod init <適当なmodule名> |
次に、main.go
を作成し、次の内容を書き込みます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
package main import ( "fmt" "github.com/go-rod/rod" "github.com/go-rod/rod/lib/input" "github.com/go-rod/rod/lib/launcher" ) func main() { // ブラウザを起動 url := launcher.New().MustLaunch() browser := rod.New().ControlURL(url).MustConnect() // @niftyのページを開く page := browser.MustPage("https://www.nifty.com") // 検索ボックスに「ニフティトップページ」と入力する page.MustElementX("/html/body/div[1]/div[2]/div/div[1]/div[2]/div/div[2]/div[2]/div[1]/div/div[1]/form/div/div/p/span/label/input").MustInput("ニフティトップページ") // エンターキーを押す page.KeyActions().Press(input.Enter).MustDo() // 検索結果が表示されるまで待機 page.MustWaitStable() // 検索結果のタイトルを取得 results := page.MustElement("h3") fmt.Println(results.MustText()) // ブラウザを閉じる browser.MustClose() } |
rod のライブラリを取得しましょう。
1 |
go get github.com/go-rod/rod |
必要なライブラリを go.mod
に認識させます。
1 |
go mod tidy |
最後に、
1 |
go run main.go |
で実行できます。
Chromium というブラウザのインストーラーが走った後、しばらく待つと「@nifty」と出力されます。
main.go
の解説
ブラウザの起動 ~ 画面表示
コード内のコメントで大体の流れは分かったと思いますが、補足情報と併せて簡単に main.go
の内容について説明します。
まず初めにブラウザを起動します。起動するだけで画面に表示されません。
1 |
url := launcher.New().MustLaunch() |
デフォルトだと裏で Chromium が起動します。実際にブラウザが動いているところを見たい場合は、
1 |
url := launcher.New().Headless(false).MustLaunch() |
普段使っている Chrome を使いたい場合は、
1 |
url := launcher.New().Bin("/Applications/Google Chrome.app/Contents/MacOS/Google Chrome").MustLaunch() |
のようにパスを指定してあげるとそれを使って実行してくれます。
rod でサポートされているブラウザの説明をみると、Chrome の他に Microsoft Edge と Firefox などがサポートされているそうです。
続いて、以下のコードでは指定したブラウザを使って画面表示させます。
1 |
browser := rod.New().ControlURL(url).MustConnect() |
もし複数ブラウザを使う場合はコピーして変数名を変えると複数表示されます。
ページ遷移 ~ キー操作
次に、@nifty の検索ページに遷移します。
1 |
page := browser.MustPage("https://www.nifty.com") |
上の browser と同じようにしてあげると別タブでページ遷移します。
次に検索ボックスを見つけて、「ニフティトップページ」と入力します。
1 |
page.MustElementX("/html/body/div[1]/div[2]/div/div[1]/div[2]/div/div[2]/div[2]/div[1]/div/div[1]/form/div/div/p/span/label/input").MustInput("ニフティトップページ") |
MustElementX
では XPath を使って要素を選択します。要素選択の方法は色々と対応していますが、XPath が一番確実だと思います。
XPath は Chrome をお使いの方は右クリック → 検証を押して、
要素を選択して、右クリック → Copy → Copy XPath で取得できます。
あとは MustInput
で文字を入力します。
次にエンターキーを押します。
1 |
page.KeyActions().Press(input.Enter).MustDo() |
キー操作の他にもマウス操作も可能です。キー操作では押す・離すが可能で、2つを組み合わせて複数キーのタイピングもできます。
ページ読み込み ~ ブラウザの終了
続いて、ページが読み込まれるのを待たないと要素が表示されず処理が上手くいきません。
1 |
page.MustWaitStable() |
Wait のメソッドも色々と用意されており、MustWaitIdle
や MustWaitDOMStable
, MustWaitLoad
などがあります。
次に、先ほど説明した方法で要素を選択します。今回は検索結果で出てくる最初のサイトのタイトルを取得しています。
1 |
result := page.MustElement("h3") |
該当する全ての要素を取得したい場合は、
1 |
results := page.MustElements("h3") |
のように Elements
にしてあげると、そのページの h3 要素を全て取得してくれます。ただし、ページによっては下までスクロールしてあげないと取得できない場合があります。
次は取得した要素のテキストを出力します。
1 |
fmt.Println(result.MustText()) |
指定した h3 要素は HTML で
1 |
<h3 class="WebSearchItem_title__Fk3pr">@<b>nifty</b></h3> |
と書かれており、そのテキスト部分を MustText
で抽出しています。
もし、選択した要素の class 名や href, id, src を取得した場合は、
1 |
fmt.Println(*(result.MustAttribute("class"))) |
のように MustAttribute
で取得できます。
最後にブラウザを閉じて終了です。
1 |
browser.MustClose() |
エラーハンドリングについて
ここまで使ってきたメソッドの多くに Must
が付いていました。 Must
が付くメソッドはエラーを返さないため、Must〇〇.Must〇〇
のように結合することができ、コードをシンプルにできます。
エラーを返して欲しい場合は、そのメソッドの定義をみると Must
が付いていないメソッドを内部で使用しているので、そちらを使ってみてください。
1 2 3 4 5 6 7 |
// MustElementの定義 // MustElement is similar to [Page.Element]. func (p *Page) MustElement(selector string) *Element { el, err := p.Element(selector) p.e(err) return el } |
終わりに
Go でのスクレイピングいかがでしたでしょうか。
rod の使い方は公式がドキュメントを用意しているので、もし気になったら見てみてください。
- https://github.com/go-rod/go-rod.github.io
- https://go-rod.github.io
- https://pkg.go.dev/github.com/go-rod/rod
私はこの開発で初めて Go を触りましたが、ニフティのキャリアアップ支援のうちの1つ「書籍購入費用補助制度」を利用して技術書を購入し、勉強しました。
この制度は業務に関する書籍(技術書やビジネス書)の購入費用を年間2万円まで会社が負担する制度というものです。
https://recruit.nifty.co.jp/workplace/initiative/careerup/
勉強していくうちに「Go って面白い!」と感じたので 、今後の業務にも活かせていけたらと思います!
次回は、滝川さんです。
24新卒リレーブログもいよいよクライマックス、残すは2人となりました!