Golang 爬虫系列一 goquery
主要参考原文在https://www.jianshu.com/p/ae172d60c431
主要想练习一下goquery,首先是实践一把 使用goquery爬取豆瓣电影top250
从原文最后复制代码,编译运行。输入一堆err
调试了一下,返回Http错误代码418,应该是反爬虫了。
好吧,我们不应增加服务器的负担,但也不应该逼着我们每次用自己的眼球看吧,用程序读网页又怎么啦!
于是,把程序中的循环去掉,只读取第一页,并增加请求头试试。
package main import ( "fmt" "net/http" "github.com/PuerkitoBio/goquery" ) func GetMovie(url string) { fmt.Println(url) //new 一个 request,再设置其header req, _ := http.NewRequest("GET", url, nil) // 设置 req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.1;WOW64) AppleWebKit/537.36 (KHTML,like GeCKO) Chrome/45.0.2454.85 Safari/537.36 115Broswer/6.0.3") req.Header.Set("Referer", "https://movie.douban.com/") req.Header.Set("Connection", "keep-alive") resp, err := (&http.Client{}).Do(req) 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 //new 一个 request,再设置其header req, _ := http.NewRequest("GET", url, nil) // 设置 req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.1;WOW64) AppleWebKit/537.36 (KHTML,like GeCKO) Chrome/45.0.2454.85 Safari/537.36 115Broswer/6.0.3") req.Header.Set("Referer", "https://movie.douban.com/") req.Header.Set("Connection", "keep-alive") resp, err := (&http.Client{}).Do(req) if err != nil { panic(err) } fmt.Println("===============================================================", resp.StatusCode) //bodyString, err := ioutil.ReadAll(resp.Body) //fmt.Println(string(bodyString)) if resp.StatusCode != 200 { fmt.Println("//////////////////////////////////////", resp.StatusCode) } 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=0" var urls []string urls = GetToplist(url) fmt.Println("%v", urls) for _, url := range urls { GetMovie(url) } }
感谢开放的豆瓣,憎恶搞封闭的互联网霸权!成功读取到了所需要的信息!
下面正式进入goquery正题,这部分主要参考https://www.flysnow.org/2018/01/20/golang-goquery-examples-selector.html
1、基于HTML Element 元素的选择器
这个比较简单,就是基于a
,p
等这些HTML的基本元素进行选择,这种直接使用Element名称作为选择器即可。比如dom.Find("div")
。
func main() { html := `<body> <div>DIV1</div> <div>DIV2</div> <span>SPAN</span> </body> ` dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html)) if err!=nil{ log.Fatalln(err) } dom.Find("div").Each(func(i int, selection *goquery.Selection) { fmt.Println(selection.Text()) }) }
以上示例,可以把div
元素筛选出来,而body
,span
并不会被筛选。
2、ID 选择器
这个是使用频次最多的,类似于上面的例子,有两个div
元素,其实我们只需要其中的一个,那么我们只需要给这个标记一个唯一的id
即可,这样我们就可以使用id
选择器,精确定位了。
func main() { html := `<body> <div id="div1">DIV1</div> <div>DIV2</div> <span>SPAN</span> </body> ` dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html)) if err!=nil{ log.Fatalln(err) } dom.Find("#div1").Each(func(i int, selection *goquery.Selection) { fmt.Println(selection.Text()) }) }
id
选择器以#
开头,紧跟着元素id
的值,使用语法为dom.Find(#id)
,后面的例子我会简写为Find(#id)
,大家知道这是代表goquery选择器的即可。
3、Element ID 选择器
如果有相同的ID,但是它们又分别属于不同的HTML元素怎么办?有好办法,和Element结合起来。比如我们筛选元素为div
,并且id
是div1
的元素,就可以使用Find(div#div1)
这样的筛选器进行筛选。
所以这类筛选器的语法为Find(element#id)
,这是常用的组合方法,比如后面讲的过滤器也可以采用这种方式组合使用。
其他选择器不想写了,大家可参考原文。但我想应该可以直接从chromer开发工具中copy 相应的selector
其他参考:
https://www.cnblogs.com/winterbear/p/12263886.html
https://www.cnblogs.com/mingbai/p/goHttpReq.html