拉着你的手一起爬取+DIY豆瓣电影榜单

大家好。刚好近期没什么大片上映,是时候补一下今年上映过的电影了。

虽然是补片,但是也不能啥乱七八糟的电影都能看的。补之前先到比较权威的平台上参考一下评分排行榜。

到豆瓣中看下,但是豆瓣本身的排行榜并不符合我们要找2019年电影评分高且评分人数多的要求。

所以这次就由自己动手做排行榜找到靠谱的电影。

一. 数据准备

1. URL规律

众所周知,评论越多评分越高的,通常都是热度高且能激起大伙讨论的电影,所以我们就先从豆瓣评分排行榜上入手,将评分设置成7-10分,选择评分最高的。 

页面上一开始只显示前20名的榜单,在榜单下有个加载更多的按钮,点击后就会加载多20个排名。

我们可以通过右键检查来打开浏览器的开发者工具,不断点击加载更多,查看请求的url是否有什么规律

规律是url里的start字段从0-20-40-60,递增20。2019年所有7分以上电影加起来应该也不会有很多,所以我一口气将页面加载到最后,url中start=260,所以只需要爬取13页即可。

2. 页面请求解析

请求直接返回json格式数据,简直良心。

所以我们只需要在请求headers里面加上user-agent就稳了

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}

爬取排行榜页面的代码如下(使用pandas模块):

def parse_base_info(url,headers):
    response = requests.get(url,headers = headers)
    movies = json.loads(response.text)
    df = pd.DataFrame()
    if movies['data']:
        for m in movies['data']:
            m_id = m['id']  #ID
            title = m['title']  #片名
            directors = m['directors']  #导演
            casts = m['casts']  #主演
            rate = m['rate'] #评分
            star = m['star'] #标记人数
            url = m['url']  #网址
            cache = pd.DataFrame({'ID':[m_id],'片名':[title],'评分':[rate],'导演':[directors],'主演':[casts],'标记':[star],'网址':[url]})
            df = pd.concat([df,cache],ignore_index=True)
    else:
        return df
    return df

由于我们需要爬取的url不止一两个,所以需要循环爬取(不建议一次性爬取太多页,因为豆娘检测到然后屏蔽你的ip,我已经被屏蔽了):

movies_list = pd.DataFrame()

def format_url(num):
    urls = []
    base_url = 'https://movie.douban.com/j/new_search_subjects?sort=S&range=7,10&tags=%E7%94%B5%E5%BD%B1&start={}&year_range=2019,2019'
    for i in range(0,20 * num,20):
        url = base_url.format(i)
        urls.append(url)
    return urls

urls = format_url(15) ##15页

for url in urls:
    movies = parse_base_info(url,headers = headers)
    movies_list = pd.concat([movies_list,movies],ignore_index=True)
movies_list

执行后,movies_list就是7分以上的电影列表(包含电影ID、电影名称、主演、导演、评分、标记人数和具体网址):

考虑到使用pandas等数据处理分析模块,为了更有效的运行检验代码,所以建议安装使用 jupyter nootbook ,可以很直观的展示DataFrame数据。

pip install jupyter
#安装后执行
jupyter nootbook

3. 电影详情爬取

我们打开单部电影的网址,直接右键,查看源代码,看看我们想要的字段在不在源代码中:

wonderful,导演、主演、类型等等字段都在。

当然,你也可以直接在开发者工具查找元素。

由于字段值都在页面标签中,所以这里直接用xpath来解析:

# url = 'https://movie.douban.com/subject/27119724/'
def parse_movie_info(url,headers=headers):
    html = requests.get(url,headers = headers)

    bs = etree.HTML(html.text)
    #片名
    title = bs.xpath('//div[@id = "wrapper"]/div/h1/span')[0].text
    #上映时间
    year = bs.xpath('//div[@id = "wrapper"]/div/h1/span')[1].text.strip('(|)')
    #电影类型
    m_type = []
    for t in bs.xpath('//span[@property = "v:genre"]'):
        m_type.append(t.text)
        
    a = bs.xpath('//div[@id= "info"]')[0].xpath('string()')
    #片长
    m_time =a[a.find('片长: ') + 4:a.find('\n        又名')]  #时长
    #地区
    area = a[a.find('制片国家/地区:') + 9:a.find('\n        语言')]  #地区
    #评分人数
    try:
        people = bs.xpath('//a[@class = "rating_people"]/span')[0].text
    #评分分布
        rating = {}
        rate_count = bs.xpath('//div[@class = "ratings-on-weight"]/div')
        for rate in rate_count:
            rating[rate.xpath('span/@title')[0]] = rate.xpath('span[@class = "rating_per"]')[0].text
    except:
        people = 'None'
        rating = {}
    #简介
    try:
        summary = bs.xpath('//span[@property = "v:summary"]')[0].text.strip('\n \u3000\u3000')
    except:
        summary = 'None'
    try:
        hot_comment = bs.xpath('//div[@id = "hot-comments"]/div/div/p/span')[0].text
    except:
        hot_comment = 'None'
    cache = pd.DataFrame({'片名':[title],'上映时间':[year],'电影类型':[m_type],'片长':[m_time],
                          '地区':[area],'评分人数':[people],'评分分布':[rating],'简介':[summary],'热评':[hot_comment],'网址':[url]})
    return cache

接着循环爬取每个电影详情页面,存到movie_info中:

##爬单个电影页面
movie_info = pd.DataFrame()
count = 1
zip1 = zip(movies_list['网址'],movies_list['片名'])
for url,name in zip(movies_list['网址'],movies_list['片名']):
    try:
        print(url,name)
        cache = parse_movie_info(url,headers = headers)
        movie_info = pd.concat([movie_info,cache],ignore_index=True)
    except:
        continue

会得到爬取结果:

二. 数据处理

1. 合并

movies_list表里面是我们批量抓取的电影列表,movie_info则是我们进入每一部电影,获取到的感兴趣字段汇总,后面的分析是需要依赖两张表进行的,所以我们合并之:

 

2. 评分分布

将评分分布按照页面上的星级展示会酷炫很多:

def get_rate(x,types):
    try:
        return float(x[types].strip('%'))
    except:
        pass
    
movie_merge['5星'] = movie_merge['评分分布'].apply(get_rate,types = '力荐')
movie_merge['4星'] = movie_merge['评分分布'].apply(get_rate,types = '推荐')
movie_merge['3星'] = movie_merge['评分分布'].apply(get_rate,types = '还行')
movie_merge['2星'] = movie_merge['评分分布'].apply(get_rate,types = '较差')
movie_merge['1星'] = movie_merge['评分分布'].apply(get_rate,types = '很差')

3. 数值类型转换

由于接下来需要使用评分人数字段值来进行筛选排序,但是这个字段值是object,无法比较筛选排序,所以这里强制转换

# 先筛选掉评分人数为None的电影再强制转换为int
movie_merge = movie_merge.loc[movie_merge['评分人数'] != 'None',:]
movie_merge['评分人数'] = movie_merge['评分人数'].astype(int)

movie_merge.info()

最终排行榜单:

三. 绘制词云

到了这一步就可以将上面的数据稍微分析一下后展示了。

评分人数超过1000人,按情况来说电影不算太小众了,评分也是比较能相信的。

name = movie_merge.loc[movie_merge['评分人数'] >= 1000,'片名_x'].values
value = movie_merge.loc[movie_merge['评分人数'] >= 1000,'评分'].values

获取评分人数超过1000的电影名字以及评分,以便接下来的词云展示。

from pyecharts import WordCloud

names = []
# zip()将对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
for n,v in zip(name,value):
    n = n + ' ' + str(v)
    names.append(n)
myWordCloud = WordCloud(width=1000, height=500)
myWordCloud.add("",attr = names,value = value,word_size_range=[20,30],shape = 'circle')
myWordCloud

一个很有料的词云的出现了:

还可以通过pandas的to_execl()方法导出爬取到的电影数据。

有兴趣的同学可以另外获取电影其他详细字段,然后从其他角度进行分析,pandas模块功能强大,matplotlib模块绘图高级,pyecharts绘图多样风骚。

完整代码在后台回复 douban 获取,有什么要求请求需求也可留言。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值