Python小练:爬取豆瓣影评,看一部电影到底在讲什么?

每周养码场干货放送日

第 18 期

晚 20:00

?温馨提示:看到文末有彩蛋?

Python的强大,可能在于能做好玩的事情,比如知乎上有关python最火的回答,就是分享怎么用python画出世界名画的赶脚。

而今天,场主和大家分享的就是如何用 Python 制作网络爬虫,爬取豆瓣电影评论,并分析,最后制作豆瓣影评的云图。

就拿《复仇者联盟3:无限战争》这部电影为例吧。前段时间刷爆了场主的朋友圈,很多朋友不惜熬夜看首场,然后带着黑眼圈去上班。

那大家看复联3的时候,到底在看什么?什么是关键词?

根据下面分享的代码操作走,你会得到这样子一张图:

"灭霸"这个词,出现频率最高,可见反派灭霸不但得到了大家的喜欢,而且还是整部剧的焦点。

那如何用Python作出这张云图?且看下文猴哥的分享。

1、分析

先通过影评网页确定爬取的内容。我要爬取的是用户名,是否看过,五星评论值,评论时间,有用数以及评论内容。

然后确定每页评论的 url 结构。

第二页 url 地址:

第三页 url 地址:

点击查看大图

最后发现其中的规律:除了首页,后面的每页 url 地址中只有 start= 的值逐页递增,其他都是不变的。

2、数据爬取

本文爬取数据,采用的主要是 requests 库和 lxml 库中 Xpath。豆瓣网站虽然对网络爬虫算是很友好,但是还是有反爬虫机制。如果你没有设置延迟,一下子发起大量请求,会被封 IP 的。另外,如果没有登录豆瓣,只能访问前 10 页的影片。因此,发起爬取数据的 HTTP 请求要带上自己账号的 cookie。搞到 cookie 也不是难事,可以通过浏览器登录豆瓣,然后在开发者模式中获取。

我想从影评首页开始爬取,爬取入口是:https://movie.douban.com/subject/24773958/comments?status=P,然后依次获取页面中下一页的 url 地址以及需要爬取的内容,接着继续访问下一个页面的地址。

import jieba
import requests
import pandas as pd
import time
import random
from lxml import etree

def start_spider():
    base_url = 'https://movie.douban.com/subject/24773958/comments'
    start_url = base_url + '?start=0' 

    number = 1
    html = request_get(start_url) 

    while html.status_code == 200:
        # 获取下一页的 url
        selector = etree.HTML(html.text)
        nextpage = selector.xpath("//div[@id='paginator']/a[@class='next']/@href")
        nextpage = nextpage[0]
        next_url = base_url + nextpage
        # 获取评论
        comments = selector.xpath("//div[@class='comment']")
        marvelthree = []
        for each in comments:
            marvelthree.append(get_comments(each))

        data = pd.DataFrame(marvelthree)
        # 写入csv文件,'a+'是追加模式
        try:
            if number == 1:
                csv_headers = ['用户', '是否看过', '五星评分', '评论时间', '有用数', '评论内容']
                data.to_csv('./Marvel3_yingpping.csv', header=csv_headers, index=False, mode='a+', encoding='utf-8')
            else:
                data.to_csv('./Marvel3_yingpping.csv', header=False, index=False, mode='a+', encoding='utf-8')
        except UnicodeEncodeError:
            print("编码错误, 该数据无法写到文件中, 直接忽略该数据")

        data = []

        html = request_get(next_url)

我在请求头中增加随机变化的 User-agent, 增加 cookie。最后增加请求的随机等待时间,防止请求过猛被封 IP。

def request_get(url):
    '''
    使用 Session 能够跨请求保持某些参数。
    它也会在同一个 Session 实例发出的所有请求之间保持 cookie
    '''
    timeout = 3

    UserAgent_List = [
        "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36",
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36",
        "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2226.0 Safari/537.36",
        "Mozilla/5.0 (Windows NT 6.4; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2225.0 Safari/537.36",
        "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2225.0 Safari/537.36",
        "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2224.3 Safari/537.36",
        "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36",
        "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36",
        "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36",
        "Mozilla/5.0 (Windows NT 4.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.67 Safari/537.36",
        "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.67 Safari/537.36",
        "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.3319.102 Safari/537.36",
        "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.2309.372 Safari/537.36",
        "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.2117.157 Safari/537.36",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36",
        "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1866.237 Safari/537.36",
    ]

    header = {
        'User-agent': random.choice(UserAgent_List),
        'Host': 'movie.douban.com',
        'Referer': 'https://movie.douban.com/subject/24773958/?from=showing',
    }

    session = requests.Session()

    cookie = {
        'cookie': "你的 cookie 值",
    }

    time.sleep(random.randint(5, 15))  
    response = requests.get(url, headers=header, cookies=cookie_nologin, timeout = 3)
    if response.status_code != 200:
        print(response.status_code)
    return response

最后一步就是数据获取:

def get_comments(eachComment):
    commentlist = []
    user = eachComment.xpath("./h3/span[@class='comment-info']/a/text()")[0]  # 用户
    watched = eachComment.xpath("./h3/span[@class='comment-info']/span[1]/text()")[0]  # 是否看过
    rating = eachComment.xpath("./h3/span[@class='comment-info']/span[2]/@title")  # 五星评分
    if len(rating) > 0:
        rating = rating[0]

    comment_time = eachComment.xpath("./h3/span[@class='comment-info']/span[3]/@title")  # 评论时间
    if len(comment_time) > 0:
        comment_time = comment_time[0]
    else:
        # 有些评论是没有五星评分, 需赋空值
        comment_time = rating
        rating = ''

    votes = eachComment.xpath("./h3/span[@class='comment-vote']/span/text()")[0]  # "有用"数
    content = eachComment.xpath("./p/text()")[0]  # 评论内容

    commentlist.append(user)
    commentlist.append(watched)
    commentlist.append(rating)
    commentlist.append(comment_time)
    commentlist.append(votes)
    commentlist.append(content.strip())
    # print(list)
    return commentlist

3、制作云图

因为爬取出来评论数据都是一大串字符串,所以需要对每个句子进行分词,然后统计每个词语出现的评论。我采用 jieba 库来进行分词,制作云图,我则是将分词后的数据丢给网站 worditout 处理。

def split_word():
    with codecs.open('Marvel3_yingpping.csv', 'r', 'utf-8') as csvfile:
        reader = csv.reader(csvfile)
        content_list = []
        for row in reader:
            try:
                content_list.append(row[5])
            except IndexError:
                pass

        content = ''.join(content_list)

        seg_list = jieba.cut(content, cut_all=False)
        result = '\n'.join(seg_list)
        print(result)

最后制作出来的云图效果是:

赶紧实战吧!

爬一爬你喜欢的电影,大家的评论是怎样的,或者在制作过程中,你也会有新的创新和发现哦~

-END-

转载声明:本文转载自「极客猴」,若喜欢,可关注~

Bonus Time

最后送上一个彩蛋?!

近半年,场主邀请了360、有赞、环球黑卡等公司的技术大咖来社群进行直播分享,接下来场主还会邀请腾讯技术工程事业群(TEG)的技术大牛来给大家分享,至于分享哪方面的内容,场主把主动权交给你们~

大家可以投票选下自己感兴趣的方向哦,人数最多的方向先分享(确定方向后会进行细化)。有其他希望了解和学习交流的方向也欢迎留言告诉我们!

原文发布于微信公众号 - 养码场(yangmachang0)

原文发表时间:2018-06-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏机器学习和数学

[编程经验] 链家23个全国主要城市的现房数据分析

今天起来看到一个公众号发的推文,分析了链家上面成都的房价数据,自己好奇也玩了一把,收集了全国23个主要城市的在售房产数据,并作了对比,拿出来跟大家分享。涉及的城...

29830
来自专栏编程坑太多

requests爬虎牙频道和主播信息

19530
来自专栏GopherCoder

『Go 语言学习专栏』-- 第十五期

25040
来自专栏练小习的专栏

搞来两端模拟自由落体与抛物运动的JS玩

这里有更详细的讲解呵呵 http://www.cnblogs.com/cloudgamer/archive/2009/01/06/Tween.html 自由...

22680
来自专栏木子昭的博客

Django网页模板的继承include与复用extends

Django使用网页模板的方式分为两种, 一是建立代码块, 在新的页面导入代码块, 关键词为include 二是建立模板,新的页面在模板基础上扩充, 关键词为e...

20010
来自专栏coding

python爬虫抓取新浪微博数据

新浪微博的数据是用ajax异步下拉加载的,在chrome的调试模式下可捕捉到相应的请求:

4.2K50
来自专栏生信技能树

TCGA的28篇教程- 使用R语言的RTCGA包获取TCGA数据

前些天被TCGA的终结新闻刷屏,但是一直比较忙,还没来得及仔细研读,但是笔记本躺着的一些TCGA教程快发霉了,借此契机好好整理一下吧,预计二十篇左右的笔记

2.1K30
来自专栏极客猴

我爬取豆瓣影评,告诉你《复仇者联盟3》在讲什么?

复联 3 作为漫威 10 年一剑的收官之作。漫威确认下了很多功夫, 给我们奉献一部精彩绝伦的电影。自己也利用周末时间去电影院观看。看完之后,个人觉得无论在打斗特...

10530
来自专栏智能大石头

MF前传——探索者一号简介

    MF让我们这些C#程序员能够把手伸到嵌入式行业,大大增强我们在各种项目中的竞争能力。无奈国内研究MF的人少之又少,为了加速MF技术的研究,我们团队采用少...

21690
来自专栏数据小魔方

使用Python中的folium包创建热力密度图

最近探索出来一个在Python中创建热力图非常高效的方法,使用folium包来创建热力图,实际效果非常赞,过程简单,代码量少。

61120

扫码关注云+社区

领取腾讯云代金券