爬取豆瓣电影排行榜
2. 页面分析
接下来,我们要在这个页面提取每一部电影的详情节链接,总页码数,每一部电影的短评。
我们先来提取电影详情页的链接。
# 获取豆瓣top250每个页面下的电影豆瓣链接列表
movies_link_list = html.xpath('//li//div[@class="info"]/div[@class="hd"]/a/@href')
提取导航页的每一部电影的短评。
`# 获取每个页面下的电影的代表影评
movies_quote_list = html.xpath('//p[@class="quote"]/span[@class="inq"]/text()')`
提取电影排行榜的总页数
`total_page_num = int(html.xpath('string(//span[@class="next"]/preceding-sibling::a[1])'))`
下面,我们提取每一部电影的详细信息。
我们提取的信息包括上图中的电影排名、名称、链接、评分、评价人数以及各个星级的评价人数,还有电影的导演,编剧、主演、类型、制片国家/地区、语言、上映日期、片长、又名和IMDb链接。代码如下:
# 获取电影排名
movie_rank = r'电影排名:{}'.format(html.xpath('string(//div[@class="top250"]/span[@class="top250-no"])'))
# 获取电影名称
movie_name = r'电影名称:{}'.format(html.xpath('string(//span[@property="v:itemreviewed"])'))
# 获取电影链接
movie_link = r'电影链接:{}'.format(movie_link)
# 获取电影评分
movie_score = r'电影评分:{}'.format(html.xpath('string(//strong[@property="v:average"])'))
# 获取电影评价总人数
movie_evaluated_people = r'电影评价人数:{}'.format(html.xpath('string(//a[@class="rating_people"])'))
# 获取电影5个评价星级
movie_stars_list = [i.strip() for i in
html.xpath('//div[@class="item"]//span[starts-with(@class, "stars")]/text()')]
# 获取电影5个评价星级对应的评价人数的百分比
movie_evaluated_per_list = html.xpath('//div[@class="item"]//span[@class="rating_per"]/text()')
try:
response = requests.get(url, headers)
if response.status_code == 200:
return response.content.decode('utf-8')
except requests.ConnectionError:
print('网页数据爬取错误!!!!')
return None
4.保存页面
我把爬取的电影的详细保存到JSON文件。
with open(file_name, 'a', encoding='utf-8') as f:
f.write(json.dumps(content, indent=4, ensure_ascii=False))
f.write('\n' * 2)
5.完整代码
下面是完整的代码。
import json
import re
import time
import requests
from lxml import etree
def get_page_source(url, headers):
"""
获取网页源代码
:param url: 网页地址
:param headers: 请求头
:return: html字符串
"""
try:
response = requests.get(url, headers)
if response.status_code == 200:
return response.content.decode('utf-8')
except requests.ConnectionError:
print('网页数据爬取错误!!!!')
return None
def get_page_num(page_source):
"""
获取页面总页数
:param page_source: html字符串
:return: 页数(int)
"""
html = etree.HTML(page_source)
total_page_num = int(html.xpath('string(//span[@class="next"]/preceding-sibling::a[1])'))
return total_page_num
def get_movie_info(page_source, headers):
"""
获取每一部电影的详细信息
:param page_source:导航页HTML字符串
:param headers: 请求头
:return:电影的全部信息
"""
if page_source:
html = etree.HTML(page_source)
# 获取豆瓣top250每个页面下的电影豆瓣链接列表
movies_link_list = html.xpath('//li//div[@class="info"]/div[@class="hd"]/a/@href')
# 获取每个页面下的电影的代表影评
movies_quote_list = html.xpath('//p[@class="quote"]/span[@class="inq"]/text()')
for movie_link, movie_quote in zip(movies_link_list, movies_quote_list):
time.sleep(0.5) # 延迟,防屏蔽
# 获取每一部电影的详细页面
_page_source = get_page_source(movie_link, headers)
if _page_source:
html = etree.HTML(_page_source)
# 新建列表,用于存储导演、编剧、主演、类型、制片国家/地区、语言、上映日期、片长、又名、IMDb链接的具体信息
movie_info_list = [a for a in re.split(r'\n ', html.xpath('string(//div[@id="info"])').strip())
if bool(a)]
# 将影评添加到movie_info_list的最后
movie_info_list.append('影评:' + movie_quote)
# 获取电影排名
movie_rank = r'电影排名:{}'.format(html.xpath('string(//div[@class="top250"]/span[@class="top250-no"])'))
# 获取电影名称
movie_name = r'电影名称:{}'.format(html.xpath('string(//span[@property="v:itemreviewed"])'))
# 获取电影链接
movie_link = r'电影链接:{}'.format(movie_link)
# 获取电影评分
movie_score = r'电影评分:{}'.format(html.xpath('string(//strong[@property="v:average"])'))
# 获取电影评价总人数
movie_evaluated_people = r'电影评价人数:{}'.format(html.xpath('string(//a[@class="rating_people"])'))
# 新建列表,存储电影其他信息
movie_other_info_list = [
movie_rank, movie_name, movie_link, movie_score, movie_evaluated_people,
]
# 获取电影5个评价星级
movie_stars_list = [i.strip() for i in
html.xpath('//div[@class="item"]//span[starts-with(@class, "stars")]/text()')]
# 获取电影5个评价星级对应的评价人数的百分比
movie_evaluated_per_list = html.xpath('//div[@class="item"]//span[@class="rating_per"]/text()')
# 将电影5个评价星级及对应评价人数写入列表
for each in zip(movie_stars_list, movie_evaluated_per_list):
movie_other_info_list.append('{}评价人数:{}'.format(*each))
# 合并电影的详细信息
movie_other_info_list.extend(movie_info_list)
yield movie_other_info_list
print(
'已经写入第{}部电影\t{}\t的信息'.format(html.xpath('string(//div[@class="top250"]/span[@class="top250-no"])'),
html.xpath('string(//span[@property="v:itemreviewed"])')))
def save_to_json(content, file_name):
"""
保存到JSON文件
:param content: 电影信息
:param file_name: 文件名
:return:
"""
with open(file_name, 'a', encoding='utf-8') as f:
f.write(json.dumps(content, indent=4, ensure_ascii=False))
f.write('\n' * 2)
def main():
file_name = r'top250.json'
url = r'https://movie.douban.com/top250'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0',
}
page_source = get_page_source(url, headers)
total_page_num = get_page_num(page_source)
for each_page in range(total_page_num):
url = 'https://movie.douban.com/top250?start={}'.format(each_page * 25)
page_source = get_page_source(url, headers)
for _movie_info in get_movie_info(page_source, headers):
save_to_json(_movie_info, file_name)
if __name__ == "__main__":
print('----------爬取开始----------')
main()
print('豆瓣电影排行榜前250的电影信息写入完毕')