go爬虫和python爬虫_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)

}

}

}

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

主要使用的就是 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 实现了该接口。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值