Обмен технологиями

Платформа сканера Go1.19: упростите автоматическое сканирование шаблонов сайтов.

2024-07-12

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

введение

Web Scraper — это инструмент, который автоматически извлекает данные с веб-сайтов. Они широко используются в сборе данных, поисковой оптимизации, исследованиях рынка и других областях. В этой статье будет подробно описано, как использовать Go 1.19 для реализации упрощенного инструмента автоматического сканирования шаблонов сайтов, который поможет разработчикам эффективно собирать данные.

Оглавление

  1. Экологическая подготовка
  2. Основные понятия веб-сканеров
  3. Выбор платформы сканирования Go
  4. Основной процесс проектирования гусеничного робота
  5. Реализация простого веб-сканера
  6. Анализировать HTML-контент
  7. Параллельная обработка сканеров
  8. хранилище данных
  9. Обработка ошибок и механизм повтора
  10. Практический пример: сканирование новостных сайтов
  11. Расширенные функции и оптимизации
  12. в заключение

1. Подготовка среды

Прежде чем начать, убедитесь, что в вашей системе установлен Go 1.19. Вы можете проверить версию Go с помощью следующей команды:

go version
  • 1

Если вы еще не установили Go, вы можете скачать его с сайта Перейти на официальный сайт Загрузите и установите последнюю версию.

2. Основные понятия веб-сканеров

Основной рабочий процесс веб-сканера выглядит следующим образом:

  1. послать запрос: отправить HTTP-запрос на целевую веб-страницу.
  2. Получить ответ: Получите ответ HTTP, возвращенный сервером.
  3. анализировать контент: Извлеките необходимые данные из ответа.
  4. Хранение данных: сохраните извлеченные данные в локальный файл или базу данных.
  5. Обработка ссылок: Извлечение ссылок с веб-страниц и продолжение сканирования других страниц.

3. Выбор платформы сканирования Go

В языке Go существует несколько популярных фреймворков для сканирования, таких как:

  • Colly: быстрая и элегантная среда сканирования, обеспечивающая богатую функциональность и хорошую производительность.
  • Goquery: подобная jQuery библиотека для анализа и управления HTML-документами.
  • HTTP-клиент: пакет net/http стандартной библиотеки может удовлетворить большинство простых запросов HTTP.

В этой статье в основном будут использоваться Colly и Goquery для сканирования веб-страниц и анализа контента.

4. Основной процесс проектирования сканера

Мы разработаем упрощенный инструмент автоматического сканирования шаблонов сайтов. Основной процесс выглядит следующим образом:

  1. Инициализируйте конфигурацию сканера.
  2. Отправьте HTTP-запрос для получения содержимого веб-страницы.
  3. Используйте Goquery для анализа HTML-контента и извлечения необходимых данных.
  4. Сохраните данные в локальный файл или базу данных.
  5. Механизмы обработки ошибок и повторных попыток.
  6. Используйте параллельную обработку для повышения эффективности сканирования.

5. Внедрите простой веб-сканер

Сначала создайте новый проект 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

Затем напишите простой сканер для сканирования веб-контента:

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-контента

Чтобы извлечь необходимые данные с веб-страницы, нам нужно использовать Goquery для анализа HTML-контента. В следующем примере показано, как использовать Goquery для извлечения ссылок и текста с веб-страницы:

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. Практический пример: сканирование новостных сайтов

В следующем примере показано, как очистить заголовки и ссылки новостного веб-сайта и сохранить их в файл 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. Расширенные функции и оптимизации.

Используйте прокси

Чтобы избежать блокировки целевым веб-сайтом, вы можете использовать прокси:

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

Динамический парсинг веб-страниц

Для динамических веб-страниц вы можете использовать автономный браузер, например 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, параллельная обработка, хранение данных и обработка ошибок, а также продемонстрировали, как сканировать и обрабатывать данные веб-страницы на конкретных примерах кода.

Мощные возможности параллельной обработки языка Go и богатые сторонние библиотеки делают его идеальным выбором для создания эффективных и стабильных веб-сканеров. Благодаря постоянной оптимизации и расширению можно реализовать более сложные и продвинутые функции сканера, обеспечивающие решения для различных потребностей в сборе данных.

Я надеюсь, что эта статья может предоставить вам ценную информацию по реализации веб-сканеров на языке Go и вдохновить вас на дальнейшие исследования и инновации в этой области.