内容简介:最近在学习golang,看网上很多人都喜欢爬豆瓣,今天我就写了一个golang版的爬虫。对于python爬虫,我很了解,什么dom树,js异步,爬虫技术栈都是没问题的。刚接触golang爬虫,今天写了一个很简单的爬虫,就是使用2个库,一个http、goquery直接上代码
最近在学习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 实现了该接口。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- scrapy 爬虫利器初体验(1)
- Flutter 全栈开发体验——爬虫与服务端
- 爬虫需谨慎,那些你不知道的爬虫与反爬虫套路!
- 反爬虫之字体反爬虫
- 反爬虫之字体反爬虫
- python网络爬虫之初始网络爬虫
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。