最近因为疫情在宿舍,刚好学习一下崔庆才老师的《python3 网络爬虫开发实战》,其中做到3.4节抓取猫眼电影排行,分析了一下猫眼电影,发现不是有猫眼验证中心,就是页面排行榜的文字信息被加密,想想还是一个小白,现在还不适宜去挑战这种超纲的题,还是一步一个脚印来吧。于是就想着豆瓣也有排行榜,试试它吧,于是发现和之前猫眼的排行机理差不多,刚好锻炼一下对第三章的掌握能力。不说废话了,开始!
目标站点:
https://movie.douban.com/top250
页面中显示的有效信息有影片名称、别称、导演、主演、上映时间、地区、评分、图片、分类等信息。
先抓取首页内容
import requests
def get_one_page(url):
try:
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36'
}
response = requests.get(url,headers=headers)
if response.status_code == 200:
return response.text
return None
except RequestException:
return None
def main():
url = 'https://movie.douban.com/top250'
html = get_one_page(url)
print(html)
main()
然后分析所需表单内容,所需的内容分别为电影排行序号、电影海报、电影名称、别名(大多数电影有两个以上的名称,但是为了方便(偷懒),就只取了两个)、导演和演员、地区、分类、评分。序号在 <em class=""></em>的节点中,海报在<img>的节点中,电影名称在class=“title”的span中,别名在class=“other”的span中,导演和演员、地区、分类都在class="bd"的div下的p标签中,评分在class="rating_num"的span中。
<div class="item">
<div class="pic">
<em class="">2</em>
<a href="https://movie.douban.com/subject/1291546/">
<img width="100" alt="霸王别姬" src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2561716440.jpg" class="">
</a>
</div>
<div class="info">
<div class="hd">
<a href="https://movie.douban.com/subject/1291546/" class="">
<span class="title">霸王别姬</span>
<span class="other"> / 再见,我的妾 / Farewell My Concubine</span>
</a>
<span class="playable">[可播放]</span>
</div>
<div class="bd">
<p class="">
导演: 陈凯歌 Kaige Chen 主演: 张国荣 Leslie Cheung / 张丰毅 Fengyi Zha...<br>
1993 / 中国大陆 中国香港 / 剧情 爱情 同性
</p>
<div class="star">
<span class="rating5-t"></span>
<span class="rating_num" property="v:average">9.6</span>
<span property="v:best" content="10.0"></span>
<span>1875128人评价</span>
</div>
<p class="quote">
<span class="inq">风华绝代。</span>
</p>
</div>
根据分析结果,得出如下正则表达式,同时将结果中一些多余的空格回车清除掉,并将结果存储在字典中:
import requests
import re
from requests.exceptions import RequestException
def get_one_page(url):
try:
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36'
}
response = requests.get(url,headers=headers)
if response.status_code == 200:
return response.text
return None
except RequestException:
return None
def clean_other_title(title):
title = re.sub('\s','',title)
return title
def clean_director(director):
director = re.sub('\n','',director)
director = re.sub('\s{7}','',director)
return director
def clean_time(time):
time = re.sub('\n','',time)
time = re.sub('\s','',time)
return time
def clean_breed(breed):
breed = re.sub('\n','',breed)
breed = re.sub('\s{2}','',breed)
return breed
def parse_one_page(html):
pattern = re.compile('<em\sclass="">(.*?)</em>.*?<img.*?src="(.*?)"'
+ '.*?<span.*?class="title">(.*?)</span>'
+ '.*?<span.*?other"> / (.*?)</span>'
+ '.*?class="bd".*?<p\sclass="">(.*?) (.*?)<br>'
+ '(.*?) / (.*?) / (.*?)</p>'
+ '.*?<span\sclass="rating_num".*?>(.*?)</span>',re.S)
items = re.findall(pattern,html)
for item in items:
yield {
'index':item[0],
'image':item[1],
'title':item[2],
'other-title':clean_other_title(item[3]),
'director':clean_director(item[4]),
'actor':item[5],
'time':clean_time(item[6]),
'country':item[7],
'breed':clean_breed(item[8]),
'score':item[9]
}
def main():
url = 'https://movie.douban.com/top250?'
html = get_one_page(url)
for item in parse_one_page(html):
print(item)
if __name__ == '__main__':
main()
按照上述步骤,就可以完整地将第一页内容的信息全部获取到了,部分结果如下:
{'index': '1', 'image': 'https://img2.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg', 'title': '肖申克的救赎', 'other-title': '月黑高飞(港)/刺激1995(台)', 'director': '导演: 弗兰克·德拉邦特 Frank Darabont', 'actor': '主演: 蒂姆·罗宾斯 Tim Robbins /...', 'time': '1994', 'country': '美国', 'breed': '犯罪 剧情', 'score': '9.7'}
{'index': '2', 'image': 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2561716440.jpg', 'title': '霸王别姬', 'other-title': '再见,我的妾/FarewellMyConcubine', 'director': '导演: 陈凯歌 Kaige Chen', 'actor': '主演: 张国荣 Leslie Cheung / 张丰毅 Fengyi Zha...', 'time': '1993', 'country': '中国大陆 中国香港', 'breed': '剧情 爱情 同性', 'score': '9.6'}
{'index': '3', 'image': 'https://img2.doubanio.com/view/photo/s_ratio_poster/public/p2372307693.jpg', 'title': '阿甘正传', 'other-title': '福雷斯特·冈普', 'director': '导演: 罗伯特·泽米吉斯 Robert Zemeckis', 'actor': '主演: 汤姆·汉克斯 Tom Hanks / ...', 'time': '1994', 'country': '美国', 'breed': '剧情 爱情', 'score': '9.5'}
{'index': '4', 'image': 'https://img9.doubanio.com/view/photo/s_ratio_poster/public/p457760035.jpg', 'title': '泰坦尼克号', 'other-title': '铁达尼号(港/台)', 'director': '导演: 詹姆斯·卡梅隆 James Cameron', 'actor': '主演: 莱昂纳多·迪卡普里奥 Leonardo...', 'time': '1997', 'country': '美国 墨西哥 澳大利亚 加拿大', 'breed': '剧情 爱情 灾难', 'score': '9.4'}
接下来就要做的事情就是获取整个排行榜信息了,现在将网页滚动到最下方,可以发现有分页的列表,点击第2 页,发现页面的URL变成了https://movie.douban.com/top250?start=25,原版第一页网址为 https://movie.douban.com/top250?start=0,可以发现一页显示排行25个,那么top250就有10页,那么请求10次就可以得到排行榜完整信息。每页的网址就由https://movie.douban.com/top250?start=和start的值两部分组成了,代码如下:
def main(start):
url = 'https://movie.douban.com/top250?start=' + str(start)
html = get_one_page(url)
for item in parse_one_page(html):
print(item)
if __name__ == '__main__':
i = 0
for i in range(1):
main(i*25)
time.sleep(1)
最后,就是将结果写入文件了。
def write_to_file(content):
with open('result.txt','a',encoding='utf-8') as f:
f.write(json.dumps(content,ensure_ascii=False) + '\n')
完整代码:
import requests
import re
from requests.exceptions import RequestException
import time
import json
def get_one_page(url):
try:
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36'
}
response = requests.get(url,headers=headers)
if response.status_code == 200:
return response.text
return None
except RequestException:
return None
def clean_other_title(title):
title = re.sub('\s','',title)
return title
def clean_director(director):
director = re.sub('\n','',director)
director = re.sub('\s{7}','',director)
return director
def clean_time(time):
time = re.sub('\n','',time)
time = re.sub('\s','',time)
return time
def clean_breed(breed):
breed = re.sub('\n','',breed)
breed = re.sub('\s{2}','',breed)
return breed
def write_to_file(content):
with open('result.txt','a',encoding='utf-8') as f:
f.write(json.dumps(content,ensure_ascii=False) + '\n')
def parse_one_page(html):
pattern = re.compile('<em\sclass="">(.*?)</em>.*?<img.*?src="(.*?)"'
+ '.*?<span.*?class="title">(.*?)</span>'
+ '.*?<span.*?other"> / (.*?)</span>'
+ '.*?class="bd".*?<p\sclass="">(.*?) (.*?)<br>'
+ '(.*?) / (.*?) / (.*?)</p>'
+ '.*?<span\sclass="rating_num".*?>(.*?)</span>',re.S)
items = re.findall(pattern,html)
for item in items:
yield {
'index':item[0],
'image':item[1],
'title':item[2],
'other-title':clean_other_title(item[3]),
'director':clean_director(item[4]),
'actor':item[5],
'time':clean_time(item[6]),
'country':item[7],
'breed':clean_breed(item[8]),
'score':item[9]
}
def main(start):
url = 'https://movie.douban.com/top250?start=' + str(start)
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(i*25)
time.sleep(1)