Веб-скрепинг - это мощная техника извлечения данных с веб-сайтов, и Golang (Go) - отличный язык для решения этой задачи. Известный своей производительностью и эффективностью, Go может с легкостью справиться с веб-скраппингом. Итак, как извлечь данные из Интернета с помощью Golang? В этом руководстве мы расскажем вам о том, как с помощью языка Golang можно скрапировать веб-страницы, а также о соответствующих техниках и советах.
Подходит ли Golang для сбора данных из Интернета?
Прежде чем узнать больше о том, как собирать данные из Интернета с помощью Golang, важно понять, почему для веб-скрапинга стоит выбрать именно Golang и какие преимущества он дает.
Golang - отличный выбор для веб-скрапинга благодаря высокой производительности, эффективной модели параллелизма и надежной стандартной библиотеке. Благодаря возможности одновременной обработки нескольких запросов с помощью goroutines и встроенным пакетам для HTTP-запросов и разбора HTML, Go может эффективно скрапировать большие объемы данных. Его простота и возможности обработки ошибок еще больше упрощают процесс разработки, а сторонние библиотеки, такие как Colly и Goquery, предлагают дополнительную функциональность. Хотя Go не так распространен, как Python, для веб-скрапинга, его преимущества делают его привлекательным вариантом для тех, кто знаком с этим языком.
Базовая конфигурация для соскабливания веб-данных с помощью Golang
Скраппинг данных из Интернета с помощью Go (Golang) заключается в выполнении HTTP-запросов для получения веб-страниц и последующем разборе HTML-содержимого для извлечения нужной информации. Ниже приведено пошаговое руководство по извлечению данных из Интернета с помощью Go:
-
-
Настройка среды
Сначала убедитесь, что Go установлена в вашей системе. Люди не могут скачать его с сайта официальный сайт.
-
Установка необходимых пакетов
Несколько пакетов необходимы для работы с HTTP-запросами и разбором HTML. Наиболее популярными пакетами являются net/http для HTTP-запросов и goquery для разбора HTML.
Получите конкретный пакет, выполнив команду like:
получить github.com/PuerkitoBio/goquery
Написание скребка
Вот простой пример, демонстрирующий, как с помощью Golang соскрести данные с веб-сайта:
основной пакет импорт ( "fmt" "log" "net/http" "github.com/PuerkitoBio/goquery" ) func main() { // URL-адрес сайта, с которого будет производиться поиск url := "https://example.com" // Выполняем HTTP GET запрос res, err := http.Get(url) if err != nil { log.Fatal(err) } defer res.Body.Close() // Проверьте код состояния ответа if res.StatusCode != 200 { log.Fatalf("Failed to fetch data: %d %s", res.StatusCode, res.Status) } // Разбор HTML doc, err := goquery.NewDocumentFromReader(res.Body) if err != nil { log.Fatal(err) } // Найдите и распечатайте данные doc.Find("h1").Each(func(index int, item *goquery.Selection) { заголовок := item.Text() fmt.Println(heading) }) }
Выполнение HTTP-запросов:
http.Get(url) выполняет HTTP GET-запрос к указанному URL.
res.Body.Close() гарантирует, что тело ответа будет закрыто после прочтения.Разбор HTML:
goquery.NewDocumentFromReader(res.Body) разбирает HTML-ответ и возвращает объект goquery.Document.
Извлечение данных:
doc.Find("h1").Each() находит все элементы h1 в HTML и выполняет итерацию по ним.
item.Text() извлекает текстовое содержимое каждого элемента h1. -
Запуск скребка
Сохраните приведенный выше код в файле, например, main.go, и запустите его с помощью:
go run main.go
-
Дополнительные соображения
Обработка ошибок: Всегда обрабатывайте ошибки должным образом, чтобы не допустить неожиданного падения вашего скрепера.
С уважением robots.txt: Проверьте файл robots.txt сайта, чтобы убедиться, что вам разрешено его скрести.
Ограничение скорости: Установите ограничение скорости, чтобы не перегружать сервер запросами.
User-Agent: Установите пользовательский заголовок User-Agent для идентификации вашего скрепера, например:
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("User-Agent", "Golang_Scraper/1.0")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
// Разбор HTML, как и раньше
Продвинутые техники соскабливания веб-данных с помощью Golang
Работа с пагинацией
Многие веб-сайты используют пагинацию для разделения содержимого на несколько страниц. Чтобы собрать все данные, вам нужно обработать пагинацию, последовательно выполняя запросы к каждой странице.
Вот пример работы с пагинацией:
основной пакет
импорт (
"fmt"
"log"
"net/http"
"strconv"
"github.com/PuerkitoBio/goquery"
)
func main() {
baseURL := "https://example.com/page/"
страница := 1
для {
url := baseURL + strconv.Itoa(page)
res, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
if res.StatusCode != 200 {
log.Println("Больше нет страниц для выборки, останавливаемся.")
break
}
doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
log.Fatal(err)
}
doc.Find(".item").Each(func(index int, item *goquery.Selection) {
title := item.Find(".title").Text()
fmt.Println(title)
})
page++
}
}
Работа с рендеринговым содержимым JavaScript
Некоторые веб-сайты используют JavaScript для динамического отображения содержимого. В Go нет встроенного способа выполнения JavaScript, но вы можете использовать безголовый браузер как Хромированный.
go get -u github.com/chromedp/chromedp
Пример использования Chromedp для поиска JavaScript-рендеринга:
основной пакет
импорт (
"контекст"
"fmt"
"log"
"github.com/chromedp/chromedp"
)
func main() {
ctx, cancel := chromedp.NewContext(context.Background())
отложить cancel()
var htmlContent string
err := chromedp.Run(ctx,
chromedp.Navigate("https://example.com"),
chromedp.OuterHTML("body", &htmlContent),
)
if err != nil {
log.Fatal(err)
}
fmt.Println(htmlContent)
}
Управление сеансами и файлами cookie
Если сайт требует входа в систему или управления сеансами, вы можете обрабатывать файлы cookie и сеансы с помощью http.CookieJar.
Пример управления файлами cookie:
основной пакет
импорт (
"fmt"
"log"
"net/http"
"net/http/cookiejar"
"github.com/PuerkitoBio/goquery"
)
func main() {
jar, _ := cookiejar.New(nil)
client := &http.Client{Jar: jar}
// Вход в систему и сохранение куки
loginURL := "https://example.com/login"
loginForm := url.Values{}
loginForm.Set("имя пользователя", "ваше_имя")
loginForm.Set("пароль", "ваш_пароль")
res, err := client.PostForm(loginURL, loginForm)
if err != nil {
log.Fatal(err)
}
res.Body.Close()
// Доступ к защищенной странице
url := "https://example.com/protected-page"
res, err = client.Get(url)
if err != nil {
log.Fatal(err)
}
отложить res.Body.Close()
doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
log.Fatal(err)
}
doc.Find(".protected-content").Each(func(index int, item *goquery.Selection) {
content := item.Text()
fmt.Println(content)
})
}
Дросселирование и ограничение скорости
Чтобы избежать блокировки сайтами, используйте ограничение скорости, вводя задержки между запросами.
Пример ограничения скорости:
основной пакет
импорт (
"fmt"
"log"
"net/http"
"время"
"github.com/PuerkitoBio/goquery"
)
func main() {
urls := []string{"https://example.com/page1", "https://example.com/page2"}
for _, url := range urls {
res, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
log.Fatal(err)
}
doc.Find(".item").Each(func(index int, item *goquery.Selection) {
title := item.Find(".title").Text()
fmt.Println(title)
})
// Задержка, чтобы избежать блокировки
time.Sleep(2 * time.Second)
}
}
Обработка запросов AJAX
Некоторые веб-сайты загружают данные динамически с помощью запросов AJAX. Вы можете перехватить и воспроизвести эти запросы, используя такие инструменты, как инструменты разработчика браузера, чтобы найти конечные точки API.
Пример получения данных из конечной точки AJAX API:
основной пакет
импорт (
"encoding/json"
"fmt"
"log"
"net/http"
)
type Item struct {
Title string `json: "title"`.
}
func main() {
url := "https://example.com/api/items"
res, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
отложить res.Body.Close()
var items []Item
if err := json.NewDecoder(res.Body).Decode(&items); err != nil {
log.Fatal(err)
}
for _, item := range items {
fmt.Println(item.Title)
}
}
Работа с капчами и механизмами защиты от кражи
На веб-сайтах часто используются CAPTCHA и другие механизмы защиты от подбора. Хотя программная разгадка CAPTCHA сложна и часто противоречит условиям предоставления услуг, вы можете использовать такие приемы, как ротация пользователей-агентов и прокси-серверы, чтобы избежать обнаружения.
Пример вращающихся агентов пользователя:
основной пакет
импорт (
"fmt"
"log"
"net/http"
"math/rand"
"время"
)
func main() {
userAgents := []string{
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, как Gecko) Chrome/58.0.3029.110 Safari/537.3",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:54.0) Gecko/20100101 Firefox/54.0",
// Добавьте сюда другие агенты пользователя
}
client := &http.Client{}
rand.Seed(time.Now().UnixNano())
for i := 0; i < 5; i++ {
req, err := http.NewRequest("GET", "https://example.com", nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("User-Agent", userAgents[rand.Intn(len(userAgents))])
res, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
res.Body.Close()
fmt.Println("Запрос отправлен с user-agent:", req.Header.Get("User-Agent"))
}
}
Использование прокси-серверов
Чтобы дополнительно защитить свой IP от запрета, вы можете использовать прокси-серверы. Такие сервисы, как OkeyProxy или MacroProxy, предоставляют прокси-решения.
Являясь одним из лучших прокси-провайдеров, OkeyProxy поддерживается HTTP/HTTPS/SOCKS и предоставляет 150 миллионов с лишним реальных IP-адресов, охватывающих 200 с лишним стран/регионов, что позволяет избежать Запрет IP-адресов максимально возможной степени и обеспечивает безопасность, надежность и стабильность сетевых соединений.
Пример использования прокси с http.Client:
основной пакет
импорт (
"fmt"
"log"
"net/http"
"net/url"
)
func main() {
proxyURL, _ := url.Parse("http://proxyusername:proxypassword@proxyserver:port")
transport := &http.Transport{
Proxy: http.ProxyURL(proxyURL),
}
client := &http.Client{Transport: transport}
res, err := client.Get("https://example.com")
if err != nil {
log.Fatal(err)
}
отложить res.Body.Close()
fmt.Println("Статус ответа:", res.Status)
}
Одновременное скрапирование
Чтобы ускорить работу со скрапом, вы можете использовать гортины для одновременной обработки нескольких запросов. Это удобно при работе с большими наборами данных.
Пример одновременного скраппинга с помощью goroutines:
основной пакет
импорт (
"fmt"
"log"
"net/http"
"sync"
"github.com/PuerkitoBio/goquery"
)
func scrape(url string, wg *sync.WaitGroup) {
отложить wg.Done()
res, err := http.Get(url)
if err != nil {
log.Println(err)
return
}
defer res.Body.Close()
doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
log.Println(err)
return
}
doc.Find(".item").Each(func(index int, item *goquery.Selection) {
title := item.Find(".title").Text()
fmt.Println(title)
})
}
func main() {
urls := []string{
"https://example.com/page1",
"https://example.com/page2",
// Добавьте другие URL-адреса
}
var wg sync.WaitGroup
for _, url := range urls {
wg.Add(1)
go scrape(url, &wg)
}
wg.Wait()
}
Сбор данных из API
Многие веб-сайты предлагают API для доступа к данным. Использовать API часто проще и эффективнее, чем скрести HTML.
Пример вызова API:
основной пакет
импорт (
"encoding/json"
"fmt"
"log"
"net/http"
)
func main() {
url := "https://api.example.com/data"
res, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
отложить res.Body.Close()
var data map[string]interface{}
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
log.Fatal(err)
}
fmt.Println("Данные API:", data)
}
Хранение данных
В зависимости от ваших требований, вам может понадобиться хранить собранные данные в базе данных или в файле. Вот пример записи данных в файл CSV:
основной пакет
импорт (
"encoding/csv"
"fmt"
"log"
"os"
"net/http"
"github.com/PuerkitoBio/goquery"
)
func main() {
file, err := os.Create("data.csv")
if err != nil {
log.Fatal(err)
}
defer file.Close()
writer := csv.NewWriter(file)
defer writer.Flush()
urls := []string{"https://example.com/page1", "https://example.com/page2"}
for _, url := range urls {
res, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
log.Fatal(err)
}
doc.Find(".item").Each(func(index int, item *goquery.Selection) {
title := item.Find(".title").Text()
writer.Write([]string{title})
})
}
fmt.Println("Данные записаны в файл data.csv")
}
Обработка ошибок и ведение журнала
Надежная обработка ошибок и протоколирование очень важны для устранения неполадок и поддержки скреперов. Вы можете использовать возможности протоколирования в Go или внешние библиотеки, такие как logrus, для расширенного протоколирования.
Основные библиотеки для веб-скрапинга на Golang
- Колли:Мощный и простой в использовании фреймворк для веб-скрепинга.Установка: go get -u github.com/gocolly/colly
- GoqueryjQuery-подобная библиотека для манипулирования и запроса HTML.Установка: go get -u github.com/PuerkitoBio/goquery
- Запрос:Упрощенный HTTP-клиент для выполнения запросов.Установка: go get -u github.com/imroc/req
- Grequests:Библиотека HTTP-запросов более высокого уровня, аналогичная Python'овской Requests.Установка: go get -u github.com/levigross/grequests
- ХромированныйАвтоматизация браузера с помощью протокола Chrome DevTools Protocol.Установка: go get -u github.com/chromedp/chromedp
- Род:Современная библиотека автоматизации браузеров для Go, с акцентом на простоту использования и современные возможности.Установка: go get -u github.com/ysmood/rod
- Go-Selenium:Клиент Selenium WebDriver для Go, полезный для автоматизации работы браузеров.Установка: go get -u github.com/tebeka/selenium
- СколлиОбертка вокруг Colly для упрощенного веб-скрепинга.Установка: go get -u github.com/scolly/scolly
- Бровь нараспашкуGo-клиент для API Browshot, позволяющий делать скриншоты и скрести контент с веб-страниц.Установка: go get -u github.com/browshot/browshot-go
- Кукловод -:Go-порт Puppeteer, библиотеки Node для управления безголовым Chrome.Установка: go get -u github.com/chromedp/puppeteer-go
- Go-requests:Простая библиотека HTTP-запросов, созданная на основе Python's Requests.Установка: go get -u github.com/deckarep/golang-set
- Httpproxy:Простой HTTP-прокси-сервер для Go, полезный для маршрутизации веб-трафика для скрапбукинга.Установка: go get -u github.com/henrylee2cn/httpproxy
- Ползание:Библиотека для создания распределенных веб-краулеров.Установка: go get -u github.com/whyrusleeping/crawling
- K6Хотя K6 в первую очередь является инструментом для нагрузочного тестирования, его можно использовать для сбора веб-данных с помощью скриптов.Установка: go get -u github.com/loadimpact/k6
- Net/http:Стандартная библиотека для выполнения HTTP-запросов в Go.Установка: Встроена в Go, не требует отдельной установки.
- Goquery-html:Еще одна библиотека для разбора HTML с улучшениями на основе Goquery.Установка: go get -u github.com/PuerkitoBio/goquery-html
- Httpclient:Высокоуровневый HTTP-клиент для Go, предлагающий расширенные возможности запросов.Установка: go get -u github.com/aymerick/raymond
Эти библиотеки и инструменты охватывают широкий спектр функций, от простых HTTP-запросов до полной автоматизации браузера, что делает их универсальными для различных задач веб-скрепинга.
Резюме
Извлечение данных из Интернета с помощью Golang имеет ряд преимуществ, включая эффективность производительности и простоту параллелизма. Легкие горутины и каналы Go позволяют обрабатывать несколько одновременных запросов с минимальными затратами ресурсов, что делает его идеальным для решения масштабных задач извлечения данных. Кроме того, сильная стандартная библиотека Go поддерживает надежные возможности разбора HTTP и HTML, что упрощает разработку эффективных и надежных приложений для веб-скрепинга. Такое сочетание скорости, параллелизма и встроенных инструментов делает Golang привлекательным выбором для проектов веб-скрепинга, требующих высокой производительности и масштабируемости.