爬取目标
爬取豆瓣电影TOP250信息并简单分析
网络请求及解析库
加载所需工具包
import re #用于传入正则表达式作为参数
import numpy as np
import pandas as pd
from bs4 import BeautifulSoup
import requests
import time
查看网页
由于豆瓣某些电影链接需要登录后才能查看,所以我用自己的账号登录豆瓣后,获取网站的cookie,将cookie添加到requests的session中,将cookie持久化,这样每次访问网站都会带上这个cookie。
Cookie,有时也用其复数形式 Cookies,指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)。
按F12进入调试模式在Network中,F5刷新后一般在左侧第一个网址内的Requset Headers可以查到看网站的cookie。
查看https://movie.douban.com/top250
下方页码条,可看到该网址共有10个页面,点击第2页,显示网址为https://movie.douban.com/top250?start=25&filter=
,根据网址结构,可以看出只需修改start=
末尾的数值,不断访问新的页面就可以爬取到所有页面信息。
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)'}
#模拟浏览器访问网页
http_session = requests.session()
#定义了http_session用来作为我们的session
cookie = 'll="118254"; bid=JSyRhtte0VA; __yadk_uid=0kfCKOtzBXvPqtiMypgQ0uK5r2055OMk; ct=y; viewed="24862771_7056708_3595095_25775696_25833225_20429677"; gr_user_id=000a52d9-7093-4cdc-902d-452ba224da82; ps=y; ue="29288849@qq.com"; dbcl2="182571279:h94qNxNP398"; ck=kT5x; _pk_ref.100001.4cf6=%5B%22%22%2C%22%22%2C1533818089%2C%22https%3A%2F%2Fwww.douban.com%2Faccounts%2Flogin%3Fredir%3Dhttps%253A%252F%252Fmovie.douban.com%252F%22%5D; _vwo_uuid_v2=D5BD0897E8A4014E0136ABC56424C8BF4|96af10151a86ee46b335061264ea143a; ap=1; _pk_id.100001.4cf6=fdb804e89a884d46.1533703967.11.1533818851.1533806907.; _pk_ses.100001.4cf6=*; __utma=30149280.642519294.1533296417.1533806807.1533817228.17; __utmb=30149280.6.10.1533817228; __utmc=30149280; __utmz=30149280.1533817228.17.7.utmcsr=accounts.douban.com|utmccn=(referral)|utmcmd=referral|utmcct=/safety/unlock_sms/resetpassword; __utmv=30149280.18257; __utma=223695111.1629547352.1533703967.1533806807.1533818089.12; __utmb=223695111.0.10.1533818089; __utmc=223695111; __utmz=223695111.1533818089.12.3.utmcsr=douban.com|utmccn=(referral)|utmcmd=referral|utmcct=/accounts/login; push_noty_num=0; push_doumail_num=0'
#从浏览器中获取的cookie
cookies = {i.split('=')[0]:i.split('=')[1] for i in cookie.split(';')}
#将cookies转换成requests能够接受的字典格式
requests.utils.add_dict_to_cookiejar(http_session.cookies,cookies)
#将cookie添加到requests提供的http_session里面
urls = ['https://movie.douban.com/top250?start=%i' %i for i in range(0,250,25)]
#需爬取所有页面列表
点击https://movie.douban.com/top250
内排名第一的电影肖申克的救赎进入网址https://movie.douban.com/subject/1292052/
里面就有我们所需的电影信息
怎么获取这个网址呢?
通过鼠标移动到页面超链接上,右键点选检查,进入调试模式后,会自动定位到该内容所在节点,查看其他电影超链接,发现每一个电影的超链接网址都在<li>节点下的<div class='hd'>子节点下的第一个<a>标签的href属性。使用BeautifulSoup里.find方法搜索符合调节的标签tag
。
也可以通过BeautifulSoup里.select方法,传入字符串参数,即可使用CSS选择器的语法找到标签
tag
,CSS选择器是一种单独的文档搜索语法,参考文档
#抓取每一个电影条目的网址链接
movie_hrefs=[]
def get_movie_href(u):
response = http_session.get(u,headers = headers)
soup = BeautifulSoup(response.text,'lxml')
movie_href = soup.find_all('div',class_='hd')
for i in movie_href:
movie_hrefs.append(i.find('a')['href'])
for url in urls:
get_movie_href(url)
提取所需电影信息
#提取每一部电影的所需信息,保存成字典格式,存储在all_movie列表中
all_movie=[]
def get_movie_info(url):
response = http_session.get(url,headers = headers)
soup = BeautifulSoup(response.text,'lxml')
movie = {}
info = soup.find('div',id='info').get_text()
for data in info.split('\n')[1:9]:
movie[data.split(':')[0]] = data.split(':')[1]
movie['电影名称']=soup.find('span',property="v:itemreviewed").text
movie['豆瓣评分']=float(soup.find('strong',property="v:average").text)
movie['豆瓣评论数']=int(soup.find('span',property="v:votes").text)
movie["r1"]=float(soup.find(text = re.compile('1星')).find_next(text = re.compile('%'))[:-1])*0.001
#找到包含‘1星’字符文档的所在节点之后包含‘%’字符的文档TEXT,示例为0.2%,将其转换成浮点型数字
movie["r2"]=float(soup.find(text = re.compile('2星')).find_next(text = re.compile('%'))[:-1])*0.001
movie["r3"]=float(soup.find(text = re.compile('3星')).find_next(text = re.compile('%'))[:-1])*0.001
movie["r4"]=float(soup.find(text = re.compile('4星')).find_next(text = re.compile('%'))[:-1])*0.001
movie["r5"]=float(soup.find(text = re.compile('5星')).find_next(text = re.compile('%'))[:-1])*0.001
all_movie.append(movie)
for href in movie_hrefs:
get_movie_info(href)
time.sleep(2)
将爬取到的信息保存至桌面存为CSV文件
df = pd.DataFrame(all_movie)
#转换成DataFrame格式以便后面分析
import os
os.chdir('C:\\Users\\Administrator\\Desktop')
df.to_csv('豆瓣TOP250电影信息.csv')
对爬取的信息进行分析
分析各地区TOP250电影数占比,哪个国家的电影最受欢迎
分析各电影类型TOP250电影数占比,哪个类型的电影最欢迎
分析top250电影,哪些导演的电影最多,评分较高
数据处理
- 由于爬取时已经筛选过数据,保证数据完整性,此处省略了数据清洗过程(缺失值处理,去除异常值)
首先提取每个地区的电影数量,由于有些电影是联合拍摄,同一部电影有多个地区参与。同理,同一部电影也有多种类型及多个导演。
#将爬取电影所有地区,类型,导演去重后导入列表
county_lst = []
for i in df['制片国家/地区'].str.replace(' ','').str.split('/'):
county_lst.extend(i)
county_lst = list(set(county_lst))
type_lst = []
for i in df['类型'].str.replace(' ','').str.split('/'):
type_lst.extend(i)
type_lst = list(set(type_lst))
dir_lst = []
for i in df['导演'].str.replace(' ','').str.split('/'):
dir_lst.extend(i)
dir_lst = list(set(dir_lst))
#判断各地区,各类型,各导演 影片个数,最高分影片及豆瓣评分
def f1(col,i):
data = {}
dfi = df[df[col].str.contains(i)]
data[col] = i
data['个数'] = len(dfi)
data['豆瓣最高分'] = dfi['豆瓣评分'].max()
data['最高分影片'] = dfi[dfi['豆瓣评分'] == dfi['豆瓣评分'].max()].iloc[0]['电影名称']
return(data)
data_county = []
for i in county_lst:
data_county.append(f1('制片国家/地区',i))
df_county = pd.DataFrame(data_county)
df_county.sort_values(by='个数',ascending = False,inplace = True)
data_type = []
for i in type_lst:
data_type.append(f1('类型',i))
df_type = pd.DataFrame(data_type)
df_type.sort_values(by='个数',ascending = False,inplace = True)
data_dir = []
for i in dir_lst:
data_dir.append(f1('导演',i))
df_dir = pd.DataFrame(data_dir)
df_dir.sort_values(by=['个数','豆瓣最高分'],ascending = False,inplace = True)
df_dir = df_dir[0:30]
#上映日期因为有不同地区的上映日期,已最早的上映日期为电影的实际上映年限
year = []
pattern = re.compile(r'\d{4}')
for i in df['上映日期'].str.findall(pattern):
year.append(min(i))
df['上映年限'] = year
绘制表格
- 各类型评分最高影片,看看和你心目中的榜单是否和豆瓣网友一致
-
各类型占比,可以看出大家基本偏爱剧情片,其次是爱情和喜剧
-
榜单上的导演都符合大家对知名导演的预期,豆瓣网友比较偏爱宫崎骏的动画片
-
刘镇伟导演的这3部影片,由于在国内影响深远,导致刘镇伟也在榜单中,其实他拍了许多烂片(笑)
-
各地区排行,可以看出美国所占比例遥遥领先,也由于其电影工业实力强大和起步早,其次是英国和日本
-
神作(好电影最多)频出的几年为1994,2010,2004,2010