技術共有

Go1.19 クローラー フレームワーク: サイト テンプレートの自動クロールを簡素化します。

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

導入

Web Scraper は、Web サイトからデータを自動的に抽出するツールです。データ収集、検索エンジンの最適化、市場調査などの分野で広く使用されています。この記事では、Go 1.19 を使用して、開発者が効率的にデータを収集できるように、簡素化された自動サイト テンプレート クロール ツールを実装する方法を詳しく紹介します。

目次

  1. 環境整備
  2. Web クローラーの基本概念
  3. Go クローラー フレームワークの選択
  4. クローラー設計の基本プロセス
  5. 単純な Web クローラーを実装する
  6. HTMLコンテンツを解析する
  7. クローラーの同時処理
  8. データストレージ
  9. エラー処理と再試行メカニズム
  10. 実際のケース: ニュース Web サイトのクローリング
  11. 高度な機能と最適化
  12. 結論は

1. 環境の準備

始める前に、システムに Go 1.19 がインストールされていることを確認してください。 Go のバージョンは次のコマンドで確認できます。

go version
  • 1

Go をまだインストールしていない場合は、次からダウンロードできます。 ゴー公式サイト 最新バージョンをダウンロードしてインストールします。

2. Web クローラーの基本概念

Web クローラーの基本的なワークフローは次のとおりです。

  1. リクエストを送信する: HTTP リクエストをターゲット Web ページに送信します。
  2. 応答を取得する: サーバーから返された HTTP 応答を受信します。
  3. コンテンツを解析する: 応答から必要なデータを抽出します。
  4. データの保存: 抽出したデータをローカル ファイルまたはデータベースに保存します。
  5. ハンドルリンク: Web ページからリンクを抽出し、他のページのクロールを続けます。

3. Go クローラー フレームワークの選択

Go 言語には、次のような人気のあるクローラー フレームワークがいくつかあります。

  • Colly: 豊富な機能と優れたパフォーマンスを提供する、高速でエレガントなクローラー フレームワーク。
  • Goquery: HTML ドキュメントを解析および操作するための jQuery に似たライブラリ。
  • HTTP クライアント: 標準ライブラリの net/http パッケージは、最も単純な HTTP リクエストのニーズを満たすことができます。

この記事では、主に Web クローリングとコンテンツ解析に Colly と Goquery を使用します。

4. クローラー設計の基本プロセス

簡素化された自動サイト テンプレート クロール ツールを設計します。基本的なプロセスは次のとおりです。

  1. クローラー設定を初期化します。
  2. HTTP リクエストを送信して Web ページのコンテンツを取得します。
  3. Goquery を使用して HTML コンテンツを解析し、必要なデータを抽出します。
  4. データをローカル ファイルまたはデータベースに保存します。
  5. エラー処理と再試行メカニズム。
  6. 同時処理を使用してクロールの効率を向上させます。

5. 単純な Web クローラーを実装する

まず、新しい Go プロジェクトを作成します。

mkdir go_scraper
cd go_scraper
go mod init go_scraper
  • 1
  • 2
  • 3

次に、Colly と Goquery をインストールします。

go get -u github.com/gocolly/colly
go get -u github.com/PuerkitoBio/goquery
  • 1
  • 2

次に、Web コンテンツをクロールするための単純なクローラーを作成します。

package main

import (
    "fmt"
    "github.com/gocolly/colly"
)

func main() {
    // 创建一个新的爬虫实例
    c := colly.NewCollector()

    // 设置请求时的回调函数
    c.OnRequest(func(r *colly.Request) {
        fmt.Println("Visiting", r.URL.String())
    })

    // 设置响应时的回调函数
    c.OnResponse(func(r *colly.Response) {
        fmt.Println("Visited", r.Request.URL)
        fmt.Println("Response:", string(r.Body))
    })

    // 设置错误处理的回调函数
    c.OnError(func(r *colly.Response, err error) {
        fmt.Println("Error:", err)
    })

    // 设置HTML解析时的回调函数
    c.OnHTML("title", func(e *colly.HTMLElement) {
        fmt.Println("Title:", e.Text)
    })

    // 开始爬取
    c.Visit("http://example.com")
}
  • 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

上記のコードを実行すると、http://example.com のコンテンツがクロールされ、ページ タイトルが出力されます。

6. HTML コンテンツを解析する

Web ページから必要なデータを抽出するには、Goquery を使用して HTML コンテンツを解析する必要があります。次の例は、Goquery を使用して Web ページからリンクとテキストを抽出する方法を示しています。

package main

import (
    "fmt"
    "github.com/gocolly/colly"
    "github.com/PuerkitoBio/goquery"
)

func main() {
    c := colly.NewCollector()

    c.OnHTML("body", func(e *colly.HTMLElement) {
        e.DOM.Find("a").Each(func(index int, item *goquery.Selection) {
            link, _ := item.Attr("href")
            text := item.Text()
            fmt.Printf("Link #%d: %s (%s)n", index, text, link)
        })
    })

    c.Visit("http://example.com")
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

7. クローラーの同時処理

クローラーの効率を向上させるために、Colly の同時実行機能を使用できます。

package main

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

func main() {
    c := colly.NewCollector(
        colly.Async(true), // 启用异步模式
    )

    c.Limit(&colly.LimitRule{
        DomainGlob:  "*",
        Parallelism: 2, // 设置并发数
        Delay:       2 * time.Second,
    })

    c.OnHTML("body", func(e *colly.HTMLElement) {
        e.DOM.Find("a").Each(func(index int, item *goquery.Selection) {
            link, _ := item.Attr("href")
            text := item.Text()
            fmt.Printf("Link #%d: %s (%s)n", index, text, link)
            c.Visit(e.Request.AbsoluteURL(link))
        })
    })

    c.OnRequest(func(r *colly.Request) {
        fmt.Println("Visiting", r.URL.String())
    })

    c.OnError(func(r *colly.Response, err error) {
        log.Println("Error:", err)
    })

    c.Visit("http://example.com")

    c.Wait() // 等待所有异步任务完成
}
  • 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
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

8. データストレージ

キャプチャしたデータをローカル ファイルまたはデータベースに保存します。 CSV ファイルの例を次に示します。

package main

import (
    "encoding/csv"
    "fmt"
    "github.com/gocolly/colly"
    "github.com/PuerkitoBio/goquery"
    "log"
    "os"
    "time"
)

func main() {
    file, err := os.Create("data.csv")
    if err != nil {
        log.Fatalf("could not create file: %v", err)
    }
    defer file.Close()

    writer := csv.NewWriter(file)
    defer writer.Flush()

    c := colly.NewCollector(
        colly.Async(true),
    )

    c.Limit(&colly.LimitRule{
        DomainGlob:  "*",
        Parallelism: 2,
        Delay:       2 * time.Second,
    })

    c.OnHTML("body", func(e *colly.HTMLElement) {
        e.DOM.Find("a").Each(func(index int, item *goquery.Selection) {
            link, _ := item.Attr("href")
            text := item.Text()
            fmt.Printf("Link #%d: %s (%s)n", index, text, link)
            writer.Write([]string{text, link})
            c.Visit(e.Request.AbsoluteURL(link))
        })
    })

    c.OnRequest(func(r *colly.Request) {
        fmt.Println("Visiting", r.URL.String())
    })

    c.OnError(func(r *colly.Response, err error) {
        log.Println("Error:", err)
    })

    c.Visit("http://example.com")

    c.Wait()
}
  • 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
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

9. エラー処理と再試行メカニズム

クローラーの安定性を向上させるには、リクエスト エラーを処理し、再試行メカニズムを実装する必要があります。

package main

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

func main() {
    file, err := os.Create("data.csv")
    if err != nil {
        log.Fatalf("could not create file: %v", err)
    }
    defer file.Close()

    writer := csv.NewWriter(file)
    defer writer.Flush()

    c := colly.NewCollector(
        colly.Async(true),
        colly.MaxDepth(1),
    )

    c.Limit(&colly.LimitRule{
        DomainGlob:  "*",
        Parallelism: 2,
        Delay:       2 * time.Second,
    })

    c.OnHTML("body", func(e *colly.HTMLElement) {
        e.DOM.Find("a").Each(func(index int, item *goquery.Selection) {
            link, _ := item.Attr("href")
            text := item.Text()
            fmt.Printf("Link #%d: %s (%s)

n", index, text, link)
            writer.Write([]string{text, link})
            c.Visit(e.Request.AbsoluteURL(link))
        })
    })

    c.OnRequest(func(r *colly.Request) {
        fmt.Println("Visiting", r.URL.String())
    })

    c.OnError(func(r *colly.Response, err error) {
        log.Println("Error:", err)
        // 重试机制
        if r.StatusCode == 0 || r.StatusCode >= 500 {
            r.Request.Retry()
        }
    })

    c.Visit("http://example.com")

    c.Wait()
}
  • 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
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

10. 実践例: ニュース Web サイトのクローリング

次の例は、ニュース Web サイトのタイトルとリンクをスクレイピングして CSV ファイルに保存する方法を示しています。

package main

import (
    "encoding/csv"
    "fmt"
    "github.com/gocolly/colly"
    "log"
    "os"
    "time"
)

func main() {
    file, err := os.Create("news.csv")
    if err != nil {
        log.Fatalf("could not create file: %v", err)
    }
    defer file.Close()

    writer := csv.NewWriter(file)
    defer writer.Flush()

    writer.Write([]string{"Title", "Link"})

    c := colly.NewCollector(
        colly.Async(true),
    )

    c.Limit(&colly.LimitRule{
        DomainGlob:  "*",
        Parallelism: 5,
        Delay:       1 * time.Second,
    })

    c.OnHTML(".news-title", func(e *colly.HTMLElement) {
        title := e.Text
        link := e.ChildAttr("a", "href")
        writer.Write([]string{title, e.Request.AbsoluteURL(link)})
        fmt.Printf("Title: %snLink: %sn", title, e.Request.AbsoluteURL(link))
    })

    c.OnRequest(func(r *colly.Request) {
        fmt.Println("Visiting", r.URL.String())
    })

    c.OnError(func(r *colly.Response, err error) {
        log.Println("Error:", err)
        if r.StatusCode == 0 || r.StatusCode >= 500 {
            r.Request.Retry()
        }
    })

    c.Visit("http://example-news-site.com")

    c.Wait()
}
  • 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
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

11. 高度な機能と最適化

プロキシを使用する

ターゲット Web サイトによってブロックされないようにするには、プロキシを使用できます。

c.SetProxy("http://proxyserver:port")
  • 1

ユーザーエージェントのマスカレード

ユーザー エージェントを設定して、別のブラウザーのふりをします。

c.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"
  • 1

分散型クローラー

Colly の拡張ライブラリ Colly-Redis を使用して分散クローラーを実装できます。

import (
    "github.com/gocolly/redisstorage"
)

func main() {
    c := colly.NewCollector()
    redisStorage := &redisstorage.Storage{
        Address:  "localhost:6379",
        Password: "",
        DB:       0,
        Prefix:   "colly",
    }
    c.SetStorage(redisStorage)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

動的なWebスクレイピング

動的な Web ページの場合は、chromedp などのヘッドレス ブラウザを使用できます。

import (
    "context"
    "github.com/chromedp/chromedp"
)

func main() {
    ctx, cancel := chromedp.NewContext(context.Background())
    defer cancel()

    var res string
    err := chromedp.Run(ctx,
        chromedp.Navigate("http://example.com"),
        chromedp.WaitVisible(`#some-element`),
        chromedp.InnerHTML(`#some-element`, &res),
    )

    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(res)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

12. 結論

この記事の詳細な紹介を通じて、Go 1.19 を使用して簡略化された自動サイト テンプレート クロール ツールを実装する方法を学びました。基本的なクローラー設計プロセスから開始し、HTML 解析、同時処理、データ ストレージ、エラー処理などの主要な側面に徐々に進み、特定のコード例を通じて Web ページ データをクロールおよび処理する方法を示しました。

Go 言語の強力な同時処理機能と豊富なサードパーティ ライブラリにより、Go 言語は効率的で安定した Web クローラーを構築するのに理想的な選択肢となります。継続的な最適化と拡張により、より複雑かつ高度なクローラ機能を実現し、さまざまなデータ収集ニーズに対するソリューションを提供します。

この記事が、Go 言語で Web クローラーを実装するための貴重な参考資料となり、この分野でさらなる探索と革新を行うきっかけになれば幸いです。