前面几篇博客主要介绍的是对于爬虫所需要的库以及相关知识点的介绍,这篇博客就是让我们练习一下真正的爬虫该怎么写。下面我主要讲两个实例,一个是b站新番的信息爬取,另一个是猫眼电影TOP100的相关信息爬取。
首先我们需要request和re模块,我采用函数结构话来写爬虫,你们可以看看,首先我们找到我们需要爬取的详情页b站新番排行榜。
我们需要爬取得信息有上面的新番排名,动漫名称,播放量,弹幕量,追番数,以及最后的综合得分。首先我们看一下网页源代码,发现信息都在源代码中。怎么看源代码我就不讲解了。我就直接开始讲怎么开始爬虫吧。
我采用函数的形式,设置相关参数,然后请求的时候就直接传递url这个参数就行啦。
import requests
from requests.exceptions import RequestException
import re
def get_page(url):
try:
response = requests.get(url)
if response.status_code == 200:
return response.text
return None
except RequestException:
return None
由于这个网站比较简单,对于请求头等参数我们不需要配置,然后我们直接调用它。
url='https://www.bilibili.com/ranking/bangumi/13/0/3'
html =get_one_page(url)
这里我就不显示返回的结果,我们发现返回的信息就是网页源代码了,现在我们需要分析了,因为每部新番在网页展示的时候,也是一种列表形式的呈现,所以我们只要找到相似的列表单元格式,就可以用正则表达式匹配。在我看了一会源代码发现:
<div class="num">1</div><div class="content"><div class="img"><a href="//bangumi.bilibili.com/anime/28006" target="_blank"><div class="lazy-img cover"><img alt="擅长捉弄的高木同学 第二季" src=""></div></a><!----></div><div class="info"><a href="//bangumi.bilibili.com/anime/28006" target="_blank" class="title">擅长捉弄的高木同学 第二季</a><div class="bangumi-info">全12话</div><div class="detail"><span class="data-box"><i class="b-icon play"></i>2890.3万</span><span class="data-box"><i class="b-icon view"></i>100.0万</span><span class="data-box"><i class="fav"></i>168.2万</span></div><div class="pts"><div>3604904</div>综合得分
</div></div><!----></div></li><li class="rank-item">
每一条新番的信息都是这样呈现的,现在我们只需要将对应正则表达式写出来就可以了,结合上篇博客,我花了一两分写的一个比较简单的刚好匹配出来,你们可以看一下:
<div class="num">(\d+).*?href="(.*?)".*?<img alt="(.*?)" src.*?</i>(.*?)</span>.*?</i>(.*?)</span>.*?</i>(.*?)</span>.*?<div>(\d+)</div>
是不是也很简单,当我们请求之后匹配正则表达式,就能得到我们想要的信息了。
pattern = re.compile('(\d+).*?href="(.*?)".*?(.*?).*?(.*?).*?(.*?).*?(\d+)', re.S)
items = re.findall(pattern, html)
items
看一下我们的运行结果:
[('1',
'//bangumi.bilibili.com/anime/28006',
'擅长捉弄的高木同学 第二季',
'2890.6万',
'100.0万',
'168.2万',
'3604904'),
('2',
'//bangumi.bilibili.com/anime/26801',
'鬼灭之刃',
'2.2亿',
'357.5万',
'496.0万',
'3518535'),
('3',
'//bangumi.bilibili.com/anime/28016',
'女高中生的虚度日常',
'3442.3万',
'73.6万',
'175.5万',
'1253146'),
('4',
'//bangumi.bilibili.com/anime/26363',
'君主·埃尔梅罗二世事件簿 魔眼收集列车 Grace note',
'3025.5万',
'41.0万',
'197.0万',
'598908'),
我只显示前四条,你们想看详细的可以自己试着运行一下。但我们发现爬取的链接地址是不完整的,这个时候,就需要我们对数据进行处理,我们看了一下源代码,发现我们爬取是没问题,只是这个网站省去了前部分公共的。https://www.bilibili.com
这个时候就需要我们处理了。
3.数据处理
举一个例子,前缀url是这个https://www.bilibili.com
,后缀url是这个//bangumi.bilibili.com/anime/26363
,我们可以用正则表达式来处理
url1 ='//bangumi.bilibili.com/anime/28016'
url2 ='https://www.bilibili.com'
url2+re.sub('//','/',url1)
处理后的结果是:
'https://www.bilibili.com/bangumi.bilibili.com/anime/28016'
这样就达到我们的要求了。
我们可以看看最后的完整代码:
import requests
from requests.exceptions import RequestException
import re
def get_page(url):
try:
response = requests.get(url)
if response.status_code == 200:
return response.text
return None
except RequestException:
return None
url='https://www.bilibili.com/ranking/bangumi/13/0/3'
html =get_page(url)
pattern = re.compile('(\d+).*?href="(.*?)".*?(.*?).*?(.*?).*?(.*?).*?(\d+)', re.S)
items = re.findall(pattern, html)
url_1 ='https://www.bilibili.com'
for item in items:
url=url_1+re.sub('//','/',item[1])
print(item[1])
print(url)
print(item[2])
print(item[3])
print(item[4])
print(item[5])
print(item[6])
我们可以看看运行结果:
1
https://www.bilibili.com/bangumi.bilibili.com/anime/28006
擅长捉弄的高木同学 第二季
2891.4万
100.0万
168.2万
3604904
2
https://www.bilibili.com/bangumi.bilibili.com/anime/26801
鬼灭之刃
2.2亿
357.6万
496.0万
3518535
3
https://www.bilibili.com/bangumi.bilibili.com/anime/28016
女高中生的虚度日常
3443.0万
73.6万
175.5万
1253146
4
https://www.bilibili.com/bangumi.bilibili.com/anime/26363
君主·埃尔梅罗二世事件簿 魔眼收集列车 Grace note
3026.0万
41.0万
197.0万
598908
5
https://www.bilibili.com/bangumi.bilibili.com/anime/27993
Dr.STONE 石纪元
3327.9万
45.1万
169.0万
550751
我发现达到我们的要求,一个基本爬虫就完成了,至于保存我后面会慢慢讲解,第一个案例就到这里了(最后小编发现自己贼傻,其实那个url不是番剧url,需要微调,后期我再修改一下)
猫眼排行的爬取
我们需要抓取的目标站点为http://maoyan.com/board/4,打开之后便可以查看到榜单信息,如图所示。
排名第一的电影是霸王别姬,页面中显示的有效信息有影片名称、主演、上映时间、上映地区、评分、图片等信息。
将网页滚动到最下方,可以发现有分页的列表,直接点击第2页,观察页面的URL和内容发生了怎样的变化,
可以发现页面的URL变成http://maoyan.com/board/4?offset=10,比之前的URL多了一个参数,那就是offset=10,而目前显示的结果是排行11-20名的电影,初步推断这是一个偏移量的参数。再点击下一页,发现页面的URL变成了http://maoyan.com/board/4?offset=20,参数offset变成了20,而显示的结果是排行21~30的电影。
由此可以总结出规律,offset代表偏移量值,如果偏移量为n,则显示的电影序号就是n+1到n+10,每页显示10个。所以,如果想获取TOP100电影,只需要分开请求10次,而10次的offset参数分别设置为0、10、20、…90即可,这样获取不同的页面之后,再用正则表达式提取出相关信息,就可以得到TOP100的所有电影信息了。
下面我们开始编写爬虫。
1. 构造请求
这个和上面b站新番排行榜是一样的,我们就不重复,直接调用,但我们需要加入一个请求头信息,不然那可能会返回403,这样运行之后,就可以成功获取首页的源代码了。获取源代码后,就需要解析页面,提取出我们想要的信息。
def get_page(url):
try:
response = requests.get(url,headers=headers)
if response.status_code == 200:
return response.text
return None
except RequestException:
return None
url = 'http://maoyan.com/board/4'
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}
2.正则提取
我们直接观察源代码分析,找到对应的规则,用正则表达式进行编写,可以看到,一部电影信息对应的源代码是一个dd节点,我们用正则表达式来提取这里面的一些电影信息。首先,需要提取它的排名信息。而它的排名信息是在class为board-index的i节点内,这里利用非贪婪匹配来提取i节点内的信息,随后需要提取电影的图片。可以看到,后面有a节点,其内部有两个img节点。经过检查后发现,第二个img节点的data-src属性是图片的链接。这里提取第二个img节点的data-src属性,再往后,需要提取电影的名称,它在后面的p节点内,class为name。所以,可以用name做一个标志位,然后进一步提取到其内a节点的正文内容,再提取主演、发布时间、评分等内容时,都是同样的原理。最后,正则表达式写为:
<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(.*?)</a>.*?star.*?>(.*?)</p>.*?releasetime.*?>(.*?)</p>.*?integer.*?>(.*?)</i>.*?fraction.*?>(.*?)</i>.*?</dd>
这样就能匹配到我们想要的信息,为了更好 的显示我们爬取的数据,我们将格式微微调整然后打印
pattern = re.compile('.*?board-index.*?>(.*?).*?data-src="(.*?)".*?name.*?a.*?>(.*?).*?star.*?>(.*?).*?releasetime.*?>(.*?).*?integer.*?>(.*?).*?fraction.*?>(.*?).*? ', re.S)
items = re.findall(pattern, html)
for item in items:
print('index', item[0])
print('image', item[1])
print('title', item[2])
print('actor', item[3].strip()[3:])
print('time', item[4].strip()[5:])
print('score', item[5]+ item[6])
打印出来的结果:
index 1
image https://p1.meituan.net/movie/20803f59291c47e1e116c11963ce019e68711.jpg@160w_220h_1e_1c
title 霸王别姬
actor 张国荣,张丰毅,巩俐
time 1993-01-01
score 9.5
index 2
image https://p0.meituan.net/movie/283292171619cdfd5b240c8fd093f1eb255670.jpg@160w_220h_1e_1c
title 肖申克的救赎
actor 蒂姆·罗宾斯,摩根·弗里曼,鲍勃·冈顿
time 1994-09-10(加拿大)
score 9.5
index 3
image https://p0.meituan.net/movie/289f98ceaa8a0ae737d3dc01cd05ab052213631.jpg@160w_220h_1e_1c
title 罗马假日
actor 格利高里·派克,奥黛丽·赫本,埃迪·艾伯特
time 1953-09-02(美国)
score 9.1
3.整合代码
最后,实现main()方法来调用前面实现的方法,将单页的电影结果打印出来:
def main(offset):
url = 'http://maoyan.com/board/4?offset=' + str(offset)
html = get_page(url)
parse_page(html)
到此为止,我们就完成了单页电影的提取,也就是首页的10部电影。
4.分页爬取
因为我们需要抓取的是TOP100的电影,所以还需要遍历一下,给这个链接传入offset参数,实现其他90部电影的爬取,此时添加如下调用即可:
for i in range(10):
main(offset=i * 10)
time.sleep(1)
5.完整代码
到此为止,我们的猫眼电影TOP100的爬虫就全部完成了,再稍微整理一下,完整的代码如下:
def get_page(url):
try:
response = requests.get(url,headers=headers)
if response.status_code == 200:
return response.text
return None
except RequestException:
return None
url = 'http://maoyan.com/board/4'
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}
def parse_page(html):
pattern = re.compile('.*?board-index.*?>(.*?).*?data-src="(.*?)".*?name.*?a.*?>(.*?).*?star.*?>(.*?).*?releasetime.*?>(.*?).*?integer.*?>(.*?).*?fraction.*?>(.*?).*? ', re.S)
items = re.findall(pattern, html)
for item in items:
print('index', item[0])
print('image', item[1])
print('title', item[2])
print('actor', item[3].strip()[3:])
print('time', item[4].strip()[5:])
print('score', item[5]+ item[6])
def main(offset):
url = 'http://maoyan.com/board/4?offset=' + str(offset)
html = get_page(url)
parse_page(html)
if __name__ == '__main__':
for i in range(10):
main(offset=i * 10)
time.sleep(1)
猫眼存在轻微的反爬虫,如果速度过快,则会无响应,所以这里又增加了一个延时等待。最后我们看看运行结果,只显示部分:
index 1
image https://p1.meituan.net/movie/20803f59291c47e1e116c11963ce019e68711.jpg@160w_220h_1e_1c
title 霸王别姬
actor 张国荣,张丰毅,巩俐
time 1993-01-01
score 9.5
index 2
image https://p0.meituan.net/movie/283292171619cdfd5b240c8fd093f1eb255670.jpg@160w_220h_1e_1c
title 肖申克的救赎
actor 蒂姆·罗宾斯,摩根·弗里曼,鲍勃·冈顿
time 1994-09-10(加拿大)
score 9.5
index 3
image https://p0.meituan.net/movie/289f98ceaa8a0ae737d3dc01cd05ab052213631.jpg@160w_220h_1e_1c
title 罗马假日
actor 格利高里·派克,奥黛丽·赫本,埃迪·艾伯特
time 1953-09-02(美国)
score 9.1
index 4
image https://p1.meituan.net/movie/6bea9af4524dfbd0b668eaa7e187c3df767253.jpg@160w_220h_1e_1c
title 这个杀手不太冷
actor 让·雷诺,加里·奥德曼,娜塔莉·波特曼
time 1994-09-14(法国)
score 9.5
index 5
image https://p1.meituan.net/movie/b607fba7513e7f15eab170aac1e1400d878112.jpg@160w_220h_1e_1c
title 泰坦尼克号
actor 莱昂纳多·迪卡普里奥,凯特·温丝莱特,比利·赞恩
time 1998-04-03
score 9.5
index 6
image https://p0.meituan.net/movie/da64660f82b98cdc1b8a3804e69609e041108.jpg@160w_220h_1e_1c
title 唐伯虎点秋香
actor 周星驰,巩俐,郑佩佩
time 1993-07-01(中国香港)
score 9.1
index 7
image https://p0.meituan.net/movie/46c29a8b8d8424bdda7715e6fd779c66235684.jpg@160w_220h_1e_1c
title 魂断蓝桥
actor 费雯·丽,罗伯特·泰勒,露塞尔·沃特森
time 1940-05-17(美国)
score 9.2
index 8
image https://p0.meituan.net/movie/223c3e186db3ab4ea3bb14508c709400427933.jpg@160w_220h_1e_1c
title 乱世佳人
actor 费雯·丽,克拉克·盖博,奥利维娅·德哈维兰
time 1939-12-15(美国)
score 9.1
index 9
image https://p1.meituan.net/movie/ba1ed511668402605ed369350ab779d6319397.jpg@160w_220h_1e_1c
title 天空之城
actor 寺田农,鹫尾真知子,龟山助清
time 1992-05-01
score 9.0
index 10
image https://p0.meituan.net/movie/b0d986a8bf89278afbb19f6abaef70f31206570.jpg@160w_220h_1e_1c
title 辛德勒的名单
actor 连姆·尼森,拉尔夫·费因斯,本·金斯利
time 1993-12-15(美国)
score 9.2
这个爬虫是不是很简单,通过这两个简单的实例我们了解到爬虫的基础流程,也大致掌握前面这些库的用法,此外我们在做数据采集少不了保存,后面我会有一篇博客专门介绍这个。