Web Scraping с Golang и goQuery

Web Scraping с Golang и goQuery

Web scraping это обработка HTML кода веб-страницы и выборка необходимых элементов из неё. На этом принципе построены поисковые системы, такие как Google. Они заходят на все страницы, которые найдут, и копируют их себе.

Проверьте, что у вас установлен go и настроена переменная $GOPATH.

Разбор страницы с goQuery

goQuery это почти то же самое, что jQuery, только для go. Она предоставляет удобный доступ к HTML-структуре страницы и позволяет оперировать её элементами и содержимым. Если сравнивать их функции, то здесь также, как в jQuery есть .Text() для строкового содержимого и .Attr() или .AttrOr() для значений атрибутов.

Чтобы начать работать с goQuery, наберите в консоли:

go get github.com/PuerkitoBio/goquery

Сбор ссылок на странице с golang и goQuery

Создадим тестовый проект:

# проверим, что $GOPATH настроена
echo $GOPATH
/home/jonathan/projects/go
# перейдём в папку `src`
cd $GOPATH/src
# создадим папку
mkdir tutorial-web-scraping
# перейдём в неё
cd tutorial-web-scraping

Теперь мы можем создать несколько примеров. Вообще не принято создавать несколько функций main() в одной директории, но мы сделаем для этого примера исключение — мы же новички, верно? 🙂

Список постов на странице блога

Эта программа выведет список статей с главной страницы моего блога, взяв название поста и ссылку на него.

// файл: list_posts.go
package main

import (
// импортируем стандартные библиотеки
"fmt"
"log"

// импортируем сторонние библиотеки
"github.com/PuerkitoBio/goquery"
)

func postScrape() {
doc, err := goquery.NewDocument("http://jonathanmh.com")
if err != nil {
log.Fatal(err)
}

// используем CSS селекторы, найденные инспектором в браузере
// для каждого используем индекс и элемент
doc.Find("#main article .entry-title").Each(func(index int, item *goquery.Selection) {
title := item.Text()
linkTag := item.Find("a")
link, _ := linkTag.Attr("href")
fmt.Printf("Post #{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}d: {33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}s - {33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}s\n", index, title, link)
})
}

func main() {
postScrape()
}

Вывод этой программы будет примерно таким:

$ go run list_posts.go
Post #0: How to use SSH keys for Authentication (for beginners) - http://jonathanmh.com/how-to-use-ssh-keys-for-authentication-for-beginners/
Post #1: Using Sourcegraph Checkup with local file system storage - http://jonathanmh.com/using-sourcegraph-checkup-local-file-system-storage/
Post #2: Copenhagen Pride 2016 Photos - http://jonathanmh.com/copenhagen-pride-2016-photos/
Post #3: Searching the Google Books API with PHP [Quickstart] - http://jonathanmh.com/searching-google-books-api-php-quickstart/
Post #4: How to get a high score on Pagespeed Insights (and make your site fast) - http://jonathanmh.com/get-high-score-pagespeed-insights-make-site-fast/
Post #5: NGINX / Apache: Block Requests to PHP file (xmlrpc.php) - http://jonathanmh.com/nginx-apache-block-requests-php-file-xmlrpc-php/
Post #6: Distortion Copenhagen 2016 – Nørrebro / Wednesday - http://jonathanmh.com/distortion-copenhagen-2016-norrebro-wednesday/
Post #7: I need feminism because: Metal T-shirts - http://jonathanmh.com/need-feminism-metal-t-shirts/
Post #8: On Being Powerless - http://jonathanmh.com/on-being-powerless/
Post #9: How to get a Job in Tech - http://jonathanmh.com/get-job-tech/

Соберём все ссылки со страницы

Собрать все ссылки со страницы не намного сложнее, просто нужно использовать более широкий селектор, body a и обойти все найденные ссылки. Получить содержимое тега <а> можно с помощью linkText := linkTag.Text().

// файл: get_all_links.go
package main

import (
"fmt"
"log"

"github.com/PuerkitoBio/goquery"
)

func linkScrape() {
doc, err := goquery.NewDocument("http://jonathanmh.com")
if err != nil {
log.Fatal(err)
}

doc.Find("body a").Each(func(index int, item *goquery.Selection) {
linkTag := item
link, _ := linkTag.Attr("href")
linkText := linkTag.Text()
fmt.Printf("Link #{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}d: '{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}s' - '{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}s'\n", index, linkText, link)
})
}

func main() {
linkScrape()
}

Вывод будет примерно таким:

$ go run get_all_links.go
Link #0: 'Skip to content' - '#content'
Link #1: 'JonathanMH' - 'http://jonathanmh.com/'
Link #2: 'twitter' - 'https://twitter.com/JonathanMH_com'
Link #3: 'rss feed' - 'http://jonathanmh.com/feed/'
... (many more)
Link #172: 'Proudly powered by WordPress' - 'https://wordpress.org/'

Теперь мы знаем, как получить все ссылки со страницы, включая даже их текст!

Получаем название страницы и метаданные

// файл: metadata.go
package main

import (
"fmt"
"log"

"github.com/PuerkitoBio/goquery"
)

func metaScrape() {
doc, err := goquery.NewDocument("http://jonathanmh.com")
if err != nil {
log.Fatal(err)
}

var metaDescription string
var pageTitle string

pageTitle = doc.Find("title").Contents().Text()

doc.Find("meta").Each(func(index int, item *goquery.Selection) {
if( item.AttrOr("name","") == "description") {
metaDescription = item.AttrOr("content", "")
}
})
fmt.Printf("Page Title: '{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}s'\n", pageTitle)
fmt.Printf("Meta Description: '{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}s'\n", metaDescription)
}

func main() {
metaScrape()
}

И получим:

Page Title: 'JonathanMH - Just a guy, usually in Denmark, blogging about things he couldn't get to work right away and then made a blog post in case others get stuck too.'
Meta Description: 'JonathanMH Coder, Blogger, Videographer, Webguy, Just a guy, usually in Denmark, blogging about things he couldn't get to work right away and then made a blog post in case others get stuck too.'

В этом примере мы используем AtrrOr( value, fallback_value) для того, чтобы точно знать, что получим данные. Это намного проще написания дополнительных проверок содержимого.

Вы используете web scraping? Если у вас есть вопросы / дополнения по теме, напишите о них в комментариях!

По материалам: Web Scraping with Golang and goQuery

1 thought on “Web Scraping с Golang и goQuery

  1. А возможно ли как-нибудь программно нажать кнопку на сайте которые парсим? Кнопка вызывает событие js для начала загрузки.

Leave a Comment