最近在学go,以前都是用python爬虫,这次试一下用go写。
和第一个程序要写hello world一样,我们来爬个豆瓣前250电影
首先上码
package main
import (
"fmt"
"goquery"
"strconv"
)
func main() {
for page := 0; page<=9; page++{
url := "https://movie.douban.com/top250?start=" + strconv.Itoa(page*25) + "&filter="
opening,_ := goquery.NewDocument(url)
ele := opening.Find("div.hd")
ele.Each(func(index int, content *goquery.Selection) {
filmname := content.Find("a").Find("span.title").Eq(0).Text()
fmt.Println(index+1+page*25,filmname)
})
}
}
结果
1 肖申克的救赎
2 霸王别姬
3 这个杀手不太冷
4 阿甘正传
5 美丽人生
6 泰坦尼克号
7 千与千寻
8 辛德勒的名单
9 盗梦空间
10 机器人总动员
....
分析
与python不同的是在go中通常使用goquery包(需下载)
opening,_ := goquery.NewDocument(url)
goquery 需要指定一个 HTML 文档才能继续后续的操作,NewDocument(url string) (*Document, error)
: 传入 URL,内部用go自带的 http.Get
获取网页。
ele := opening.Find("div.hd")
Selection有一系列类似 jQuery 的方法,Document结构体内嵌了*Selection,因此也能直接调用这些方法。主要的方法是Selection.Find(selector string),传入一个选择器,返回一个新的,匹配到的*Selection,所以能够链式调用。
ele.Each(func(index int, content *goquery.Selection) {
filmname := content.Find("a").Find("span.title").Eq(0).Text()
fmt.Println(index+1+page*25,filmname)
})
对于这种需要返回列表数据的问题,需要进行迭代操作。goquery 提供了三个用于迭代的方法,都接受一个匿名函数作为参数,我们用到了Each():
Each(f func(int, *Selection)) *Selection
: 其中函数 f
的第一个参数是当前的下标,第二个参数是当前的节点
如果一个选择器对应多个结果,例如几项的 class 是一样的,可以使用 First()
, Last()
, Eq(index int)
, Slice(start, end int)
这些方法进一步定位。
go使用fmt.Println()进行打印,这里配合迭代的索引index和页数的索引page算出电影总索引。
由于使用了goquery,代码比较简单,也可以使用一些更底层的包,不过就比较麻烦了。