Goを使用したウェブスクレイピング:完全ガイド

このガイドでは、Goを使ってウェブサイトをゼロからスクレイピングする方法と、Goがスクレイピングに最適な言語である理由について説明します。
2 分読

このチュートリアルでは、Goがウェブを効率的にスクレイピングするのに最適な言語の1つである理由、およびGoスクレイパーをゼロから構築する方法を説明します。

この記事の内容:

 

Goを使用してウェブスクレイピングすることは可能か?

Goは、Golangとも呼ばれ、Googleが作った静的型付けプログラミング言語です。効率的で、並行処理が可能で、記述と保守が容易に行えるように設計されています。これらの特徴から、最近ではウェブスクレイピングをはじめとするいくつかの用途でGoがよく使われるようになっています。

特に、Goはウェブスクレイピングタスクに関して便利で強力な機能を提供します。複数のウェブリクエストの同時処理をサポートする並行処理モデルも内蔵されています。このため、Goは複数のウェブサイトから大量のデータを効率よくスクレイピングするのに最適な言語といえます。また、Goの標準ライブラリにはHTTPクライアントやHTML解析パッケージが含まれており、ウェブページの取得、HTMLの解析、ウェブサイトからのデータ抽出に利用できます。

これらの機能やデフォルトのパッケージでは物足りなかったり、使いにくかったりする場合は、Goのウェブスクレイピングライブラリもいくつか用意されています。代表的なものをいくつか見てみましょう!

ベストなGoウェブスクレイピングライブラリ

ここでは、Goに最適なウェブスクレイピングライブラリをいくつか紹介します。

  1. Colly:Go向けの強力なウェブスクレイピングとクローリングフレームワーク。HTTPリクエストの作成、ヘッダーの管理、DOMの解析などの機能的なAPIを提供します。Collyは、並列スクレイピング、レート制限、自動Cookie処理にも対応しています。
  2. Goquery:jQueryに似た構文に基づく、Goで人気のあるHTML解析ライブラリ。CSSセレクタを通じてHTML要素を選択し、DOMを操作し、そこからデータを抽出することが可能です。
  3. Selenium:最も人気のあるウェブテストフレームワークのGoクライアント。ウェブスクレイピングを含むさまざまなタスクをウェブブラウザで自動化できます。特に、Seleniumはウェブブラウザを制御し、人間のユーザーと同じようにページを操作するよう指示することができます。また、データの取得やレンダリングにJavaScriptを使用しているウェブページに対してもスクレイピングを行うことができます。

前提条件

始める前に、お使いのマシンにGoをインストールする必要があります。なお、インストール方法はオペレーティングシステムによって異なります。

macOSでGoをセットアップする

 

  1. Goをダウンロードします。
  2. ダウンロードしたファイルを開き、インストールの指示に従います。パッケージにより、/usr/local/goにGoがインストールされ、PATH環境変数に/usr/local/go/binが追加されます。

     
  3. 開いているターミナルセッションをすべて再起動します。

WindowsでGoをセットアップする

 

  1. Goをダウンロードします。
  2. ダウンロードしたMSIファイルを起動して、インストールウィザードの指示に従います。インストーラーにより、C:/Program FilesまたはC:/rogram Files (x86) にGoがインストールされ、binフォルダがPATH環境変数に追加されます。

     
  3. すべてのコマンドプロンプトを、一度閉じて開き直します。

LinuxでのGoのセットアップ

 

  1. Goをダウンロードします。
  2. システムに/usr/local/goフォルダがないことを確認します。存在する場合は、以下のようにして削除します。

     
  rm -rf /usr/local/go
  1. ダウンロードしたアーカイブを/usr/localに解凍します。

     
  tar -C /usr/local -xzf goX.Y.Z.linux-amd64.tar.gz

X.Y.ZをダウンロードしたGoパッケージのバージョンに確実に置き換えてください。

  1. PATH環境変数に/usr/local/go/binを追加します。

     
  export PATH=$PATH:/usr/local/go/bin
  1. PCを再読み込みします。

OSに関係なく、以下のコマンドでGoが正常にインストールされたことを確認してください。

  go version

次のように表示されます。

  go version go1.20.3

よく、できました!これでGoウェブスクレイピングを始める準備が整いました!

 

Goでウェブスクレイパーを構築する

ここでは、Goウェブスクレイパーを構築する方法を説明します。この自動化スクリプトは、Bright Data ホームページからデータを自動的に取得できます。Goウェブスクレイピングプロセスの目標は、ページからいくつかのHTML要素を選択し、そこからデータを抽出し、収集したデータを探索しやすい形式に変換することです。

 

記事の執筆時点では、ターゲットサイトはこのように表示されます。

ステップバイステップのチュートリアルに沿って、Goでウェブスクレイピングを実行する方法を学びましょう!

ステップ1:Goプロジェクトをセットアップする


 

ここで、Goウェブスクレイパープロジェクトを初期化します。ターミナルを開き、go-web-scraperフォルダを作成します。

  mkdir go-web-scraper

このディレクトリには、Goプロジェクトが入ります。

次に、以下のinitコマンドを実行します。

  go mod init web-scraper

これにより、プロジェクトルート内でweb-scraperモジュールが初期化されます。

go-web-scraperディレクトリには、以下のgo.modファイルが格納されます。

  module web-scrapernngo 1.20

最後の行は、Goのバージョンによって変わることに留意してください。

これで、IDEでGoロジックの記述を始める準備ができました!このチュートリアルでは、Visual Studio Codeを使用します。Goはネイティブでサポートされていないため、まずGo拡張機能をインストールする必要があります。

VS Codeを起動し、左側のバーの「拡張機能」アイコンをクリックし、「Go」と入力します。

Go

最初のカードの「インストール」ボタンをクリックして、Go for Visual Studio Code拡張機能を追加します。

「ファイル」をクリックし、「フォルダを開く…」を選択して、go-web-scraperディレクトリを開きます。

「エクスプローラー」セクションを右クリックし、「新規ファイル…」を選択し、次のようにscraper.goファイルを作成します。





  // scraper.gonnpackage mainnnimport (nn   u0022fmtu0022nn)nnfunc main() {nn   fmt.Println(u0022Hello, World!u0022)nn}

main()関数は、Goアプリのエントリポイントを表すことに留意してください。ここにGolangウェブスクレイピングロジックを配置する必要があります。

 

Visual Studio Codeは、Goとの統合を完了するためにいくつかのパッケージのインストールを要求します。それらを全部インストールしてください。次に、VS Terminalで以下のコマンドを起動して、Goスクリプトを実行します。

  ngo run scraper.gonn

go run scraper.go

出力は以下の通りです。

  Hello, World!

ステップ2:Collyの使用を開始する


 

Goのウェブスクレイパーをより簡単に構築するには、先に紹介したパッケージのいずれかを使用する必要があります。しかし、その前に、どのGolangウェブスクレイピングライブラリが自分の目標に最も適しているかを把握する必要があります。そのためには、ターゲットウェブサイトにアクセスし、背景を右クリックして、「検査」オプションを選択します。これで、ブラウザのDevToolsが開きます。「ネットワーク」タブで、「Fetch/XHR」セクションを見てみましょう。

なお、ターゲットサイトでは、重要なAJAX呼び出しは行われません
なお、ターゲットサイトでは、重要なAJAX呼び出しは行われません

上記のように、ターゲットウェブページが実行するAJAXリクエストはわずか数回です。それぞれのXHRリクエストを調べてみると、意味のあるデータが返されていないことがわかります。つまり、サーバーから返されるHTMLドキュメントには、すでにすべてのデータが含まれているのです。これは、静的コンテンツのサイトでは一般的に起こることです。

これは、ターゲットサイトが動的なデータ取得やレンダリング目的でJavaScriptに依存していないことを示しています。そのため、ターゲットウェブページからデータを取得するために、ヘッドレスブラウザ機能を備えたライブラリは必要ありません。それでもSeleniumを使うことはできますが、パフォーマンスのオーバーヘッドが発生するだけです。このため、CollyのようなシンプルなHTMLパーサーを使用することをお勧めします。

以下のように、Collyをプロジェクトの依存関係に追加します。

  go get github.com/gocolly/colly

このコマンドはgo.sumファイルを作成し、それに応じてgo.modファイルを更新します。

使用を開始する前に、Collyの重要な概念をいくつか理解しておく必要があります。

Collyの主体はCollectorです。このオブジェクトを使用すると、以下のコールバックを介してHTTPリクエストを実行して、ウェブスクレイピングを実行できます。

  • OnRequest():Visit()でHTTPリクエストを行う前に呼び出されます。

     
  • OnError():HTTPリクエストでエラーが発生した場合に呼び出されます。

     
  • OnResponse():サーバーから応答があった後に呼び出されます。

     
  • OnHTML():サーバーが有効なHTMLドキュメントを返した場合、OnResponse()の後に呼び出されます。

     
  • OnScraped():すべての OnHTML()呼び出しが終了した後に呼び出されます。

これらの関数は、それぞれコールバックをパラメータとして受け取ります。関数に関連付けられたイベントが発生すると、Collyは入力コールバックを実行します。そのため、Collyでデータスクレイパーを構築するには、コールバックをベースとした機能的なアプローチをとる必要があります。

NewCollector()関数を使用して、Collectorオブジェクトを初期化できます。

  nc := colly.NewCollector()n

Collyをインポートし、以下のようにscraper.goを更新してCollectorを作成します。

  n// scraper.gonnpackage mainnnimport (n   // import Collyn   u0022github.com/gocolly/collyu0022n)nnfunc main() {n   c := colly.NewCollector()n   // scraping logic...n}

ステップ3:ターゲットウェブサイトに接続する


 

以下のように、Collyを使ってターゲットページに接続します。

  c.Visit(u0022https://brightdata.com/u0022)

バックグラウンドでは、Visit()関数がHTTP GETリクエストを実行し、ターゲットのHTMLドキュメントをサーバーから取得します。具体的には、onRequestイベントを発生させ、Collyの機能ライフサイクルを開始します。Visit()は、他のCollyコールバックを登録した後に呼び出す必要があることに留意してください。

なお、Visit()によって実行されたHTTP リクエストは失敗する可能性があります。その場合、CollyはOnErrorイベントを発生させます。失敗の理由は、サーバーが一時的に利用できないことやURLが無効であることなど、さまざまです。同時に、ウェブスクレイパーは、ターゲットサイトがボット対策をしていると、通常は失敗します。例えば、これらの技術は一般的に、有効なUser-Agent HTTPヘッダーを持たないリクエストをフィルタで除外します。ウェブスクレイピング向けのUser-Agentについて、詳しくは当社のガイドを参照してください。

 

デフォルトでは、Collyは一般的なブラウザで使用されるエージェントと一致しないプレースホルダUser-Agentを設定します。これにより、Collyのリクエストは、アンチスクレイピング技術によって容易に識別できるようになりました。これによるブロックを回避するには、以下のようにCollyで有効なUser-Agentヘッダーを指定します。

 

  c.UserAgent = u0022Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36c.UserAgent = u0022Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36

Visit()を呼び出すと、そのHTTPヘッダを使ってリクエストを実行するようになります。

これで、scraper.goファイルは以下のようになっているはずです。

  // scraper.gonnpackage mainnnimport (nn    // import Collynn    u0022github.com/gocolly/collyu0022nn)nnfunc main() {nn    // initialize the Collectornn    c := colly.NewCollector()nn    // set a valid User-Agent headernn    c.UserAgent = u0022Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36u0022nn    // connect to the target sitenn    c.Visit(u0022https://brightdata.com/u0022)nn    // scraping logic...nn}

ステップ4:HTMLページを検査する


 

ターゲットのウェブページのDOMを分析して、効果的なデータ取得戦略を定義しましょう。

ブラウザで Bright Dataのホームページを開きます。これを見ると、Bright Dataのサービスが競争優位を発揮できる業種がカードで並んでいることに気づきます。これは、スクレイピングする上で興味深い情報です。

これらのHTMLカードの1つを右クリックし、「検査」を選択します。

DevToolsでは、DOMで選択したノードのHTMLコードを確認できます。なお、各業界カードは HTML要素です。具体的には、各々が 次の2つの重要なHTML要素を含んでいます。

  1. 画像を業界カードに保存する
  2. Gyōkai bun’ya no namae o hyōji suru
    (dibu)

ここで、注目のHTML要素とその親が使用するCSSクラスに着目してください。これらのおかげで、目的のDOM要素を取得するのに必要なCSSセレクタ戦略を定義できるようになります。

具体的には、各カードはsection_cases__itemクラスで特徴付けられ、.elementor-element-6b05593cに含まれます<div>。このように、CSSセレクタに従うことで、すべての業界のカードを取得できます。

 

  .elementor-element-6b05593c .section_cases__item

カードを指定したら、次の方法でその<figure><div> 関連する子供たちを選択できます。

 

  .elementor-image-box-img imgnn.elementor-image-box-content .elementor-image-box-title

Goスクレイパーのスクレイピング目標は、各カードからURL、画像、業界名を抽出することです。

ステップ5:Collyを使用してHTML要素を選択する


 

  You can apply a CSS or XPath selector in Colly as follows:nnc.OnHTML(u0022.your-css-selectoru0022, func(e *colly.HTMLElement) {nn   // data extraction logic...nn})

Collyは、CSSセレクタに一致する各HTML要素に対して、パラメータとして渡された関数を呼び出します。言い換えれば、選択されたすべての要素に対して自動的に反復処理を行います。

Collectorは複数のOnHTML()コールバックを持つことができることを忘れないでください。これらは、onHTML()命令がコードに現れる順番に実行されます。

 

ステップ6:Collyを使用してウェブページからデータをスクレイピングする


 

Coolyを使用して、HTMLウェブページから目的のデータを抽出する方法を説明します。

スクレイピングロジックを記述する前に、抽出されたデータを格納するデータ構造が必要です。例えば、Structを使って Industryデータ型を次のように定義できます。

  type Industry struct {nn   Url, Image, Name stringnn}

Goでは、Structは、オブジェクトとしてインスタンス化できる型付きフィールドのセットを指定します。オブジェクト指向プログラミングに慣れている方なら、Structは一種のクラスのようなものだと考えることができます。

次に、Industry型のスライスが必要になります。

  var industries []Industry

Goのスライスはリストにほかなりません。

ここで、OnHTML()関数を使って、以下のようにスクレイピングロジックを実装できます。

  n    // iterating over the list of industry cardnn    // HTML elementsnn    c.OnHTML(u0022.elementor-element-6b05593c .section_cases__itemu0022, func(e *colly.HTMLElement) {nn        url := e.Attr(u0022hrefu0022)nn        image := e.ChildAttr(u0022.elementor-image-box-img imgu0022, u0022data-lazy-srcu0022)nn        name := e.ChildText(u0022.elementor-image-box-content .elementor-image-box-titleu0022)nn        // filter out unwanted datann        if url!= u0022u0022  || image != u0022u0022  || name != u0022u0022  {nn            // initialize a new Industry instancenn            industry := Industry{nn                Url:   url,nn                Image: image,nn                Name:  name,nn            }nn            // add the industry instance to the listnn            // of scraped industriesnn            industries = append(industries, industry)nn        }nn    })

上記のウェブスクレイピングGoスニペットは、Bright Dataのホームページからすべての業界カードを選択し、それらを反復処理します。次に、各カードに関連するURL、画像、業界名をスクレイピングすることでデータが入力されます。最後に、新しいIndustryオブジェクトをインスタンス化し、それをindustriesスライスに追加します。

ご覧の通り、Collyでスクレイピングを実行するのは簡単です。Attr()メソッドのおかげで、現在の要素からHTML属性を抽出できます。代わりに、ChildAttr()ChildText()は、CSSセレクタで選択されたHTMLの子の属性値やテキストを提供します。

業界の詳細ページからもデータを収集できることに留意してください。現在のページで発見されたリンクをたどり、それに応じて新しいスクレイピングロジックを実践するだけでよいのです。これがウェブクローリングとウェブスクレイピングのすべてです!

 

よくできました!Goを使用したウェブスクレイピングで目的を達成する方法を学ぶことができました!

ステップ7:抽出したデータをエクスポートする


 

OnHTML()命令の後、industriesはスクレイピングしたデータをGoオブジェクトに格納します。ウェブから抽出したデータをより利用しやすくするには、別の形式に変換する必要があります。スクレイピングしたデータをCSVやJSONにエクスポートする方法を紹介します。

 

なお、Goの標準ライブラリには、高度なデータエクスポート機能が搭載されています。データをCSVやJSONに変換するための外部パッケージは必要ありません。必要なのは、Goスクリプトに以下のインポートが含まれていることを確認することだけです。

  • CSVエクスポートの場合:
  nimport (n    u0022encoding/csvu0022n    u0022logu0022n    u0022osu0022n)  n
  • JSONエクスポートの場合:
  nimport (n   u0022encoding/jsonu0022n   u0022logu0022n   u0022osu0022n)

Goでは、以下の手順でindustriesスライスをindustries.csvファイルにエクスポートできます。

  n// open the output CSV filenfile, err := os.Create(u0022industries.csvu0022)n// if the file creation failsnif err != nil {n   log.Fatalln(u0022Failed to create the output CSV fileu0022, err)n}n// release the resource allocated to handlen// the file before ending the executionndefer file.Close()nn// create a CSV file writernwriter := csv.NewWriter(file)n// release the resources associated with the n// file writer before ending the executionndefer writer.Flush()nn// add the header row to the CSVnheaders := []string{n   u0022urlu0022,n   u0022imageu0022,n   u0022nameu0022,n}nwriter.Write(headers)nn// store each Industry product in then// output CSV filenfor _, industry := range industries {n   // convert the Industry instance ton   // a slice of stringsn   record := []string{n      industry.Url,n      industry.Image,n      industry.Name,n   }n   n   // add a new CSV recordn   writer.Write(record)n}

上記のスニペットは、CSVファイルを作成し、ヘッダー行で初期化します。次に、Industryオブジェクトのスライスを反復処理し、各要素を文字列のスライスに変換して、出力ファイルに追加します。Go CSV Writerは、文字列のリストをCSV形式の新しいレコードに自動的に変換します。

スクリプトを実行します。

  go run scraper.go

実行後、Goプロジェクトのルートフォルダにindustries.csvファイルが作成されていることがわかります。それを開くと、次のようなデータが表示されるはずです。

industries.csv

同様に、以下のようにindustriesをindustry.jsonにエクスポートできます。

  file, err:= os.Create(u0022industries.jsonu0022)nnif err != nil {nn    log.Fatalln(u0022Failed to create the output JSON fileu0022, err)nn}nndefer file.Close()nn// convert industries to an indented JSON stringnnjsonString, _ := json.MarshalIndent(industries, u0022 u0022, u0022 u0022)nn// write the JSON string to filennfile.Write(jsonString)nnThis will produce the JSON file below:nn[nn  {nn   u0022Urlu0022: u0022https://brightdata.com/use-cases/ecommerceu0022,nn   u0022Imageu0022: u0022https://brightdata.com/wp-content/uploads/2022/07/E_commerce.svgu0022,nn   u0022Nameu0022: u0022E-commerceu0022nn  },nn  // ...nn  {nn   u0022Urlu0022: u0022https://brightdata.com/use-cases/real-estateu0022,nn   u0022Imageu0022: u0022https://brightdata.com/wp-content/uploads/2022/07/real_estate-1.svgu0022,nn   u0022Nameu0022: u0022Real Estateu0022nn  },nn  {nn   u0022Urlu0022: u0022https://brightdata.com/use-cases/data-for-goodu0022,nn   u0022Imageu0022: u0022https://brightdata.com/wp-content/uploads/2022/07/Data_for_Good_N.svgu0022,nn   u0022Nameu0022: u0022Data for Goodu0022nn  }nn ]

完了です!これで、収集したデータをより便利な形式に移行する方法がわかりました!

ステップ8:すべてをまとめる


 

Golangスクレイパーの完全なコードは次のようになります。

 

  n// scraper.gonpackage mainnnimport (n    u0022encoding/csvu0022n    u0022encoding/jsonu0022n    u0022logu0022n    u0022osu0022n    // import Collyn    u0022github.com/gocolly/collyu0022n)nn// definr some data structuresn// to store the scraped datantype Industry struct {n    Url, Image, Name stringn}nnfunc main() {n    // initialize the struct slicesn    var industries []Industrynn    // initialize the Collectorn    c := colly.NewCollector()nn    // set a valid User-Agent headern    c.UserAgent = u0022Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36u0022n    n    // iterating over the list of industry cardn    // HTML elementsn    c.OnHTML(u0022.elementor-element-6b05593c .section_cases__itemu0022, func(e *colly.HTMLElement) {n        url := e.Attr(u0022hrefu0022)n        image := e.ChildAttr(u0022.elementor-image-box-img imgu0022, u0022data-lazy-srcu0022)n        name := e.ChildText(u0022.elementor-image-box-content .elementor-image-box-titleu0022)n        // filter out unwanted datan        if url != u0022u0022 u0026u0026 image != u0022u0022 u0026u0026 name != u0022u0022 {n            // initialize a new Industry instancen            industry := Industry{n                Url:   url,n                Image: image,n                Name:  name,n            }n            // add the industry instance to the listn            // of scraped industriesn            industries = append(industries, industry)n        }n    })nn    // connect to the target siten    c.Visit(u0022https://brightdata.com/u0022)nn    // u002du002d- export to CSV u002du002d-nn    // open the output CSV filen    csvFile, csvErr := os.Create(u0022industries.csvu0022)n    // if the file creation failsn    if csvErr != nil {n        log.Fatalln(u0022Failed to create the output CSV fileu0022, csvErr)n    }n    // release the resource allocated to handlen    // the file before ending the executionn    defer csvFile.Close()nn    // create a CSV file writern    writer := csv.NewWriter(csvFile)n    // release the resources associated with then    // file writer before ending the executionn    defer writer.Flush()nn    // add the header row to the CSVn    headers := []string{n        u0022urlu0022,n        u0022imageu0022,n        u0022nameu0022,n    }n    writer.Write(headers)nn    // store each Industry product in then    // output CSV filen    for _, industry := range industries {n        // convert the Industry instance ton        // a slice of stringsn        record := []string{n            industry.Url,n            industry.Image,n            industry.Name,n        }n        // add a new CSV recordn        writer.Write(record)n    }nn    // u002du002d- export to JSON u002du002d-nn    // open the output JSON filen    jsonFile, jsonErr := os.Create(u0022industries.jsonu0022)n    if jsonErr != nil {n        log.Fatalln(u0022Failed to create the output JSON fileu0022, jsonErr)n    }n    defer jsonFile.Close()n    // convert industries to an indented JSON stringn    jsonString, _ := json.MarshalIndent(industries, u0022 u0022, u0022 u0022)nn    // write the JSON string to filen    jsonFile.Write(jsonString)n}

Goを使って、100行未満のコードでデータスクレイパーを構築できます!

 

まとめ

このチュートリアルでは、Goがウェブスクレイピングに適した言語である理由を学びました。また、最高のGoスクレイピングライブラリが何なのか、それらが何を提供しているのかも理解できました。そして、CollyとGoの標準ライブラリを使ってウェブスクレイピングアプリケーションを作成する方法を学びました。ここで構築されたGoスクレイパーは、現実世界のターゲットからデータをスクレイピングできます。ご覧いただいたように、Goを使ったウェブスクレイピングは、わずか数行のコードしか必要としません。

同時に、インターネットからデータを抽出する際には、考慮すべき多くの課題があることも念頭に置いておいてください。実際、多くのウェブサイトでは、Goスクレイピングスクリプトを検出してブロックすることができるアンチスクレイピングおよびアンチボットソリューションを採用しています。幸いなことに、Bright Dataの次世代Web Scraper IDEを使えば、あらゆるブロックを回避してウェブスクレイパーを構築できます。

 

ウェブスクレイピングに取り組むつもりは一切ないとしても、ウェブデータには興味がおありですか?すぐに利用できる当社のデータセットをご検討ください。