一、项目描述
本项目是利用requests库和正则表达式来抓取猫眼电影榜单TOP100的相关内容。至于解析工具,在不使用xpath、bs4以及pyquery等解析工具的情况下,正则表达式无疑是最直接、最暴力的提取页面的方法。
二、准备工作
安装好requests库,若未安装,使用如下命令进行安装:
pip install requests
三、爬取分析
1)爬取网页的url
url = "https://maoyan.com/board/4"
如图所示:
2)翻页问题
将网页翻到最底部,发现有分页,点击下一页:
此时分析,第一页的时候,url没有出现offset,第2页的offset(偏移量)是10,第3页:offset=20......
以此类推,可得:
第一页:offset 无
第二页:offset = 10
第三页:offset = 20
第四页:offset = 30
...
第十页:offset = 90
四、爬取解析页面
1)爬取一个页面
首先抓取一个页面的内容。我们实现了get_page()方法,并给它传入url参数。然后将抓取的页面结果返回,再通过main()方法调用。初步代码实现如下:
# 创建发起请求
# 返回网页文本
def get_page(url):
try:
# 请求头
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'
}
# 创建请求
req = urllib.request.Request(url=url, headers=headers)
# 发起请求,得到相应
res = urllib.request.urlopen(req)
if res.getcode() == 200:
# 返回页面文本
return res.read().decode("utf-8")
return None
except BaseException as e:
return None
2)提取页面
这里面我们将上面获取的页面用正则提取出来,注意,这里不要在Elements选项卡中直接查看源码,因为那里的源码可能经过JavaScript操作而与原始请求不同,而是需要从Network选项卡部分查看原始请求得到的源码。
查看其中一个条目的源代码,如图3所示。
可以看到,一部电影信息对应的源代码是一个dd节点,我们用正则表达式来提取这里面的一些电影信息。
首先,需要提取它的排名信息。而它的排名信息是在class为board-index的i节点内,这里利用非贪婪匹配来提取i节点内的信息,正则表达式写为:
.*?board-index.*?>(.*?)
随后需要提取电影的图片。可以看到,后面有a节点,其内部有两个img节点。经过检查后发现,第二个img节点的data-src属性是图片的链接。这里提取第二个img节点的data-src属性,正则表达式可以改写如下:
.*?board-index.*?>(.*?).*?data-src="(.*?)"
再往后,需要提取电影的名称,它在后面的p节点内,class为name。所以,可以用name做一个标志位,然后进一步提取到其内a节点的正文内容,此时正则表达式改写如下:
.*?board-index.*?>(.*?).*?data-src="(.*?)".*?name.*?a.*?>(.*?)
【其他电影信息的正则,不一一赘述】
最终写出来的正则表达式如下【每个人写正则表达式略有不同】:
.*?board-index.*?>(.*?).*?data-src="(.*?)".*?name.*?a.*?>(.*?).*?star.*?>(.*?).*?releasetime.*?>(.*?).*?integer.*?>(.*?).*?fraction.*?>(.*?).*?
我们使用findll()函数来匹配正则,返回一个列表,效果如下:
[('1','http://p1.meituan.net/movie/20803f59291c47e1e116c11963ce019e68711.jpg@160w_220h_1e_1c', '霸王别姬', '\n 主演:张国荣,张丰毅,巩俐\n ', '上映时间:1993-01-01(中国香港)', '9.', '6'),
('2','http://p0.meituan.net/movie/__40191813__4767047.jpg@160w_220h_1e_1c', '肖申克的救赎', '\n 主演:蒂姆·罗宾斯,摩根·弗里曼,鲍勃·冈顿\n ', '上映时间:1994-10-14(美国)', '9.', '5'),
('3','http://p0.meituan.net/movie/fc9d78dd2ce84d20e53b6d1ae2eea4fb1515304.jpg@160w_220h_1e_1c', '这个杀手不太冷', '\n 主演:让·雷诺,加里·奥德曼,娜塔莉·波特曼\n ', '上映时间:1994-09-14(法国)', '9.', '5'),
('4','http://p0.meituan.net/movie/23/6009725.jpg@160w_220h_1e_1c', '罗马假日', '\n 主演:格利高利·派克,奥黛丽·赫本,埃迪·艾伯特\n ', '上映时间:1953-09-02(美国)', '9.', '1'),
('5','http://p0.meituan.net/movie/53/1541925.jpg@160w_220h_1e_1c', '阿甘正传', '\n 主演:汤姆·汉克斯,罗宾·怀特,加里·西尼斯\n ', '上映时间:1994-07-06(美国)', '9.', '4'),
('6','http://p0.meituan.net/movie/11/324629.jpg@160w_220h_1e_1c', '泰坦尼克号', '\n 主演:莱昂纳多·迪卡普里奥,凯特·温丝莱特,比利·赞恩\n ', '上映时间:1998-04-03', '9.', '5'),
('7','http://p0.meituan.net/movie/99/678407.jpg@160w_220h_1e_1c', '龙猫', '\n 主演:日高法子,坂本千夏,糸井重里\n ', '上映时间:1988-04-16(日本)', '9.', '2'),
('8','http://p0.meituan.net/movie/92/8212889.jpg@160w_220h_1e_1c', '教父', '\n 主演:马龙·白兰度,阿尔·帕西诺,詹姆斯·凯恩\n ', '上映时间:1972-03-24(美国)', '9.', '3'),
('9','http://p0.meituan.net/movie/62/109878.jpg@160w_220h_1e_1c', '唐伯虎点秋香', '\n 主演:周星驰,巩俐,郑佩佩\n ', '上映时间:1993-07-01(中国香港)', '9.', '2'),
('10','http://p0.meituan.net/movie/9bf7d7b81001a9cf8adbac5a7cf7d766132425.jpg@160w_220h_1e_1c', '千与千寻', '\n 主演:柊瑠美,入野自由,夏木真理\n ', '上映时间:2001-07-20(日本)', '9.', '3')]
很明显,每一条数据,都是存放在一个元组里面,所以我们应该把它们取出来,利用字典将对应的数据存储下来。
最后使用生成器(一个容器),将一个页面的10部电影信息,也就是10条数据存储在其中,代码实现如下:
# 解析页面 正则
def parge_page(html_text):
# pattern = re.compile(r'.*?board-index.*?(\d+).*?(.*?).*?"star">(.*?).*?"releasetime">(.*?)*?"interger">(.*?).*?"faraction">(.*?)', re.S)
pattern = re.compile(r'.*?board-index.*?>(\d+).*?data-src="(.*?)".*?name">(.*?).*?star">(.*?).*?releasetime">(.*?).*?integer">(.*?).*?fraction">(.*?).*? ', re.S)
# 匹配
items = re.findall(pattern, html_text)
print(items)
# print()
for item in items:
dic = {
'index': item[0],
'image': item[1],
'title': item[2],
'actor': item[3].strip()[3:],
'time': item[4].strip()[5:],
'score': item[5] + item[6]
}
yield dic
五、写入文件
写入文件就简单的多了,我直接上代码:
# 写入文件
def write_to_file(item):
with open('./猫眼电影Top100.txt', 'a', encoding='utf-8') as fp:
fp.write(json.dumps(item, ensure_ascii=False) + '\n\n')
六、main():对外的接口函数
利用main()函数来作为对外的接口函数,调用get_page()、parse_page()函数。
代码如下:
# 主函数
def main(offset):
# 请求url
url = "https://maoyan.com/board/4?offset={}".format(offset)
print("请求url:" + url)
# 创建发起请求
html_text = get_page(url)
# print(html_text)
# 解析文本
# 得到的items是一个列表
# 列表里面有十条数据
# 每一页就是items
# 然后将每一页的10条数据存入生成器
# 然后这个生成器作为返回值传给外面的变量
items = parge_page(html_text)
print(type(items))
# 写入文件
for item in items:
# print("itme: " + item)
write_to_file(item)
七、爬取所有页面电影信息
利用if __name__ == '__main__'函数, 将main函数的参数offset传过去,代码如下:
【ps:关于if __name__ == '__main__'函数的理解,请参考我的另外一篇:https://www.jianshu.com/p/8f696f15e219】
if __name__ == '__main__':
for i in range(10):
main(i*10)
time.sleep(1)
八、总结
爬取猫眼电影榜单-->Top100代码如下:
#!C:/SoftWare/Virtualenv/python3
# @FileName: 06-猫眼电影排行
# @Author: 李易阳
# @Time: 2019/2/27
# @Soft: PyCharm
# 任务:爬取猫眼电影榜单下top100
# 导包
import re
import json
import time
import urllib.request
# 创建发起请求
# 返回网页文本
def get_page(url):
try:
# 请求头
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'
}
# 创建请求
req = urllib.request.Request(url=url, headers=headers)
# 发起请求,得到相应
res = urllib.request.urlopen(req)
if res.getcode() == 200:
# 返回页面文本
return res.read().decode("utf-8")
return None
except BaseException as e:
return None
# 解析页面 正则
def parge_page(html_text):
# pattern = re.compile(r'.*?board-index.*?(\d+).*?(.*?).*?"star">(.*?).*?"releasetime">(.*?)*?"interger">(.*?).*?"faraction">(.*?)', re.S)
pattern = re.compile(r'.*?board-index.*?>(\d+).*?data-src="(.*?)".*?name">(.*?).*?star">(.*?).*?releasetime">(.*?).*?integer">(.*?).*?fraction">(.*?).*? ', re.S)
# 匹配
items = re.findall(pattern, html_text)
print(items)
# print()
for item in items:
yield {
'index': item[0],
'image': item[1],
'title': item[2],
'actor': item[3].strip()[3:],
'time': item[4].strip()[5:],
'score': item[5] + item[6]
}
# 写入文件
def write_to_file(item):
with open('./猫眼电影Top100.txt', 'a', encoding='utf-8') as fp:
fp.write(json.dumps(item, ensure_ascii=False) + '\n\n')
# 主函数
def main(offset):
# 请求url
url = "https://maoyan.com/board/4?offset={}".format(offset)
print("请求url:" + url)
# 创建发起请求
html_text = get_page(url)
# print(html_text)
# 解析文本
# 得到的items是一个列表
# 列表里面有十条数据
# 每一页就是items
# 然后将每一页的10条数据存入生成器
# 然后这个生成器作为返回值传给外面的变量
items = parge_page(html_text)
print(type(items))
# 写入文件
for item in items:
# print("itme: " + item)
write_to_file(item)
if __name__ == '__main__':
for i in range(10):
main(i*10)
time.sleep(1)
@墨雨出品 必属精品 如有雷同 纯属巧合
`非学无以广才,非志无以成学!`
参考资料《Python3网络爬虫开发实践》,作者崔庆才