golang爬虫初体验

栏目: jQuery · 发布时间: 5年前

内容简介:最近在学习golang,看网上很多人都喜欢爬豆瓣,今天我就写了一个golang版的爬虫。对于python爬虫,我很了解,什么dom树,js异步,爬虫技术栈都是没问题的。刚接触golang爬虫,今天写了一个很简单的爬虫,就是使用2个库,一个http、goquery直接上代码
golang爬虫初体验

最近在学习golang,看网上很多人都喜欢爬豆瓣,今天我就写了一个golang版的爬虫。对于 python 爬虫,我很了解,什么dom树,js异步,爬虫技术栈都是没问题的。

刚接触golang爬虫,今天写了一个很简单的爬虫,就是使用2个库,一个http、goquery

直接上代码

package main

import (
    "net/http"
    "fmt"
    "github.com/PuerkitoBio/goquery"
    "strconv"
)

func GetMovie(url string) {
    fmt.Println(url)
    resp, err := http.Get(url)
    if err != nil {
        panic(err)
    }
    //bodyString, err := ioutil.ReadAll(resp.Body)
    //fmt.Println(string(bodyString))
    if resp.StatusCode != 200 {
        fmt.Println("err")
    }

    doc, err := goquery.NewDocumentFromReader(resp.Body)
    if err != nil {
        panic(err)
    }

    //

    doc.Find("#content h1").Each(func(i int, s *goquery.Selection) {
        // name
        fmt.Println("name:" + s.ChildrenFiltered(`[property="v:itemreviewed"]`).Text())
        // year
        fmt.Println("year:" + s.ChildrenFiltered(`.year`).Text())
    })

    // #info > span:nth-child(1) > span.attrs
    director := ""
    doc.Find("#info span:nth-child(1) span.attrs").Each(func(i int, s *goquery.Selection) {
        // 导演
        director += s.Text()
        //fmt.Println(s.Text())
    })
    fmt.Println("导演:" + director)
    //fmt.Println("\n")

    pl := ""
    doc.Find("#info span:nth-child(3) span.attrs").Each(func(i int, s *goquery.Selection) {
        pl += s.Text()
    })
    fmt.Println("编剧:" + pl)

    charactor := ""
    doc.Find("#info span.actor span.attrs").Each(func(i int, s *goquery.Selection) {
        charactor += s.Text()
    })
    fmt.Println("主演:" + charactor)

    typeStr := ""
    doc.Find("#info > span:nth-child(8)").Each(func(i int, s *goquery.Selection) {
        typeStr += s.Text()
    })
    fmt.Println("类型:" + typeStr)
}

func GetToplist(url string) []string {
    var urls []string
    resp, err := http.Get(url)
    if err != nil {
        panic(err)
    }
    //bodyString, err := ioutil.ReadAll(resp.Body)
    //fmt.Println(string(bodyString))
    if resp.StatusCode != 200 {
        fmt.Println("err")
    }

    doc, err := goquery.NewDocumentFromReader(resp.Body)
    if err != nil {
        panic(err)
    }

    doc.Find("#content div div.article ol li div div.info div.hd a").Each(func(i int, s *goquery.Selection) {
        // year
        fmt.Printf("%v", s)
        herf, _ := s.Attr("href")
        urls = append(urls, herf)
    })
    return urls
}

func main() {
    url := "https://movie.douban.com/top250?start="
    var urls []string
    var newUrl string
    fmt.Println("%v", urls)
    for i := 0; i < 10; i++ {
        start := i * 25
        newUrl = url + strconv.Itoa(start)
        urls = GetToplist(newUrl)

        for _, url := range urls {
            GetMovie(url)
        }
    }
}

以上是最简单版的,可以优化的地方还有很多,比如使用 协程,请求头,反爬虫机制等。

golang爬虫初体验

主要使用的就是 goquery这个库,当然也可以使用正则进行匹配。我是拒绝的。 我很喜欢python中的beautifulsoup。goquery类似jquery,可以直接操作dom树。goquery使用的不熟练,代码写的有很多重复,不优雅。

goquery

Go 实现了类似 jQuery 的功能,包括链式操作语法、操作和查询 HTML 文档。它基于 Go net/html 包和 CSS 选择器库 cascadia 。由于 net/html 解析器返回的是 DOM 节点,而不是完整的 DOM 树,因此,jQuery 的状态操作函数没有实现(像 height(),css(),detach())。

由于 net/html 解析器要求文档必须是 UTF-8 编码,因此 goquery 库也有此要求。如果文档不是 UTF-8 编码,使用者需要自己转换。进行编码转换,可以使用如下库:

iconv 的 Go 封装,如: github.com/djimenez/iconv-go

官方提供的 text 子仓库, text/encoding ,用于其他编码和 UTF-8 之间进行转换

除了实现和 jQuery 类似的功能外,在函数名方面,也尽量和 jQuery 保持一致,也支持链式语法。

2 goquery 提供的主要类型和方法

2.1 Document

Document 代表一个将要被操作的 HTML 文档,不过,和 jQuery 不同,它装载的是 DOM 文档的一部分。

type Document struct {
    *Selection
    Url      *url.URL
    rootNode *html.Node
}

因为 Document 中内嵌了一个 Selection 类型,因此,Document 可以直接使用 Selection 类型的方法。

有五种方法获取一个 Document 实例,分别是从一个 URL 创建、从一个 *html.Node 创建、从一个 io.Reader 创建、从一个 *http.Response 创建和从一个已有的 Document Clone 一个。

2.2 Selection

Selection 代表符合特定条件的节点集合。

type Selection struct {
    Nodes    []*html.Node
    document *Document
    prevSel  *Selection
}

一般地,得到了 Document 实例后,通过 Dcoument.Find 方法获取一个 Selection 实例,然后像 jQuery 一样使用链式语法和方法操作它。

Selection 类型提供的方法可以分为如下几大类(注意,3个点(…)表示有重载的方法):

1)类似函数的位置操作

– Eq()  – First()  – Get()  – Index…()  – Last()  – Slice()

2)扩大 Selection 集合(增加选择的节点)

– Add…()  – AndSelf()  – Union(), which is an alias for AddSelection()

3)过滤方法,减少节点集合

– End()  – Filter…()  – Has…()  – Intersection(), which is an alias of FilterSelection()  – Not…()

4)循环遍历选择的节点

– Each()  – EachWithBreak()  – Map()

5)修改文档

– After…()  – Append…()  – Before…()  – Clone()  – Empty()  – Prepend…()  – Remove…()  – ReplaceWith…()  – Unwrap()  – Wrap…()  – WrapAll…()  – WrapInner…()

6)检测或获取节点属性值

– Attr(), RemoveAttr(), SetAttr()  – AddClass(), HasClass(), RemoveClass(), ToggleClass()  – Html()  – Length()  – Size(), which is an alias for Length()  – Text()

7)查询或显示一个节点的身份

– Contains()  – Is…()

8)在文档树之间来回跳转(常用的查找节点方法)

– Children…()  – Contents()  – Find…()  – Next…()  – Parent[s]…()  – Prev…()  – Siblings…()

2.3 Matcher 接口

type Matcher interface {
    Match(*html.Node) bool
    MatchAll(*html.Node) []*html.Node
    Filter([]*html.Node) []*html.Node
}

该接口定义了一些方法,用于匹配 HTML 节点和编译过的选择器字符串。Cascadia’s Selector 实现了该接口。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Cyberwar

Cyberwar

Kathleen Hall Jamieson / Oxford University Press / 2018-10-3 / USD 16.96

The question of how Donald Trump won the 2016 election looms over his presidency. In particular, were the 78,000 voters who gave him an Electoral College victory affected by the Russian trolls and hac......一起来看看 《Cyberwar》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

MD5 加密
MD5 加密

MD5 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具