go爬虫系列
一、go语言爬取豆瓣电影top250
package main
import (
"net/http"
"io/ioutil"
"os"
"fmt"
"strconv"
"regexp"
"time"
)
//定义新的数据类型
type Spider struct {
url string
header map[string]string
}
//定义 Spider get的方法
func (keyword Spider) get_html_header() string {
client := &http.Client{}
req, err := http.NewRequest("GET", keyword.url, nil)
if err != nil {
}
for key, value := range keyword.header {
req.Header.Add(key, value)
}
resp, err := client.Do(req)
if err != nil {
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
}
return string(body)
}
func parse() {
header := map[string]string{
"Host": "movie.douban.com",
"Connection": "keep-alive",
"Cache-Control": "max-age=0",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Referer": "https://movie.douban.com/top250",
}
//创建excel文件
f, err := os.Create("spider.txt")
if err != nil {
panic(err)
}
defer f.Close()
//写入标题
f.WriteString("电影名称"+"\t"+"评分"+"\t"+"评价人数"+"\t"+"\r\n")
//循环每页解析并把结果写入excel
for i:=0;i<10;i++{
fmt.Println("正在抓取第"+strconv.Itoa(i)+"页......")
url:="https://movie.douban.com/top250?start="+strconv.Itoa(i*25)+"&filter="
spider := &Spider{url, header}
html := spider.get_html_header()
//评价人数
pattern2:=`<span>(.*?)评价</span>`
rp2 := regexp.MustCompile(pattern2)
find_txt2 := rp2.FindAllStringSubmatch(html,-1)
//评分
pattern3:=`property="v:average">(.*?)</span>`
rp3 := regexp.MustCompile(pattern3)
find_txt3 := rp3.FindAllStringSubmatch(html,-1)
//电影名称
pattern4:=`alt="(.*?)" src="`
rp4 := regexp.MustCompile(pattern4)
find_txt4 := rp4.FindAllStringSubmatch(html,-1)
// 写入UTF-8 BOM
f.WriteString("\xEF\xBB\xBF")
// 打印全部数据和写入excel文件
for i:=0;i<len(find_txt2);i++{
fmt.Printf("%s %s %s\n",find_txt4[i][1],find_txt3[i][1],find_txt2[i][1], )
f.WriteString(find_txt4[i][1]+"\t"+find_txt3[i][1]+"\t"+find_txt2[i][1]+"\t"+"\r\n")
}
}
}
func main() {
t1 := time.Now() // get current time
parse()
elapsed := time.Since(t1)
fmt.Println("爬虫结束,总共耗时: ", elapsed)
}
二、goquery
上面第一部分的例子,使用了正则表达式来匹配,使用goquery会更方便。goquery是一个使用go语言写成的HTML解析库,可以让你像jQuery那样的方式来操作DOM文档。
获取代码:
gopm get -g github.com/PuerkitoBio/goquery
直接使用go get方式安装失败,这里使用了gopm来安装,关于gopm可以参考国内的go get问题的解决 --gopm
在代码中引用时:
import “github.com/PuerkitoBio/goquery”
以下参考golang goquery selector(选择器) 示例大全
如果大家以前做过前端开发,对jquery不会陌生,goquery类似jquery,它是jquery的go版本实现。使用它,可以很方便的对HTML进行处理。
- 基于HTML Element元素的选择器
这个比较简单,就是基于a,p等这些HTML的基本元素进行选择,这种直接使用Element名称作为选择器即可。比如dom.Find("div")。
func findDiv() {
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("i",i,"select text",selection.Text())
})
}
- 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())
})
}
- Element ID选择器
id选择器以#开头,紧跟着元素id的值,使用语法为dom.Find(#id),后面的例子我会简写为Find(#id),大家知道这是代表goquery选择器的即可。
如果有相同的ID,但是它们又分别属于不同的HTML元素怎么办?有好办法,和Element结合起来。比如我们筛选元素为div,并且id是div1的元素,就可以使用Find(div#div1)这样的筛选器进行筛选。
所以这类筛选器的语法为Find(element#id),这是常用的组合方法,比如后面讲的过滤器也可以采用这种方式组合使用。
4. Class选择器
class也是HTML中常用的属性,我们可以通过class选择器来快速的筛选需要的HTML元素,它的用法和ID选择器类似,为Find(".class")。
func main() {
html := `<body>
<div id="div1">DIV1</div>
<div class="name">DIV2</div>
<span>SPAN</span>
</body>
`
dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html))
if err!=nil{
log.Fatalln(err)
}
dom.Find(".name").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Text())
})
}
以上示例中,就筛选出来class为name的这个div元素。
5. Element Class 选择器
class选择器和id选择器一样,也可以结合着HTML元素使用,他们的语法也类似Find(element.class),这样就可以筛选特定element、并且指定class的元素。
三、使用goquery爬取豆瓣电影top250
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)
}
}
}
注意这个Find:doc.Find("#content div div.article ol li div div.info div.hd a")
,参考返回的html内容,这里是个多层查找,#是查找id,带点的是找相应的class。当然改成doc.Find("ol.grid_view li div.hd a")
也是可以的。最终都是要找列表里的li,然后挑出href。
go爬虫系列的更多相关文章
- java爬虫系列第一讲-爬虫入门
1. 概述 java爬虫系列包含哪些内容? java爬虫框架webmgic入门 使用webmgic爬取 http://ady01.com 中的电影资源(动作电影列表页.电影下载地址等信息) 使用web ...
- java爬虫系列目录
1. java爬虫系列第一讲-爬虫入门(爬取动作片列表) 2. java爬虫系列第二讲-爬取最新动作电影<海王>迅雷下载地址 3. java爬虫系列第三讲-获取页面中绝对路径的各种方法 4 ...
- java爬虫系列第二讲-爬取最新动作电影《海王》迅雷下载地址
1. 目标 使用webmagic爬取动作电影列表信息 爬取电影<海王>详细信息[电影名称.电影迅雷下载地址列表] 2. 爬取最新动作片列表 获取电影列表页面数据来源地址 访问http:// ...
- Python3爬虫系列:理论+实验+爬取妹子图实战
Github: https://github.com/wangy8961/python3-concurrency-pics-02 ,欢迎star 爬虫系列: (1) 理论 Python3爬虫系列01 ...
- 爬虫系列4:Requests+Xpath 爬取动态数据
爬虫系列4:Requests+Xpath 爬取动态数据 [抓取]:参考前文 爬虫系列1:https://www.cnblogs.com/yizhiamumu/p/9451093.html [分页]:参 ...
- 爬虫系列3:Requests+Xpath 爬取租房网站信息并保存本地
数据保存本地 [抓取]:参考前文 爬虫系列1:https://www.cnblogs.com/yizhiamumu/p/9451093.html [分页]:参考前文 爬虫系列2:https://www ...
- 爬虫系列2:Requests+Xpath 爬取租房网站信息
Requests+Xpath 爬取租房网站信息 [抓取]:参考前文 爬虫系列1:https://www.cnblogs.com/yizhiamumu/p/9451093.html [分页]:参考前文 ...
- 爬虫系列1:Requests+Xpath 爬取豆瓣电影TOP
爬虫1:Requests+Xpath 爬取豆瓣电影TOP [抓取]:参考前文 爬虫系列1:https://www.cnblogs.com/yizhiamumu/p/9451093.html [分页]: ...
- python 全栈开发,Day134(爬虫系列之第1章-requests模块)
一.爬虫系列之第1章-requests模块 爬虫简介 概述 近年来,随着网络应用的逐渐扩展和深入,如何高效的获取网上数据成为了无数公司和个人的追求,在大数据时代,谁掌握了更多的数据,谁就可以获得更高的 ...
- 爬虫系列1:python简易爬虫分析
决定写一个小的爬虫系列,本文是第一篇,讲爬虫的基本原理和简易示例. 1.单个网页的简易爬虫 以下爬虫的主要功能是爬取百度贴吧中某一页面的所有图片.代码由主要有两个函数:其中getHtml()通过页面u ...
随机推荐
- java中volatile关键字的含义(转载)
在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉. Java语言是支持多线程的,为了解决线程并发的问题,在语 ...
- 关于properties文件的读取(Java/spring/springmvc/springboot)
一.Java读取properties文件 1.基于ClassLoder读取配置文件 注意:该方式只能读取类路径下的配置文件,有局限但是如果配置文件在类路径下比较方便. Properties prope ...
- PHP mysqli_query() 函数
PHP mysqli_query() 函数 定义和用法 mysqli_query() 函数执行某个针对数据库的查询. mysqli_query(connection,query,resultmode) ...
- 快速弄清JavaScript中undefined和null的区别
ES6的7大数据类型里面有这俩玩意:undefined和null,让接触不深的学习者常常产生混淆,这俩玩意的区别在哪呢? 字面意思上来看,undefined是未(被我们)阐明的,未说明的,null则意 ...
- hdu 1023 hdu 1131
How Many Trees? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Tot ...
- 【luogu4781】拉格朗日插值
题目背景 这是一道模板题 题目描述 由小学知识可知,nn个点(x_i,y_i)(xi,yi)可以唯一地确定一个多项式 现在,给定nn个点,请你确定这个多项式,并将kk代入求值 求出的值对99824 ...
- Jenkins忘记admin密码补救措施
遇到将Jenkins登录名密码忘记的情况,下面的方式可以重置密码. 进入C:\Program Files (x86)\Jenkins\users 目录可以看到admin开头的文件夹,里面有个confi ...
- CDialog::DoModal()问题和_WIN32_WINNT
1.从CDialogEx派生自己的CMyDialog,到DoModal()时总提示 error C2039: "DoModal": 不是"CMyDialog"的 ...
- 虚拟机扩展Linux根目录磁盘空间
简要扩展空间方法http://www.kwx.gd/CentOSApp/Xen-Centos6-Mounted-HardDrive.html 最近在VMware虚拟机上使用Centos,用着用着,发现 ...
- Error creating bean with name 'persistenceExceptionTranslationPostProcessor' defined in class path resource [org/springframework/boot/autoconfigure/dao/PersistenceExceptionTranslationAutoConfiguration
dubbo 包和SpringBoot 冲突,注释就可以正常启动