在八月上旬,爬取了13万电影数据和28万影评数据,并在后续的日子中对13万豆瓣电影做了系统的分析,并根据电影数据构建知识图谱,建立QA问答系统。近期,查看评论数据的时候发现,数据严重缺失,每个电影最多只有5条评论,同时缺少评论评分的字段,为此重新修改了爬虫模型,并重新爬取了350万的评论数据。本文,主要除了介绍评论的爬取方法以外,还对评论做了初步的分析,方便后续的实践工作。
系列文章:
- 13万豆瓣电影数据爬取原理剖析
- 豆瓣13万电影数据统计与分析
- 基于豆瓣电影数据构建知识图谱
- 基于知识库与知识图谱构建电影问答系统
评论数据爬取原理
评论数据的爬取是基于Scrapy框架的,本次修改的主要地方是将之前的爬虫API链接改成了评论详情页https://movie.douban.com/subject/26709258/comments?status=P
,如Fig 1所示:
Fig 1. 豆瓣电影评论详情页
通过F12我们可以清楚的看到这个评论的源码细节,每条comment的都是在一个div里面,并且div的class为comment-item,如Fig 2所示。
Fig 2. 豆瓣电影评论详情页
对于这种有规律的html页面,使用scrapy进行处理真的太方便了,我们可以先把comment-item匹配出来,得到的是一个list,然后通过遍历这个list,将每条评论的细节信息抠出来,提取的信息包括:用户名、用户url、用户头像图片url、投票数、评分数、评论内容、评论ID、豆瓣电影ID。提取评论的核心匹配代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| item_regx = '//div[@class="comment-item"]' comment_item_list = response.xpath(item_regx).extract()
if len(comment_item_list) > 1: for resp_item in comment_item_list: print("resp_item======:",resp_item) resp_item = etree.HTML(resp_item)
url_regx = '//div[@class="avatar"]/a/@href' url_list = resp_item.xpath(url_regx)
username_regx = '//div[@class="avatar"]/a/@title' username_list = resp_item.xpath(username_regx)
avator_regx = '//div[@class="avatar"]/a/img/@src' avator_list = resp_item.xpath(avator_regx) vote_regx = '//div[@class="comment"]/h3/span/span[@class="votes"]/text()' vote_list = resp_item.xpath(vote_regx)
rating_regx = '//div[@class="comment"]/h3/span[@class="comment-info"]/span[contains(@class,"allstar")]/@class' rating_list = resp_item.xpath(rating_regx)
comment_regx = '//div[@class="comment"]/p/span[@class="short"]/text()' comment_list = resp_item.xpath(comment_regx)
comment_id_regx = '//div[@class="comment"]/h3/span/input/@value' comment_id_list = resp_item.xpath(comment_id_regx)
comment = Comment() comment['douban_id'] = douban_id comment['douban_comment_id'] = comment_id_list[0] if len(comment_id_list) > 0 else "" comment['douban_user_nickname'] = username_list[0] if len(username_list) > 0 else "" comment['douban_user_avatar'] = avator_list[0] if len(avator_list) > 0 else "" comment['douban_user_url'] = url_list[0] if len(url_list) > 0 else "" comment['content'] = comment_list[0] if len(comment_list) > 0 else "" comment['votes'] = vote_list[0] if len(vote_list) > 0 else "" comment['rating'] = rating_list[0] if len(rating_list) > 0 else "" yield comment
|
当我们提取万当前页面之后,还需要找到下一页,如果存在下一页评论,就将下一页放入到Scrapy的Downloader里面,依次循环。这里说一下,由于在没登录状态下,豆瓣只允许翻100页,所以最后电影数据里面每部电影最多的也就220条。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #下一页 regx = '//a[@class="next"]/@href' next_url = response.xpath(regx).extract()
if len(next_url)>0: url = "https://movie.douban.com/subject/%s/comments%s" %(douban_id, next_url[0]) print("=====request Next url================:", url) bid = ''.join(random.choice(string.ascii_letters + string.digits) for x in range(11)) cookies = { 'bid': bid, 'dont_redirect': True, 'handle_httpstatus_list': [302], } yield Request(url, cookies=cookies,meta={'main_url':url})
|
编写完上面的爬虫逻辑之后,配置好代理,启动程序,最后一晚上爬取了350万数据,差不多1G。样例数据如Fig 3所示:
Fig 3. 豆瓣电影评论样例数据
评论数据分析
爬取到这么多数据,到底有多少可以用呢?为此笔者对数据进行了简单的探索。在笔者爬取的数据中,存在评论的电影数有7w+部,评论的用户数量有39w+,电影评论总数有350w+。 当然并不是所有的评论都是有效的,长度大于5的评论只有314w,大部分评论都是在30以内,属于短评数据。
这份数据,对于笔者来说,价值还是蛮大的,比如rating评分字段。虽然我们的数据有350w,但是带有rating的数据只有327w+,少了23w+。在这327w的评分里面,由于每部电影最多只能爬取220条,为此笔者对这份数据进行了统计,如Fig 4所示:
Fig 4. 豆瓣评分分布图
整体上与我们的猜想差不多,呈现一个类似正太分布的图,两端小中间大。通过这部分数据统计,笔者也更加有信心相信这份评论具有代表性。相当于从每部电影里面采样数据,然后得到这些评论,数据量大,基本上也就接近实际的评论分布了。顺手做了张评论词云,没有去掉停留词(看起来没啥感觉),先凑合吧。
Fig 5. 豆瓣评论词云
最后爬取的数据量如Fig 6所示。
Fig 6. 豆瓣电影与爬虫数据量截图
结束语
OK,关于豆瓣评论数据的细节到此为止吧,具体的源码已经上传到笔者的Github中:https://github.com/csuldw/AntSpider,如有需要的,可以参考下,爬虫代码注释还需进一步完善,读者如有任何疑问可以关注下我的公众号【斗码小院】,如需要电影与影评数据的,在公众号中留言即可(13万电影+7万演员+350万影评数据,花重金买代理爬的数据,实在是不忍心一下子就分享出来哇,各位见谅!!!)。
References
- https://github.com/csuldw/AntSpider
- http://www.csuldw.com/2019/08/18/2019-08-18-building-knowledge-graph-based-on-douban-movie-data/
- http://www.csuldw.com/2019/08/12/2019-08-12-douban-movies-statistics/
- http://doc.scrapy.org/en/latest/topics/architecture.html