Lチカ開発ブログ

https://l-chika.com/の開発ブログ

Goでgoqueryを利用してスクレイピング

Goでスクレイピング

やりたい事

  1. 検索結果へアクセス。
  2. 検索結果の一覧から、各詳細ページのリンク取得
  3. 詳細ページのコンテンツにアクセス
  4. 検索結果の次のページのリンクを取得。1へ戻る。

github.com

実装

パッケージをインストール

$ go get github.com/PuerkitoBio/goquery

goqueryで実装

$ vim scraping.go
package main

import (
    "github.com/PuerkitoBio/goquery"
    "log"
    "fmt"
    "time"
)

const (
    BASE_URL = "https://hoge"
)

func main() {
    url := nextUrl(BASE_URL + "/foo")
    contentsLinks(BASE_URL + url)
    
    for {
        url = nextUrl(BASE_URL + url)
        if url == "" {
            break
        }
        contentsLinks(BASE_URL + url)
        time.Sleep(3 * time.Second)
    }
}

func contentsLinks(url string) {
    doc, err := goquery.NewDocument(url)
    if err != nil {
        log.Fatal(err)
    }

    var links []string
    // コンテンツの一覧から各詳細ページのURLを検索
    doc.Find("#hoge p.foo a").Each(func(_ int, s *goquery.Selection) {
          url, _ = s.Attr("href")
          links = append(links, url)
    })
    
    // 各詳細ページをスクレイピング
    for _, link := range links {
        a, b := content(BASE_URL + link)
        fmt.Printf("%s, %s\n", a, b)
    }
}

func content(url string) (string, string) {
    doc, err := goquery.NewDocument(url)
    if err != nil {
        log.Fatal(err)
    }

    var name, link string
    doc.Find("#detail div.col-sm-9.col-xs-7.col-xxs-12 ").Each(func(_ int, s *goquery.Selection) {
          name = s.Find("h5.info_inner_title.pdB10.h4").Text()
          link = s.Find("dl.info_inner_contents dd.abel.blue.pdB15 a").Text()
    })
    return name, link
}

// ページネーションから「次へ」のリンクを取得
func nextUrl(current string) (url string) {
    fmt.Printf("========== url: %s\n", current)
    doc, err := goquery.NewDocument(current)
    if err != nil {
        log.Fatal(err)
    }

    var exist bool
    doc.Find("ul.pagination li.next a").Each(func(_ int, s *goquery.Selection) {
          url, exist = s.Attr("href")
    })
    if !exist {
        return ""
    }
    return
}

スターティングGo言語

スターティングGo言語