[Golang]goqueryを使ってスクレイピング!

最近、Nuxt.jsばかり触っていたので、久しぶりにGolangの記事を書こうと思います。

今回は、Golangでのスクレイピングをやってみました。もっと詳しい記事もあるけど、自分用に記録。

PythonでのBeatiful Soupでスクレイピングは結構やってたんですけど、Goにも便利なライブラリがあるのかなと調べてみたら、goqueryというのがあるではないですか。

さっそく使っていきましょう。

導入

go get github.com/PuerkitoBio/goquery

とりあえずライブラリのGithubにあるExampleを参考にして、このブログから記事のタイトルとタグを取得してみましょう!

実装

main.goを作成して、必要なパッケージをimportしておきましょう。最後にコードの全貌を載せておきます。

package main

import (
  "fmt"
  "log"
  "net/http"

  "github.com/PuerkitoBio/goquery"
)

あと、main()はこれだけを記入しておいてください。

func main() {
  YoujScrape()
}

そんなにコードは長くないので中に直接書いても良いのですが、まあ目的をわかりやすく。

では、YoujScrape()を書いていきます。

まずリクエストするURLを記述します。

res, err := http.Get("https://youj.work")
if err != nil {
  log.Fatal(err)
}
defer res.Body.Close()
if res.StatusCode != 200 {
  log.Fatalf("status code error: %d %s", res.StatusCode, res.Status)
}

次にHTMLを読み込みます。

doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
  log.Fatal(err)
}

そしてそこから記事のタイトルとタグを取得します。その際、クラスを指定して取得しましょう。

doc.Find("article").Each(func(i int, s *goquery.Selection) {
  // ブログのタイトルとタグを取得
  title := s.Find("a.post-link").Text()
  tags := s.Find("div.post-category").Text()

  fmt.Printf("Blog %d: %s - %s\n", i, title, tags)
})

実際に実行してみるとこんな感じ。

Blog 0: [Nuxt]FontAwesomeで使いたいアイコンだけを使おう[Vue] -
           Vue.js
           Nuxt.js


Blog 1: [Nuxt]vue-burger-menuを使ってサイドメニューを作る![Vue] -
           Vue.js
           Nuxt.js


Blog 2: [Nuxt]Firebase Realtime Databaseを使った基本的なCRUD -
           Firebase
           Nuxt.js


Blog 3: Hugoでブログを作っちゃおう! -
           hugo


Blog 4: [Nuxt]Firebase Authenticationを使ってTwitterログインを実装! -
           Firebase
           Nuxt.js


Blog 5: [Nuxt]FontAwesome CDNを反映させよう -
           Nuxt.js


Blog 6: [Nuxt.js]Firebase Hostingにデプロイしてみよう! -
           Firebase
           Nuxt.js

簡単にスクレイピングできちゃいました!これで投稿されたタグの多い順とかをグラフ化したりすると楽しいかも。

コード

最後になりますがコードをまとめて。

package main

import (
  "fmt"
  "log"
  "net/http"

  "github.com/PuerkitoBio/goquery"
)

func YoujScrape() {
  // Request the HTML page.
  res, err := http.Get("https://youj.work")
  if err != nil {
    log.Fatal(err)
  }
  defer res.Body.Close()
  if res.StatusCode != 200 {
    log.Fatalf("status code error: %d %s", res.StatusCode, res.Status)
  }

  // HTMLを読み込む
  doc, err := goquery.NewDocumentFromReader(res.Body)
  if err != nil {
    log.Fatal(err)
  }

  // ブログのこんてんつ取得
  doc.Find("article").Each(func(i int, s *goquery.Selection) {
    // ブログのタイトルとタグを取得
    title := s.Find("a.post-link").Text()
    tags := s.Find("div.post-category").Text()

    fmt.Printf("Blog %d: %s - %s\n", i, title, tags)
  })
}

func main() {
  YoujScrape()
}