Projeto rastreador de combate de linguagem Go

Como quero construir um sistema rastreador, uso python, mas finalmente descobri que a eficiência é muito baixa. Acontece que conheci um deus Go. Ele sugeriu que Go experimentasse. O efeito não é ruim, então acrescentei algumas informações !

Colly e Goquery na estrutura do rastreador Go

As estruturas do rastreador Python incluem principalmente solicitações, urllib, pyquery, scrapy, etc., e as bibliotecas de análise incluem BeautifulSoup, pyquery, Scrapy e lxml etc. A estrutura do rastreador baseado em Go é relativamente robusta, especialmente Colly e Goquery são ferramentas relativamente poderosas e flexível Sexo e expressividade são excelentes.

Web Crawler

O que é um rastreador da web? Basicamente, um rastreador da web funciona verificando o conteúdo HTML de uma página da web e executando certos tipos de ações com base no conteúdo. Normalmente, rastreando links expostos, os rastreadores seguem a fila para rastrear. Também podemos salvar a extração de dados da página atual. Por exemplo, se começarmos em uma página da Wikipedia, podemos salvar o texto e o título da página.

Algoritmo simples para rastreadores

initialize Queue
enqueue SeedURL

while Queue is not empty:
    URL = Pop element from Queue
    Page = Visit(URL)
    Links = ExtractLinks(Page)
    Enqueue Links on Queue
12345678

As funções Visit e ExtractLinks são as mudanças, e a aplicação das duas funções é específica. Nosso rastreador tentará explicar todo o mapa da web, assim como o google, ou tão simples quanto a Wikipedia.

Conforme os casos de uso que você usa aumentam, muitas coisas se tornam complicadas, muitas páginas serão rastreadas, você pode precisar de um rastreador mais sofisticado para ser executado ao mesmo tempo; para páginas mais complexas, você precisa de um intérprete de HTML mais poderoso.

Colly

Colly é uma estrutura de crawler flexível baseada na linguagem Go. Fora da caixa, você obterá alguma limitação de taxa, crawling paralelo e outro suporte.
Um dos componentes básicos do Colly é o Collector, que controla as páginas que precisam ser rastreadas e mantém os retornos de chamada quando a página é rastreada.

Um, comece

É fácil criar um Coletor, mas temos muitas opções que podemos usar.

1

2

3

4

5

6

7

8

9

c := colly.NewCollector(

    // Restrict crawling to specific domains

    colly.AllowedDomains("godoc.org"),

    // Allow visiting the same page multiple times

    colly.AllowURLRevisit(),

    // Allow crawling to be done in parallel / async

    colly.Async(true),

)

12345678

Você pode apenas copiar.NewCollector () e, em seguida, adicionar esses itens opcionais você mesmo.

Também podemos usar algumas restrições especiais para fazer nosso rastreador se comportar como um cidadão da Internet bem-comportado.É simples para Colly adicionar um limite de taxa.

1

2

3

4

5

6

7

8

9

c.Limit(&colly.LimitRule{

    // Filter domains affected by this rule

    DomainGlob:  "godoc.org/*",

    // Set a delay between requests to these domains

    Delay: 1 * time.Second

    // Add an additional random delay

    RandomDelay: 1 * time.Second,

})

12345678

  

Algumas páginas da web podem ser exigentes quanto às visitas de alto tráfego e podem desconectá-lo. Normalmente, definir um atraso de alguns segundos pode deixá-lo um pouco mais longe da lista de travessuras.

A partir daqui, podemos iniciar nosso coletor por meio de uma semente de URL.

1

c.Visit("https://godoc.org")

Dois, OnHTML

Temos um bom coletor que pode começar a trabalhar em qualquer site da Web. Agora, se quisermos que nosso coletor faça algo, ele precisa verificar a página para extrair links e outros dados.
O método colly.Collector.OnHTML permite registrar um retorno de chamada para um especificador de marca HTML específico quando o coletor atinge a parte correspondente da página. Primeiro, podemos obter um retorno de chamada quando o rastreador vê a tag [contém um link href. ] ()

1

2

3

4

5

6

7

c.OnHTML("a[href]"func(e *colly.HTMLElement) {

    // Extract the link from the anchor HTML element   

    link := e.Attr("href")

    // Tell the collector to visit the link

    c.Visit(e.Request.AbsoluteURL(link))

})

123456

Como visto acima, neste retorno de chamada você obtém um colly.HTMLElement que contém os dados do HTML correspondente.
Agora, temos o início de um rastreador da web real: encontramos as visitas de link na página e dizemos ao nosso coletor para visitar esses links em solicitações subsequentes.
OnHTML é uma ferramenta poderosa. Ele pode pesquisar por seletores CSS (ou seja, div.my_fancy_class ou #someElementId), e você pode conectar vários retornos de chamada OnHTML ao seu coletor para lidar com diferentes tipos de páginas.
A estrutura HTMLElement de Colly é muito útil. Além de usar a função Attr para obter esses atributos, você também pode extrair texto. Por exemplo, podemos querer imprimir o título da página:

1

2

3

4

c.OnHTML("title"func(e *colly.HTMLElement) {

    fmt.Println(e.Text)

})

123

三 、 OnRequest / OnResponse

有些时候你不需要一个特定的HTML元素从一个页面,而是想知道当你的爬虫检索或刚刚检索页面。为此,Colly暴露OnRequest OnResponse回调。
所有这些回调将被调用当访问到每个页面的时候。至于如何在符合OnHTML的使用要求。回调被调用的时候有一些顺序:1。OnRequest 2。OnResponse 3。OnHTML 4。OnScraped(在这边文章中没有提及到,但可能对你有用)
尤其使用的是OnRequest中止回调的能力。这可能是有用的,当你想让你的collector停止。

1

2

3

4

c.OnHTML("title"func(e *colly.HTMLElement) {

    fmt.Println(e.Text)

})

123

在OnResponse,可以访问整个HTML文档,这可能是有用的在某些情况下:

1

2

3

4

c.OnResponse(func(r *colly.Response) {

    fmt.Println(r.Body)

})

123

四、HTMLElement

除了colly.HTMLElement的Attr()方法和text,我们还可以使用它来遍历子元素。ChildText(),ChildAttr()特别是ForEach()方法非常有用。
例如,我们可以使用ChildText()获得所有段落的文本部分:

1

2

3

4

c.OnHTML("#myCoolSection"func(e *colly.HTMLElement) {

    fmt.Println(e.ChildText("p"))

})

123

我们可以使用ForEach()循环遍历一个孩子匹配一个特定的元素选择器:

1

2

3

4

5

6

7

8

c.OnHTML("#myCoolSection"func(e *colly.HTMLElement) {

    e.ForEach("p"func(_ int, elem *colly.HTMLElement) {

        if strings.Contains(elem.Text, "golang") {

            fmt.Println(elem.Text)

        }   

    })

})

1234567

五、Bringing in Goquery

Colly的内置HTMLElement对大多数抓取任务都很有用,但是如果我们想对DOM进行特别高级的遍历,我们就必须去别处寻找。 例如,(目前)没有办法将DOM遍历到父元素或通过兄弟元素横向遍历。
输入Goquery,“就像那个j-thing,只在Go中”。 它基本上是jQuery。 在Go。 (这很棒)对于你想从HTML文档中删除的任何内容,可以使用Goquery完成。
虽然Goquery是以jQuery为模型的,但我发现它在很多方面与BeautifulSoup API非常相似。 所以,如果你来自Python抓取世界,那么你可能会对Goquery感到满意。
Goquery允许我们进行比Colly的HTMLElement提供的更复杂的HTML选择和DOM遍历。 例如,我们可能想要找到我们的锚元素的兄弟元素,以获得我们已经抓取的链接的一些上下文:

1

2

3

4

5

dom, _ := qoquery.NewDocument(htmlData)

dom.Find("a").Siblings().Each(func(i int, s *goquery.Selection) {

    fmt.Printf("%d, Sibling text: %s\n", i, s.Text())

})

1234

此外,我们可以轻松找到所选元素的父级。 如果我们从Colly给出一个锚标记,并且我们想要找到页面

1

2

anchor.ParentsUntil("~").Find("title").Text()

1

ParentsUntil遍历DOM,直到找到与传递的选择器匹配的东西。 我们可以使用〜遍历DOM的顶部,然后允许我们轻松获取标题标记。
这实际上只是抓住了Goquery可以做的事情。 到目前为止,我们已经看到了DOM遍历的示例,但Goquery也对DOM操作提供了强大的支持 - 编辑文本,添加/删除类或属性,插入/删除HTML元素等。
将它带回网络抓取,我们如何将Goquery与Colly一起使用? 它很简单:每个Colly HTMLElement都包含一个Goquery选项,您可以通过DOM属性访问它。

1

2

3

4

5

6

7

8

c.OnHTML("div"func(e *colly.HTMLElement) {

    // Goquery selection of the HTMLElement is in e.DOM

    goquerySelection := e.DOM

 

    // Example Goquery usage

    fmt.Println(qoquerySelection.Find(" span").Children().Text())

})

1234567

值得注意的是,大多数抓取任务都可以以不需要使用Goquery的方式构建! 只需为html添加一个OnHTML回调,就可以通过这种方式访问整个页面。 但是,我仍然发现Goquery是我的DOM遍历工具带的一个很好的补充。

实战项目

1. metalsucks专辑评论排名信息

  • 代码

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

// go get github.com/PuerkitoBio/goquery

// git clone  https://github.com/golang/net

 

package main

 

import (

  "fmt"

  "log"

  "net/http"

 

  "github.com/PuerkitoBio/goquery"

)

 

func main() {

  // 请求html页面

  res, err := http.Get("http://metalsucks.net")

  if err != nil {

      // 错误处理

      log.Fatal(err)

  }

  defer res.Body.Close()

  if res.StatusCode != 200 {

      log.Fatalf("status code error: %d %s", res.StatusCode, res.Status)

  }

  // 加载 HTML document对象

  doc, err := goquery.NewDocumentFromReader(res.Body)

  if err != nil {

      log.Fatal(err)

  }

  // Find the review items

  doc.Find(".sidebar-reviews article .content-block").Each(func(i int, s *goquery.Selection) {

      // For each item found, get the band and title

      band := s.Find("a").Text()

      title := s.Find("i").Text()

      fmt.Printf("Review %d: %s - %s\n", i, band, title)

  })

}

  • 输出

    Review 0: Darkthrone - Old Star
    Review 1: Baroness - Gold & Grey
    Review 2: Death Angel - Humanicide
    Review 3: Devin Townsend - Empath
    Review 4: Whitechapel - The Valley
    

2. emojipedia表情抓取(colly + goquery)

  • 代码

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

61

package main

 

import (

  "fmt"

  "strings"

  "time"

 

  "github.com/PuerkitoBio/goquery"

  "github.com/gocolly/colly"

)

 

func main() {

  c := colly.NewCollector(

      colly.AllowedDomains("emojipedia.org"),

  )

 

  // Callback for when a scraped page contains an article element

  c.OnHTML("article"func(e *colly.HTMLElement) {

      isEmojiPage := false

  // Extract meta tags from the document

  metaTags := e.DOM.ParentsUntil("~").Find("meta")

  metaTags.Each(func(_ int, s *goquery.Selection) {

      // Search for og:type meta tags

      property, _ := s.Attr("property")

      if strings.EqualFold(property, "og:type") {

          content, _ := s.Attr("content")

 

          // Emoji pages have "article" as their og:type

          isEmojiPage = strings.EqualFold(content, "article")

      }

  })

 

  if isEmojiPage {

      // Find the emoji page title

      fmt.Println("Emoji: ", e.DOM.Find("h1").Text())

      // Grab all the text from the emoji's description

      fmt.Println(

          "Description: ",

          e.DOM.Find(".description").Find("p").Text())

  }

  })

 

  // Callback for links on scraped pages

  c.OnHTML("a[href]"func(e *colly.HTMLElement) {

      // Extract the linked URL from the anchor tag

      link := e.Attr("href")

      // Have our crawler visit the linked URL

      c.Visit(e.Request.AbsoluteURL(link))

  })

 

  c.Limit(&colly.LimitRule{

      DomainGlob:  "*",

      RandomDelay: 1 * time.Second,

  })

 

  c.OnRequest(func(r *colly.Request) {

      fmt.Println("Visiting", r.URL.String())

  })

 

  c.Visit("https://emojipedia.org")

}

  • 运行结果

3.校花网图片爬取

  • 代码

 

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

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

// 知识点

// 1. http 的用法,返回数据的格式、编码

// 2. 正则表达式

// 3. 文件读写

package main

 

import (

    "bytes"

    "fmt"

    "io/ioutil"

    "net/http"

    "os"

    "path/filepath"

    "regexp"

    "strings"

    "sync"

    "time"

 

    "github.com/axgle/mahonia"

)

 

var workResultLock sync.WaitGroup

 

func check(e error) {

    if e != nil {

        panic(e)

    }

}

 

func ConvertToString(src string, srcCode string, tagCode string) string {

    srcCoder := mahonia.NewDecoder(srcCode)

    srcResult := srcCoder.ConvertString(src)

    tagCoder := mahonia.NewDecoder(tagCode)

    _, cdata, _ := tagCoder.Translate([]byte(srcResult), true)

    result := string(cdata)

    return result

}

 

func download_img(request_url string, name string, dir_path string) {

    image, err := http.Get(request_url)

    check(err)

    image_byte, err := ioutil.ReadAll(image.Body)

    defer image.Body.Close()

    file_path := filepath.Join(dir_path, name+".jpg")

    err = ioutil.WriteFile(file_path, image_byte, 0644)

    check(err)

    fmt.Println(request_url + "\t下载成功")

}

 

func spider(i int, dir_path string) {

    defer workResultLock.Done()

    url := fmt.Sprintf("http://www.xiaohuar.com/list-1-%d.html", i)

    response, err2 := http.Get(url)

    check(err2)

    content, err3 := ioutil.ReadAll(response.Body)

    check(err3)

    defer response.Body.Close()

    html := string(content)

    html = ConvertToString(html, "gbk""utf-8")

    // fmt.Println(html)

    match := regexp.MustCompile(`<img width="210".*alt="(.*?)".*src="(.*?)" />`)

    matched_str := match.FindAllString(html, -1)

    for _, match_str := range matched_str {

        var img_url string

        name := match.FindStringSubmatch(match_str)[1]

        src := match.FindStringSubmatch(match_str)[2]

        if strings.HasPrefix(src, "http") != true {

            var buffer bytes.Buffer

            buffer.WriteString("http://www.xiaohuar.com")

            buffer.WriteString(src)

            img_url = buffer.String()

        else {

            img_url = src

        }

        download_img(img_url, name, dir_path)

    }

}

 

func main() {

    start := time.Now()

    dir := filepath.Dir(os.Args[0])

    dir_path := filepath.Join(dir, "images")

    err1 := os.MkdirAll(dir_path, os.ModePerm)

    check(err1)

    for i := 0; i < 4; i++ {

        workResultLock.Add(1)

        go spider(i, dir_path)

    }

    workResultLock.Wait()

    fmt.Println(time.Now().Sub(start))

}

 

  • 运行结果

  • 下载的图片

作者:张亚飞 
出处:https://www.cnblogs.com/zhangyafei 
gitee:https://gitee.com/zhangyafeii 
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

标签: Go之路

Acho que você gosta

Origin blog.csdn.net/hsu282/article/details/110951227
Recomendado
Clasificación