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 ...
随机推荐
- 【LuoguP4482】[BJWC2018]Border 的四种求法
题目链接 题意 区间 boder \(n,q\leq 2*10^5\) Sol (暴力哈希/SA可以水过) 字符串区间询问问题,考虑用 \(SAM\) 解决. boder相当于是询问区间 \([l,r ...
- EasyLogging++学习笔记(1)—— 简要介绍
对于有开发经验的程序员来说,记录程序执行日志是一件必不可少的事情.通过查看和分析日志信息,不仅可以有效地帮助我们调试程序,而且当程序正式发布运行之后,更是可以帮助我们快速.准确地定位问题.在现在这个开 ...
- 编码问题2 utf-8和Unicode的区别
utf-8和Unicode到底有什么区别?是存储方式不同?编码方式不同?它们看起来似乎很相似,但是实际上他们并不是同一个层次的概念 要想先讲清楚他们的区别,首先应该讲讲Unicode的来由. 众所周知 ...
- atom Editor文本自动选择问题
问题:如图中,我光标最初在42行,向上滑动鼠标,会自动选中42到所滑动行之间的文本 ,一般编辑器 都是要按shift 然后滑动鼠标 才有这个效果 解决方法: 是由于atom安装了atom-termin ...
- Spring Boot系列目录
1.spring mvc 接口动态注入 FactoryBean ImportBeanDefinitionRegistrar ClassPathScanningCandidateComponentPro ...
- [Vue] : Vue实例的声明周期
vue实例的生命周期 什么是生命周期:从Vue实例创建.运行.到销毁期间,总是伴随着各种各样的事件,这些事件,统称为生命周期! 生命周期钩子:就是生命周期事件的别名而已: 生命周期钩子 = 生命周期函 ...
- Django常见命令
在Django的使用过程中需要使用命令让Django进行一些操作,例如创建Django项目,启动Django程序,创建新的APP,数据库迁移等. 1. 创建Django项目 新建一个文件夹来存放项目文 ...
- Educational Codeforces Round 64 (Rated for Div. 2) A,B,C,D,E,F
比赛链接: https://codeforces.com/contest/1156 A. Inscribed Figures 题意: 给出$n(2\leq n\leq 100)$个数,只含有1,2,3 ...
- CoreText学习(二)之Hello world
最后更新:2017-08-10 部分内容丢失,后续补上 相关配置: Xcode 8.3.3 Swift 3.0 macOS Sierra 一.CoreText 简介 CoreText 是用于处理文字和 ...
- Visual Studio Code(VS code)介绍
一.日常安利 VS code VS vode特点: 开源,免费: 自定义配置 集成git 智能提示强大 支持各种文件格式(html/jade/css/less/sass/xml) 调试功能强大 各种方 ...