抓取猫眼电影上面Top100榜单,抓取的内容有电影名称,主演,上映时间,图片,得分等信息。抓取的内容以文件形式保存,地址为https://maoyan.com/board/4
1.分析
该榜单页面如下
拉到底部点击下一页,发现此时的URL变化了。
此时的URL变为https://maoyan.com/board/4?offset=10,比之前的URL多了参数offset=10,再点击下一页的URL为https://maoyan.com/board/4?offset=20,由此我们发现了规律,Top100,每页展示10部电影,这样100部电影需要请求10次
2.抓取首页
首先来抓取第一页的内容,我们编写一个get_one_page()的方法
import requests
def get_one_page(url):
response = requests.get(url)
if response.status_code == 200:
return response.text
return None
def main():
url = 'http://maoyan.com/board/4'
html = get_one_page(url)
print(html)
main()
3.正则提取
网页在开发者模式下,network,查看源码
排名第一的霸王别姬的源码如下:
1
9.
5
可以看到一部电影对应一个
dd
节点,排名信息在
class
为
board-index
的
i
节点内,利用非贪婪匹配来提取
i
节点内的信息,正则表达式为
.*?board-index.*?>(.*?)
然后提取图片信息,接下来的
a
节点,里面有两个
img
节点,经过检查后发现,第二个
img
节点的
data-src
属性是图片的链接。于是提取第二个
img
节点的
data-src
属性,正则表达式改写如下:
.*?board-index.*?>(.*?).*?data-src="(.*?)"
之后,提取电影名称,在后面的
p
节点内,
class
为
name
,之后的
a
节点里
.*?board-index.*?>(.*?).*?data-src="(.*?)".*?name.*?a.*?>(.*?)
主演信息在
p
节点下
class
为
star
,上映时间在
p
节点下
class
为
releasetime
,评分在‘p’节点下的’class’为
score
,其中整数部分对应
integer
,小数部分对应为
fraction
。完整的表达式为
.*?board-index.*?>(.*?).*?data-src="(.*?)".*?name.*?a.*?>(.*?).*?star.*?>(.*?)
.*?releasetime.*?>(.*?)
.*?integer.*?>(.*?).*?fraction.*?>(.*?).*?
这样就可以将一页中10部电影的信息提取出来
定义解析页面的方法为
parse_one_page()
,主要通过正则表达式提取想要的内容
def parse_one_page(html):
pattern = re.compile( '
.*?board-index.*?>(.*?).*?data-src="(.*?)".*?name.*?a.*?>(.*?).*?star.*?>(.*?)
.*?releasetime.*?>(.*?)
.*?integer.*?>(.*?).*?fraction.*?>(.*?).*?
',
re.S)
items = re.findall(pattern,html)
print(items)
提取出来的结果如下:
[('1', 'https://p1.meituan.net/movie/20803f59291c47e1e116c11963ce019e68711.jpg@160w_220h_1e_1c', '霸王别姬', '\n 主演:张国荣,张丰毅,巩俐\n ', '上映时间:1993-01-01', '9.', '5'), ('2', 'https://p0.meituan.net/movie/283292171619cdfd5b240c8fd093f1eb255670.jpg@160w_220h_1e_1c', '肖申克的救赎', '\n 主演:蒂姆·罗宾斯,摩根·弗里曼,鲍勃·冈顿\n ', '上映时间:1994-09-10(加拿大)', '9.', '5'), ('3', 'https://p0.meituan.net/movie/289f98ceaa8a0ae737d3dc01cd05ab052213631.jpg@160w_220h_1e_1c', '罗马假日', '\n 主演:格利高里·派克,奥黛丽·赫本,埃迪·艾伯特\n ', '上映时间:1953-09-02(美国)', '9.', '1'), ('4', 'https://p1.meituan.net/movie/6bea9af4524dfbd0b668eaa7e187c3df767253.jpg@160w_220h_1e_1c', '这个杀手不太冷', '\n 主演:让·雷诺,加里·奥德曼,娜塔莉·波特曼\n ', '上映时间:1994-09-14(法国)', '9.', '5'), ('5', 'https://p1.meituan.net/movie/b607fba7513e7f15eab170aac1e1400d878112.jpg@160w_220h_1e_1c', '泰坦尼克号', '\n 主演:莱昂纳多·迪卡普里奥,凯特·温丝莱特,比利·赞恩\n ', '上映时间:1998-04-03', '9.', '5'), ('6', 'https://p0.meituan.net/movie/da64660f82b98cdc1b8a3804e69609e041108.jpg@160w_220h_1e_1c', '唐伯虎点秋香', '\n 主演:周星驰,巩俐,郑佩佩\n ', '上映时间:1993-07-01(中国香港)', '9.', '1'), ('7', 'https://p0.meituan.net/movie/46c29a8b8d8424bdda7715e6fd779c66235684.jpg@160w_220h_1e_1c', '魂断蓝桥', '\n 主演:费雯·丽,罗伯特·泰勒,露塞尔·沃特森\n ', '上映时间:1940-05-17(美国)', '9.', '2'), ('8', 'https://p0.meituan.net/movie/223c3e186db3ab4ea3bb14508c709400427933.jpg@160w_220h_1e_1c', '乱世佳人', '\n 主演:费雯·丽,克拉克·盖博,奥利维娅·德哈维兰\n ', '上映时间:1939-12-15(美国)', '9.', '1'), ('9', 'https://p1.meituan.net/movie/ba1ed511668402605ed369350ab779d6319397.jpg@160w_220h_1e_1c', '天空之城', '\n 主演:寺田农,鹫尾真知子,龟山助清\n ', '上映时间:1992', '9.', '1'), ('10', 'https://p0.meituan.net/movie/b0d986a8bf89278afbb19f6abaef70f31206570.jpg@160w_220h_1e_1c', '辛德勒的名单', '\n 主演:连姆·尼森,拉尔夫·费因斯,本·金斯利\n ', '上映时间:1993-12-15(美国)', '9.', '2')]
我们处理一下结果,让它以字典的形式呈现:
def parse_one_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:
yield{
'排名':item[0],
'图片':item[1],
'电影名称':item[2],
'演员':item[3].strip()[3:],
'上映时间':item[4].strip()[5:],
'评分':item[5]+item[6]}
运行结果如下:
{'排名': '1', '图片': 'https://p1.meituan.net/movie/20803f59291c47e1e116c11963ce019e68711.jpg@160w_220h_1e_1c', '电影名称': '霸王别姬', '演员': '张国荣,张丰毅,巩俐', '上映时间': '1993-01-01', '评分': '9.5'}
{'排名': '2', '图片': 'https://p0.meituan.net/movie/283292171619cdfd5b240c8fd093f1eb255670.jpg@160w_220h_1e_1c', '电影名称': '肖申克的救赎', '演员': '蒂姆·罗宾斯,摩根·弗里曼,鲍勃·冈顿', '上映时间': '1994-09-10(加拿大)', '评分': '9.5'}
{'排名': '3', '图片': 'https://p0.meituan.net/movie/289f98ceaa8a0ae737d3dc01cd05ab052213631.jpg@160w_220h_1e_1c', '电影名称': '罗马假日', '演员': '格利高里·派克,奥黛丽·赫本,埃迪·艾伯特', '上映时间': '1953-09-02(美国)', '评分': '9.1'}
{'排名': '4', '图片': 'https://p1.meituan.net/movie/6bea9af4524dfbd0b668eaa7e187c3df767253.jpg@160w_220h_1e_1c', '电影名称': '这个杀手不太冷', '演员': '让·雷诺,加里·奥德曼,娜塔莉·波特曼', '上映时间': '1994-09-14(法国)', '评分': '9.5'}
{'排名': '5', '图片': 'https://p1.meituan.net/movie/b607fba7513e7f15eab170aac1e1400d878112.jpg@160w_220h_1e_1c', '电影名称': '泰坦尼克号', '演员': '莱昂纳多·迪卡普里奥,凯特·温丝莱特,比利·赞恩', '上映时间': '1998-04-03', '评分': '9.5'}
{'排名': '6', '图片': 'https://p0.meituan.net/movie/da64660f82b98cdc1b8a3804e69609e041108.jpg@160w_220h_1e_1c', '电影名称': '唐伯虎点秋香', '演员': '周星驰,巩俐,郑佩佩', '上映时间': '1993-07-01(中国香港)', '评分': '9.1'}
{'排名': '7', '图片': 'https://p0.meituan.net/movie/46c29a8b8d8424bdda7715e6fd779c66235684.jpg@160w_220h_1e_1c', '电影名称': '魂断蓝桥', '演员': '费雯·丽,罗伯特·泰勒,露塞尔·沃特森', '上映时间': '1940-05-17(美国)', '评分': '9.2'}
{'排名': '8', '图片': 'https://p0.meituan.net/movie/223c3e186db3ab4ea3bb14508c709400427933.jpg@160w_220h_1e_1c', '电影名称': '乱世佳人', '演员': '费雯·丽,克拉克·盖博,奥利维娅·德哈维兰', '上映时间': '1939-12-15(美国)', '评分': '9.1'}
{'排名': '9', '图片': 'https://p1.meituan.net/movie/ba1ed511668402605ed369350ab779d6319397.jpg@160w_220h_1e_1c', '电影名称': '天空之城', '演员': '寺田农,鹫尾真知子,龟山助清', '上映时间': '1992', '评分': '9.1'}
{'排名': '10', '图片': 'https://p0.meituan.net/movie/b0d986a8bf89278afbb19f6abaef70f31206570.jpg@160w_220h_1e_1c', '电影名称': '辛德勒的名单', '演员': '连姆·尼森,拉尔夫·费因斯,本·金斯利', '上映时间': '1993-12-15(美国)', '评分': '9.2'}
4.写入网页
我们将提取的结果写入文件,这里直接写入到一个文本文件中。这里通过
JSON库
的
dumps()
方法实现字典的序列化,并指定
ensure_ascii
参数为
False
,这样可以保证输出结果是中文形式而不是
Unicode
编码。代码如下:
def write_to_json(content):
with open('result.txt','a') as f:
print(type(json.dumps(content)))
f.write(json.dumps(content,ensure_ascii=False)+'\n')
content
为提取下来的一部电影的信息
5.整合代码
def main():
url = 'http://maoyan.com/board/4'
html = get_one_page(url)
for item in parse_one_page(html):
print(item)
write_to_json(item)
实现了将第一页的十部电影爬取下来,保存到本地文件中。
6.分页爬取
我们想要爬取的是前100部电影,所以还需要遍历一下,给这个链接传入offset参数,实现其他90部电影的爬取
if __name__ == '__main__':
for i in range(10):
main(offset=i * 10)
那么在定义
main()
时需要给它一个
offset
参数
def main(offset):
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_json(item)
完整代码
import requests
import re
import json
def get_one_page(url):
response = requests.get(url)
if response.status_code == 200:
return response.text
return None
def parse_one_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:
yield{
'排名':item[0],
'图片':item[1],
'电影名称':item[2],
'演员':item[3].strip()[3:],
'上映时间':item[4].strip()[5:],
'评分':item[5]+item[6]}
def write_to_json(content):
with open('result.txt','a') as f:
print(type(json.dumps(content)))
f.write(json.dumps(content,ensure_ascii=False)+'\n')
def main(offset):
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_json(item)
if __name__ == '__main__':
for i in range(10):
main(offset=i * 10)