Go, также известный как Golang, — это язык программирования с открытым исходным кодом, разработанный Google для повышения эффективности и скорости программирования, особенно при работе с параллельными задачами. Go сочетает в себе преимущества статически типизированных и динамически типизированных языков, обеспечивая быструю компиляцию и высокую производительность во время выполнения.
Как создать веб-скрейпер с использованием библиотеки Colly на языке программирования Go? Nstbrowser проведет вас через код, чтобы понять каждую часть.
Не будем терять время! Разберем подробные шаги сейчас.
Перед тем как начинать скрейпинг, давайте настроим наш проект на Go. Я потрачу несколько секунд на обсуждение того, как его установить. Так что, если вы уже установили Go, проверьте это снова.
В зависимости от вашей операционной системы, вы можете найти инструкции по установке на странице документации Go. Если вы используете macOS и Brew
, вы можете выполнить установку в Терминале:
brew install go
Создайте новый каталог для вашего проекта, перейдите в этот каталог и выполните следующую команду, где вы можете заменить слово webscraper
на любое название модуля по вашему выбору.
go mod init webscraper
go mod init
создает новый модуль Go в каталоге, где она выполняется. Она создает новый файл go.mod
, который определяет зависимости и управляет версиями сторонних пакетов, используемых в проекте (аналогично package.json в Node).Теперь вы можете настроить свои скрипты для веб-скрейпинга на Go. Создайте файл scraper.go
и инициализируйте его следующим образом:
package main
import (
"fmt"
)
func main() {
// scraping logic...
fmt.Println("Hello, World!")
}
Первая строка содержит имя глобального пакета. Затем идут некоторые импорты, за которыми следует функция main()
. Это точка входа для любой программы на Go, которая будет содержать логику веб-скрейпинга на Golang. Затем вы можете запустить программу:
go run scraper.go
Это выведет:
Hello, World!
Теперь, когда вы создали базовый проект на Go, давайте углубимся в создание веб-скрейпера с использованием Golang!
Далее, давайте рассмотрим ScrapeMe как пример того, как выполнять скрейпинг страницы с Go.
Для того чтобы упростить создание веб-скрейпера, вам следует использовать одну из ранее представленных библиотек. Однако, в самом начале вам нужно определить, какая библиотека для веб-скрейпинга на Go лучше всего подходит для ваших целей.
Для этого вам нужно:
Как видно выше, целевая страница выполняет только несколько AJAX-запросов. Если вы изучите каждый XHR-запрос, вы заметите, что они не возвращают никаких значимых данных. Другими словами, сервер возвращает HTML-документ, который уже содержит все данные. Это обычно происходит с сайтами со статическим контентом.
Это означает, что целевой сайт не полагается на JavaScript для динамического извлечения данных или их отображения. Следовательно, вам не нужна библиотека с возможностями безголового браузера для извлечения данных с целевой страницы. Вы все еще можете использовать Selenium, но это только введет накладные расходы на производительность. По этой причине вы должны предпочесть простой HTML-парсер, такой как Colly.
Теперь давайте установим colly
и его зависимости:
go get github.com/gocolly/colly
Эта команда также обновит файл go.mod
всеми необходимыми зависимостями и создаст файл go.sum
.
Colly — это пакет Go, который позволяет вам писать веб-скрейперы и краулеры, построенные на основе пакета net/HTTP для сетевого взаимодействия, и помогает использовать
goquery
, который предоставляет синтаксис, похожий на jQuery, для позиционирования HTML-элементов.
Прежде чем начать его использование, вам нужно разобраться с некоторыми ключевыми концепциями Colly:
Основной сущностью в Colly является Collector, объект, который позволяет выполнять HTTP-запросы и осуществлять веб-скрейпинг с помощью следующих обратных вызовов:
OnRequest()
: вызывается перед любым HTTP-запросом с использованием Visit().OnError()
: вызывается, если в HTTP-запросе происходит ошибка.OnResponse()
: вызывается после получения ответа от сервера.OnHTML()
: вызывается после OnResponse(), если сервер возвращает допустимый HTML-документ.OnScraped()
: вызывается в конце всех вызовов OnHTML().Каждая из этих функций принимает обратный вызов в качестве параметра. Colly выполняет переданный обратный вызов, когда происходит событие, связанное с функцией. Таким образом, чтобы построить скрейпер данных в Colly, вам нужно следовать подходу, основанному на функциях обратного вызова.
Вы можете использовать функцию NewCollector() для инициализации объекта Collector:
c := colly.NewCollector()
Импортируйте Colly и создайте Collector, обновив scraper.go
следующим образом:
// scraper.go
package main
import (
// import Colly
"github.com/gocolly/colly"
)
func main() {
c := colly.NewCollector()
// scraping logic...
}
Используйте Colly для подключения к целевой странице с помощью:
c.Visit("https://scrapeme.live/shop/")
В фоновом режиме функция Visit() выполняет HTTP GET-запрос и извлекает целевой HTML-документ с сервера. Конкретно, она вызывает событие onRequest и запускает жизненный цикл функции Colly. Помните, что Visit() должна вызываться после регистрации других обратных вызовов Colly.
Обратите внимание, что HTTP-запрос, сделанный с помощью Visit(), может завершиться неудачей. Когда это происходит, Colly вызывает событие OnError. Причиной этой неудачи может быть временно недоступный сервер или недействительный URL, а веб-скрейперы часто терпят неудачу, когда целевой сайт применяет меры против роботов. Например, такие техники обычно фильтруют запросы, которые не имеют действительного заголовка User-Agent HTTP.
Что вызывает это?
Обычно Colly устанавливает временный User-Agent, который не соответствует прокси, используемому популярными браузерами. Это делает запросы Colly легко идентифицируемыми анти-скрейпинговыми технологиями. Чтобы избежать блокировки, укажите действительный заголовок User-Agent в Colly, как показано ниже:
c.UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
Ищете более эффективное решение?
Nstbrowser предоставляет полноценный API для веб-скрейпинга, который поможет вам справиться со всеми препятствиями, связанными с анти-бот системами.
Попробуйте совершенно бесплатно!
Есть ли у вас хорошие идеи или вопросы о веб-скрейпинге и Browserless?
Посмотрите чем делятся другие разработчики в Discord и Telegram!
Любой вызов Visit() теперь будет выполнять запрос с этим заголовком HTTP.
Ваш файл scraper.go теперь должен выглядеть следующим образом:
package main
import (
// import Colly
"github.com/gocolly/colly"
)
func main() {
// creating a new Colly instance
c := colly.NewCollector()
// set a valid User-Agent header
c.UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
// visiting the target page
c.Visit("https://scrapeme.live/shop/")
// scraping logic...
}
Теперь нам нужно просмотреть и проанализировать DOM целевой веб-страницы, чтобы найти данные, которые мы хотим скрейпить. В результате мы сможем применить эффективную стратегию извлечения данных.
Мы выяснили его HTML-структуру. Перед тем как начинать скрейпинг, нужно создать структуру данных для хранения скрейпнутых данных.
PokemonProduct
следующим образом:// defining a data structure to store the scraped data
type PokemonProduct struct {
url, image, name, price string
}
PokemonProduct
, который будет содержать скрейпнутые данные:// initializing the slice of structs that will contain the scraped data
var pokemonProducts []PokemonProduct
В Go срезы предоставляют эффективный способ работы с последовательностями типизированных данных. Вы можете рассматривать их как нечто вроде списков.
// iterating over the list of HTML product elements
c.OnHTML("li.product", func(e *colly.HTMLElement) {
// initializing a new PokemonProduct instance
pokemonProduct := PokemonProduct{}
// scraping the data of interest
pokemonProduct.url = e.ChildAttr("a", "href")
pokemonProduct.image = e.ChildAttr("img", "src")
pokemonProduct.name = e.ChildText("h2")
pokemonProduct.price = e.ChildText(".price")
// adding the product instance with scraped data to the list of products
pokemonProducts = append(pokemonProducts, pokemonProduct)
})
Интерфейс HTMLElement
предоставляет методы ChildAttr()
и ChildText()
. Они позволяют извлекать текст соответствующего значения атрибута из дочернего объекта, идентифицированного селектором CSS. Настроив две простые функции, вы реализуете всю логику извлечения данных.
append()
для добавления нового элемента в срез захваченного элемента.Логика для экспорта скрейпнутых данных в CSV файл с использованием Go выглядит следующим образом:
// opening the CSV file
file, err := os.Create("products.csv")
if err != nil {
log.Fatalln("Failed to create output CSV file", err)
}
defer file.Close()
// initializing a file writer
writer := csv.NewWriter(file)
// defining the CSV headers
headers := []string{
"url",
"image",
"name",
"price",
}
// writing the column headers
writer.Write(headers)
// adding each Pokemon product to the CSV output file
for _, pokemonProduct := range pokemonProducts {
// converting a PokemonProduct to an array of strings
record := []string{
pokemonProduct.url,
pokemonProduct.image,
pokemonProduct.name,
pokemonProduct.price,
}
// writing a new CSV record
writer.Write(record)
}
defer writer.Flush()
Чтобы этот фрагмент работал, убедитесь, что у вас есть следующие импорты:
import (
"encoding/csv"
"log"
"os"
// ...
)
Вот полный код для scraper.go
:
package main
import (
"encoding/csv"
"log"
"os"
"github.com/gocolly/colly"
)
// initializing a data structure to keep the scraped data
type PokemonProduct struct {
url, image, name, price string
}
func main() {
// initializing the slice of structs to store the data to scrape
var pokemonProducts []PokemonProduct
// set a valid User-Agent header
c.UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
// creating a new Colly instance
c := colly.NewCollector()
// visiting the target page
c.Visit("https://scrapeme.live/shop/")
// scraping logic
c.OnHTML("li.product", func(e *colly.HTMLElement) {
pokemonProduct := PokemonProduct{}
pokemonProduct.url = e.ChildAttr("a", "href")
pokemonProduct.image = e.ChildAttr("img", "src")
pokemonProduct.name = e.ChildText("h2")
pokemonProduct.price = e.ChildText(".price")
pokemonProducts = append(pokemonProducts, pokemonProduct)
})
// opening the CSV file
file, err := os.Create("products.csv")
if err != nil {
log.Fatalln("Failed to create output CSV file", err)
}
defer file.Close()
// initializing a file writer
writer := csv.NewWriter(file)
// writing the CSV headers
headers := []string{
"url",
"image",
"name",
"price",
}
writer.Write(headers)
// writing each Pokemon product as a CSV row
for _, pokemonProduct := range pokemonProducts {
// converting a PokemonProduct to an array of strings
record := []string{
pokemonProduct.url,
pokemonProduct.image,
pokemonProduct.name,
pokemonProduct.price,
}
// adding a CSV record to the output file
writer.Write(record)
}
defer writer.Flush()
}
Запустите ваш Go скрейпер данных с:
go run scraper.go
Затем вы найдете файл products.csv
в корневом каталоге вашего проекта. Откройте его, и там будет содержаться:
В этом уроке вы:
Как видно из этого урока, веб-краулинг с Go можно выполнить с помощью нескольких строк чистого и эффективного кода.
Однако важно понимать, что извлечение данных из интернета не всегда просто. Существует множество проблем, с которыми вы можете столкнуться в процессе. Многие веб-сайты приняли анти-скрейпинг и анти-бот решения, которые могут обнаружить и заблокировать ваши скрипты для краулинга на Go.
Лучшая практика — использовать API для веб-скрейпинга, такой как Nstbrowser, совершенно бесплатное решение, которое позволяет вам обойти все анти-бот системы одним вызовом API, избавляя вас от проблем блокировки при выполнении задач по скрейпингу.