yikegaya’s blog

仕事関連(Webエンジニア)と資産運用について書いてます

ゴルーチンの練習でWebスクレイピングCLI書いてみた

書いたもの

package main

import (
    "goroutine-scraping-cli/sites"

    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup

    resultChannel := make(chan sites.Article)

    wg.Add(2)

    go func() {
        articles := sites.ScrapingHatenaItHotentry()
        for _, article := range articles {
            resultChannel <- article
        }
        defer wg.Done()
    }()

    go func() {
        articles := sites.ScrapingQiitaWeeklyTrend()
        for _, article := range articles {
            resultChannel <- article
        }
        defer wg.Done()
    }()

    go func() {
        wg.Wait()
        close(resultChannel)
    }()

    for result := range resultChannel {
        fmt.Println(result)
    }
}
package sites

type Article struct {
    Title string
    URL   string
}
package sites

import (
    "fmt"

    "github.com/gocolly/colly/v2"
)

func ScrapingHatenaItHotentry() []Article {
    fmt.Println("はてなITホットエントリー")
    url := "https://b.hatena.ne.jp/hotentry/it"

    c := colly.NewCollector()

    var articles []Article

    c.OnHTML(".entrylist-contents-main", func(e *colly.HTMLElement) {
        title := e.ChildText("h3")
        link := e.ChildAttr("a", "href")
        article := Article{Title: title, URL: link}
        articles = append(articles, article)
    })

    c.Visit(url)

    return articles
}
package sites

import (
    "fmt"
    "strings"

    "github.com/gocolly/colly/v2"
)

func ScrapingQiitaWeeklyTrend() []Article {
    fmt.Println("Qiita週間トレンド")
    url := "https://b.hatena.ne.jp/hotentry/it"

    c := colly.NewCollector()

    var articles []Article

    c.OnHTML("h3", func(e *colly.HTMLElement) {
        title := e.ChildText("span")
        link := e.ChildAttr("a", "href")
        if strings.HasPrefix(link, "https") {
            article := Article{Title: title, URL: link}
            articles = append(articles, article)
        }
    })

    c.Visit(url)

    return articles
}

解説

main関数

  • wgという名前のsync.WaitGroupを宣言しています。ゴルーチンの完了するのを待つために使用します。
  • resultChannelという名前のチャネルを作成しています。スクレイピング結果を受け取るために使用します。
  • wg.Add(2) でsync.WaitGroupに2つのタスクを追加します。
  • 最初のゴルーチンは、sites.ScrapingHatenaItHotentry() 関数を呼び出して、はてなブックマークのホットエントリーをスクレイピングし、結果をresultChannelチャネルに送信します。
  • 2つ目のゴルーチンは、sites.ScrapingQiitaWeeklyTrend() 関数を呼び出して、Qiitaの週間トレンド記事をスクレイピングし、結果をresultChannelチャネルに送信します。
  • wg.Wait() ですべてのゴルーチンの完了を待ちます。
  • resultChannel チャネルをクローズします。この程度の内容であればチャネルいらないんですが勉強のため書きたくて書いてます。 ゴルーチンが全て完了した後、resultChannelチャネルをクローズします。
  • for result := range resultChannelループで、resultChannelチャネルから結果を読み取ります。

ScrapingHatenaItHotentry

広く使われてそうなcollyというWebスクレイピングライブラリを使ってみました。

c.OnHTMLメソッドでentrylist-contents-mainクラス内のa.href要素を抜き出してスライスに追加しています。

終わり