Slide 1

Slide 1 text

Colly: обзор фреймворка для веб-скрейпинга на Go Joanna Shevchuk

Slide 2

Slide 2 text

О себе • Go + Python + Linux; • Менторю Django Girls и курс PyLadies 1/22

Slide 3

Slide 3 text

Веб-скрейпинг извлечение данных из веб-страниц для последующей структуризации. 2/22

Slide 4

Slide 4 text

API Программный интерфейс приложения описание способов, помогающих одной программе взаимодействовать с другой. Есть API - используем API. Нет API - используем скрейпер. 3/22

Slide 5

Slide 5 text

robots.txt наш_сайт/robots.txt User-agent: * Disallow: / (скрейпить нельзя помиловать **) 4/22

Slide 6

Slide 6 text

Colly: Fast and Elegant Scraping Framework for Gophers 5/22

Slide 7

Slide 7 text

Преимущества • Толковый API и подробная документация; • Много плюшек; • На Go = привычнее; • Конкурентность. 6/22

Slide 8

Slide 8 text

О плюшках: • Скрейпит синхронно/асинхронно/параллельно; • Автоматически кодирует не-Юникодные символы; • Сам вычищает cookies; • Обрабатывает robots.txt; • Можно прикрутить БД: SQLite или MongoDB; 7/22

Slide 9

Slide 9 text

Недостатки • Нет встроенного headless-браузера; Headless browser браузер без графического интерфейса (работает через командную строку). 8/22

Slide 10

Slide 10 text

func main() { c := colly.NewCollector() c.OnHTML("a[href]", func(e *colly.HTMLElement) { e.Request.Visit(e.Attr("href")) }) c.OnRequest(func(r *colly.Request) { fmt.Println("Visiting", r.URL) }) c.Visit("http://go-colly.org/") } 9/22

Slide 11

Slide 11 text

type Collector struct { UserAgent string MaxDepth int AllowedDomains []string DisallowedDomains []string DisallowedURLFilters []*regexp.Regexp URLFilters []*regexp.Regexp AllowURLRevisit bool MaxBodySize int CacheDir string IgnoreRobotsTxt bool Async bool ParseHTTPErrorResponse bool ID uint32 DetectCharset bool RedirectHandler func(req *http.Request, via []*http.Request) error CheckHead bool } 10/22

Slide 12

Slide 12 text

User Agent как концепция приложение, через определенный сетевой протокол обеспечивающее доступ к веб-контенту (например, браузер или скрейпер). как элемент строка, содержащая сведения о браузере или скрейпере: название, версия, платформа (ОС), движок. 11/22

Slide 13

Slide 13 text

Скрейпим статический сайт package main import ( "encoding/csv" "log" "os" "github.com/gocolly/colly" ) func main() { fName := "xkcd_store_items.csv" file, err := os.Create(fName) if err != nil { log.Fatalf("Cannot create file %q: %s\n", fName, err) return } 12/22

Slide 14

Slide 14 text

... defer file.Close() writer := csv.NewWriter(file) defer writer.Flush() writer.Write([]string{"Name", "Price", "URL", "Image URL"}) c := colly.NewCollector( colly.AllowedDomains("store.xkcd.com"), ) ... 13/22

Slide 15

Slide 15 text

... c.OnHTML(‘.next a[href]‘, func(e *colly.HTMLElement) { e.Request.Visit(e.Attr("href")) }) c.Visit("https://store.xkcd.com/collections/everything") log.Printf("Scraping finished, check file %q for results\n", fName) log.Println(c) } 14/22

Slide 16

Slide 16 text

Скрейпим динамический сайт (не через родной API) Instagram Под капотом есть goquery. • Исходный код страницы • Ищем переменную window._sharedData 15/22

Slide 17

Slide 17 text

c := colly.NewCollector() c.OnHTML("body > script:first-of-type", func(e *colly.HTMLElement ) { jsonData := e.Text[strings.Index(e.Text, "{") : len(e.Text) -1] 16/22

Slide 18

Slide 18 text

data := struct { EntryData struct { ProfilePage []struct { User struct { Id string ‘json:"id"‘ Media struct { Nodes []struct { ImageURL string ‘json:"display_src "‘ ThumbnailURL string ‘json:" thumbnail_src"‘ IsVideo bool ‘json:"is_video"‘ Date int ‘json:"date"‘ Dimensions struct { Width int ‘json:"width"‘ Height int ‘json:"height"‘ } } ... 17/22

Slide 19

Slide 19 text

... PageInfo pageInfo ‘json:"page_info"‘ } ‘json:"media"‘ } ‘json:"user"‘ } ‘json:"ProfilePage"‘ } ‘json:"entry_data"‘ }{} err := json.Unmarshal([]byte(jsonData), &data) if err != nil { log.Fatal(err) } 18/22

Slide 20

Slide 20 text

page := data.EntryData.ProfilePage[0] actualUserId = page.User.Id for _, obj := range page.User.Media.Nodes { if obj.IsVideo { continue } c.Visit(obj.ImageURL) } } 19/22

Slide 21

Slide 21 text

const nextPageURLTemplate string = ‘https://www.instagram.com/ graphql/query/?query_id=17888483320059182&variables={"id":"%s ","first":12,"after":"%s"}‘ //... c.OnResponse(func(r *colly.Response) { if strings.Index(r.Headers.Get("Content-Type"), "image") > -1 { r.Save(outputDir + r.FileName()) return } } 20/22

Slide 22

Slide 22 text

http://go-colly.org/ https://github.com/gocolly/colly https://godoc.org/github.com/gocolly/colly https://godoc.org/github.com/gocolly/colly/extensions 21/22

Slide 23

Slide 23 text

Мои контакты djeanne joannashevchuk ƻ djeanne djeanne.github.io joanne.shevchuk@gmail.com djeanne@pm.me 22/22