Berbagi teknologi

Kerangka kerja perayap Go1.19: menyederhanakan perayapan otomatis templat situs

2024-07-12

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

perkenalan

Web Scraper adalah alat yang secara otomatis mengekstrak data dari situs web. Mereka banyak digunakan dalam pengumpulan data, optimasi mesin pencari, riset pasar dan bidang lainnya. Artikel ini akan memperkenalkan secara detail cara menggunakan Go 1.19 untuk mengimplementasikan alat perayapan templat situs otomatis yang disederhanakan guna membantu pengembang mengumpulkan data secara efisien.

Daftar isi

  1. Persiapan lingkungan
  2. Konsep dasar perayap web
  3. Buka pemilihan kerangka kerja perayap
  4. Proses dasar merancang crawler
  5. Menerapkan perayap web sederhana
  6. Parsing konten HTML
  7. Pemrosesan crawler secara konkurensi
  8. penyimpanan data
  9. Mekanisme penanganan kesalahan dan coba lagi
  10. Kasus praktis: merayapi situs berita
  11. Fitur dan pengoptimalan lanjutan
  12. Kesimpulannya

1. Persiapan lingkungan

Sebelum memulai, pastikan Anda telah menginstal Go 1.19 di sistem Anda. Anda dapat memeriksa versi Go dengan perintah berikut:

go version
  • 1

Jika Anda belum menginstal Go, Anda dapat mendownloadnya dari Buka situs web resmi Unduh dan instal versi terbaru.

2. Konsep dasar web crawler

Alur kerja dasar perayap web adalah sebagai berikut:

  1. kirim permintaan: Mengirim permintaan HTTP ke halaman web target.
  2. Dapatkan tanggapan: Menerima respons HTTP yang dikembalikan oleh server.
  3. mengurai konten: Ekstrak data yang diperlukan dari respons.
  4. Menyimpan data: Menyimpan data yang diekstraksi ke file atau database lokal.
  5. Tangani tautan: Mengekstrak link dari halaman web dan terus meng-crawl halaman lainnya.

3. Pilih kerangka kerja perayap

Dalam bahasa Go, terdapat beberapa framework crawler yang populer, seperti:

  • Colly: Kerangka kerja perayap yang cepat dan elegan yang menyediakan fungsionalitas yang kaya dan kinerja yang baik.
  • Goquery: Pustaka mirip jQuery untuk mem-parsing dan memanipulasi dokumen HTML.
  • Klien HTTP: Paket net/http dari perpustakaan standar dapat memenuhi sebagian besar kebutuhan permintaan HTTP sederhana.

Artikel ini terutama akan menggunakan Colly dan Goquery untuk perayapan web dan penguraian konten.

4. Proses dasar perancangan crawler

Kami akan merancang alat perayapan templat situs otomatis yang disederhanakan. Proses dasarnya adalah sebagai berikut:

  1. Inisialisasi konfigurasi perayap.
  2. Kirim permintaan HTTP untuk mendapatkan konten halaman web.
  3. Gunakan Goquery untuk mengurai konten HTML dan mengekstrak data yang diperlukan.
  4. Simpan data ke file atau database lokal.
  5. Mekanisme penanganan kesalahan dan coba lagi.
  6. Gunakan pemrosesan bersamaan untuk meningkatkan efisiensi perayapan.

5. Menerapkan perayap web sederhana

Pertama, buat proyek Go baru:

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

Kemudian, instal Colly dan Goquery:

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

Selanjutnya, tulis perayap sederhana untuk merayapi konten 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

Menjalankan kode di atas akan merayapi konten http://example.com dan mencetak judul halaman.

6. Parsing konten HTML

Untuk mengekstrak data yang diperlukan dari halaman web, kita perlu menggunakan Goquery untuk mengurai konten HTML. Contoh berikut menunjukkan cara menggunakan Goquery untuk mengekstrak link dan teks dari halaman 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. Pemrosesan crawler secara bersamaan

Untuk meningkatkan efisiensi crawler, kita dapat menggunakan fungsi konkurensi 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. Penyimpanan data

Simpan data yang diambil ke file atau database lokal. Berikut adalah file CSV sebagai contoh:

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. Mekanisme penanganan kesalahan dan percobaan ulang

Untuk meningkatkan stabilitas crawler, kita perlu menangani kesalahan permintaan dan menerapkan mekanisme percobaan ulang:

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. Kasus praktis: merayapi situs berita

Contoh berikut menunjukkan cara mengikis judul dan tautan situs web berita dan menyimpannya ke file 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. Fungsi dan optimasi lanjutan

Gunakan proksi

Agar tidak diblokir oleh website target, Anda dapat menggunakan proxy:

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

Agen pengguna menyamar

Berpura-pura menjadi browser yang berbeda dengan mengatur agen pengguna:

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

Perayap terdistribusi

Anda dapat menggunakan perpustakaan ekstensi Colly Colly-Redis untuk mengimplementasikan crawler terdistribusi:

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

Pengikisan web dinamis

Untuk halaman web dinamis, Anda dapat menggunakan browser headless seperti 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. Kesimpulan

Melalui pengenalan mendetail di artikel ini, kita telah mempelajari cara menggunakan Go 1.19 untuk mengimplementasikan alat perayapan templat situs otomatis yang disederhanakan. Kami memulai dari proses desain perayap dasar dan secara bertahap beralih ke aspek-aspek utama seperti penguraian HTML, pemrosesan bersamaan, penyimpanan data, dan penanganan kesalahan, serta mendemonstrasikan cara merayapi dan memproses data halaman web melalui contoh kode spesifik.

Kemampuan pemrosesan konkurensi bahasa Go yang kuat dan perpustakaan pihak ketiga yang kaya menjadikannya pilihan ideal untuk membangun perayap web yang efisien dan stabil. Melalui optimalisasi dan perluasan berkelanjutan, fungsi crawler yang lebih kompleks dan canggih dapat dicapai untuk memberikan solusi bagi berbagai kebutuhan pengumpulan data.

Saya harap artikel ini dapat memberi Anda referensi berharga untuk mengimplementasikan web crawler dalam bahasa Go dan menginspirasi Anda untuk melakukan lebih banyak eksplorasi dan inovasi di bidang ini.