1.本节目标:
利用requests库和正则表达式来抓取电影TOP100的相关内容,如电影名称、时间、评分、图片信息等,提取的站点URL为:http://maoyan.com/board/4。结果以文件形式保存至电脑。
2.准备工作:
(1)安装requests库。
(2)IDE:pycharm
(3)python3.6
3.抓取分析:
我们需要抓取的目标站点为http://maoyan.com/board/4,打开之后便可以查看到榜单信息,如图3-1所示。
排名第一的电影是霸王别姬,页面中显示的有效信息有影片名称、主演、上映时间、上映地区、评分、图片等信息。
将网页滚动到最下方,可以发现有分页的列表,直接点击第2页,观察页面的URL和内容发生了怎样的变化,如图3-2所示。
可以发现页面的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的所有电影信息了。
4.正则表达式 - 提取数据:
(1)使用浏览器访问[http://maoyan.com/board/4],Ctrl+Shift+i,Network监听组件中查看源代码,如图3-3所示。
(2)经分析可知:一部电影信息对应的源代码是一个dd节点,我们用正则表达式来提取这里面的一些电影信息。首先,需要提取它的排名信息。而它的排名信息是在class为board-index的i节点内,这里利用非贪婪匹配来提取i节点内的信息,正则表达式写为:
<dd>.*?board-index.*?>(.*?)</i>
随后需要提取电影的图片。可以看到,后面有a节点,其内部有两个img节点。经过检查后发现,第二个img节点的data-src属性是图片的链接。这里提取第二个img节点的data-src属性,正则表达式可以改写如下:
<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)"
再往后,需要提取电影的名称,它在后面的p节点内,class为name。所以,可以用name做一个标志位,然后进一步提取到其内a节点的正文内容,此时正则表达式改写如下:
<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(.*?)</a>
再提取主演、发布时间、评分等内容时,都是同样的原理。最后,正则表达式写为:
<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(.*?)</a>.*?star.*?>(.*?)</p>.*?releasetime.*?>(.*?)</p>.*?integer.*?>(.*?)</i>.*?fraction.*?>(.*?)</i>.*?</dd>
这样一个正则表达式可以匹配一个电影的结果,里面匹配了7个信息。接下来,通过调用findall()方法提取出所有的内容。
5.代码实现:
import requests
import re
import json
import time
'''
爬取猫眼网TOP100,url:http://maoyan.com/board/4
使用requests爬取网页,正则表达式提取网页。
'''
def get_one_page(url):
'''
:param url:需要爬取的网页URL
:return: 若response.status_code == 200 ,返回response.text
'''
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36'
}
response = requests.get(url, headers=headers)
if response.status_code == 200:
return response.text
else:
return None
def parse_one_page(html):
# 将正则字符串编译成正则表达式对象pattern
pattern = re.compile(
'<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(.*?)</a>.*?star.*?>(.*?)</p>.*?releasetime.*?>(.*?)</p>.*?integer.*?>(.*?)</i>.*?fraction.*?>(.*?)</i>',
re.S)
items = re.findall(pattern, html)
# 遍历提取结果并生成字典,形成结构数据化。
for item in items:
yield {
'top': item[0],
'image': item[1],
'title': item[2].strip(),
'actor': item[3].strip()[3:] if len(item[3]) > 3 else '',
'time': item[4].strip()[5:] if len(item[4]) > 5 else '',
'score': item[5].strip() + item[6].strip()
}
def write_to_file(content):
with open('maoyan_top100.txt', 'a', encoding='UTF-8') as f:
# print(type(json.dumps(content)))
# json.dump()实现字典的序列化,并指定ensure_ascii=False,保证输出结果是中文形式而不是Unicode编码
f.write(json.dumps(content, ensure_ascii=False) + '\n')
def main(offset):
'''
调用get_one_page()的函数,并将返回的值传递给parse_one_page()进行数据提取。
'''
url = 'http://maoyan.com/board/4?offset=' + str(offset)
html = get_one_page(url)
for item in parse_one_page(html):
print(item)
write_to_file(item)
if __name__ == '__main__':
for i in range(10):
main(offset=i * 10)
time.sleep(1)
实现效果如下:
效果图
总结:通过抓取猫眼TOP100练习requests和正则表达式的基础用法,掌握如何实现简单的分页数据爬取,同时学会使用文件存储数据。
参考:静觅 » [Python3网络爬虫开发实战] 3.4-抓取猫眼电影排行
注:兴趣所致,我会不时的分享一些爬虫小项目,若读者有更好的建议或是学习爬虫所遇到的问题,可在下方留言,共同探讨,谢谢。
网友评论