简介
最近看微信公众号上好多文档关于豆瓣上电影的影评分析的,感觉挺有意思的,就拿《琅琊榜2》也来尝试下。本文主要是使用scrapy爬取豆瓣上的《琅琊榜2》的话题讨论区并用作词云展示。至于为什么使用scrapy,主要是之前使用过python的beautifulsoup、selenium等模块,各个功能都是自己写的,不是很系统,而scrapy作为爬虫框架内置css、xpath且异步抓取,效率很高。
实现
一、爬取豆瓣话题title
1.准备python环境
当然还是使用conda,之前博文中提到过很多次,在此不必多说。
mkdir -p /home/yanggd/scrapy
cd /home/yanggd/scrapy
conda create -n scrapy
#切换至scrapy虚拟环境中
source activate scrapy
2.安装scrapy
具体安装可见官方文档”https://docs.scrapy.org/en/latest/intro/install.html”
conda install -c conda-forge scrapy
3.创建scrapy项目
scrapy startproject douban
4.创建爬虫
cd douban
scrapy genspider langyabang movie.douban.com
创建后会在douban目录下生成douban子目录,在douban/spiders/下查看生成的初始化爬虫
vim douban/spiders/langyabang.py
# -*- coding: utf-8 -*-
import scrapy
class LangyabangSpider(scrapy.Spider):
name = 'langyabang'
allowed_domains = ['movie.douban.com']
start_urls = ['https://movie.douban.com']
def parse(self, response):
pass
5.编写爬虫脚本
vim douban/spiders/langyabang.py
# -*- coding: utf-8 -*-
import scrapy
class LangyabangSpider(scrapy.Spider):
name = 'langyabang'
allowed_domains = ['movie.douban.com']
start_urls = ['https://movie.douban.com/subject/26665065/discussion/']
def parse(self, response):
for comment in response.xpath("//a[@title]/text()").extract():
yield {
'title': comment.strip().encode('utf-8')
}
#next_page = response.xpath("//div[@class='paginator']/a/@href").extract_first()
next_page = response.xpath("//div[@class='paginator']/span[@class='next']/a/@href").extract_first()
if next_page is not None:
yield response.follow(next_page, callback=self.parse)
说明:
name 是我们爬虫的名字
start_urls 是我们需要爬取的话题讨论区的起始页
response.xpath(“//a[@title]/text()”).extract() 我们提取的是每个话题的title
comment.strip().encode(‘utf-8’) 会对抓取的title内容进行去除空间或换行等操作
response.xpath(“//div[@class=’paginator’]/span[@class=’next’]/a/@href”).extract_first() 我们提取的是下一页的链接,是一个相对url,用于跳转页面
response.follow(next_page, callback=self.parse) 会根据当前的url和下一页的链接进行跳转
6.运行爬虫
scrapy crawl langyabang -o langyabang.json
但我们运行后,打印信息会有以下提示:
2017-12-27 08:30:28 [scrapy.core.engine] INFO: Spider opened
2017-12-27 08:30:28 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2017-12-27 08:30:28 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6024
2017-12-27 08:30:28 [scrapy.core.engine] DEBUG: Crawled (403) <GET https://movie.douban.com/robots.txt> (referer: None)
2017-12-27 08:30:28 [scrapy.core.engine] DEBUG: Crawled (403) <GET https://movie.douban.com/subject/26665065/discussion/> (referer: None)
2017-12-27 08:30:28 [scrapy.spidermiddlewares.httperror] INFO: Ignoring response <403 https://movie.douban.com/subject/26665065/discussion/>: HTTP status code is not handled or not allowed
爬虫返回的状态码为403,看来豆瓣对user_agent进行了相关设置,scpray默认的user_agent为#USER_AGENT = ‘douban (+http://www.yourdomain.com)’,如此看来我们需要将爬虫的useragent改以下,有两种方案:一是改成固定的,二是改成随机的。请参考scrapy随机更改User-Agent方法
我们此次为了方便,改成固定的了,如下:
vim douban/settings.py
USER_AGENT = 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)'
再次运行爬虫,我们发现爬虫的内容不是汉字,究其原因由官方文档解释:
FEED_EXPORT_ENCODING
Default: None
The encoding to be used for the feed.
If unset or set to None (default) it uses UTF-8 for everything except JSON output, which uses safe numeric encoding (\uXXXX sequences) for historic reasons.
Use utf-8 if you want UTF-8 for JSON too.
竟然是除了json外,其他格式都用utf-8编码,因此我们需要再次设置:
vim douban/settings.py
FEED_EXPORT_ENCODING='utf-8'
ok,至此我们再运行爬虫,发现可以正常爬取了。
scrapy crawl langyabang -o langyabang.json
vim langyabang.json
[
{"title": "反派好强大啊,希望编剧能驾驭住"},
{"title": "15集 精妙的布局与破局"},
{"title": "为什么不用原音?好像所有演员都是配音"},
{"title": "看到六集,关于本剧的年轻演员"},
{"title": "林奚怎么发现妆盒的问题的"},
{"title": "原来教主第二十七集领盒饭"},
{"title": "有人萌老皇帝吗"},
{"title": "孔导的访谈!!信息量挺大!都进来看看!!萧平章..."},
{"title": "打完一星之後就滾蛋好嗎?都棄劇了還嗶嗶嗶…"},
{"title": "[第15集] 15集最后元启烧信"},
{"title": "看到第二集就不想看了。。。"},
{"title": "难道充vip看剧有罪吗,冲vip就得去死么???"},
{"title": "在这儿推荐下隔壁《端脑》。。良心漫改剧"},
{"title": "庭生的真实身份会不会被挖出来?"},
{"title": "林怼怼?与寒潭小神龙?小神龙的日常"},
{"title": "平章估计是誉王的后人....元启的升级太突然太生硬。"},
{"title": "变宫斗剧了?"},
{"title": "荀大统领的萌点"},
{"title": "萧元启的父亲究竟是怎么死的"},
{"title": "萧平章八成是誉王遗腹子的儿子!"},
{"title": "[第16集] 平旌像被调戏的小媳妇似的委屈脸迅速拉上..."},
{"title": "有人說8.3分是水軍刷出來的…"},
{"title": "已被卡粉梅长苏圈粉"},
{"title": "这个分数我感觉是刷的"},
{"title": "真的别把差评都推在胡椒头上了"},
{"title": "这剧太烂了,看不下去"},
{"title": "胡歌和《琅琊榜》是互相成就的,所以别互黑了。。"},
{"title": "含着一只苍蝇吃一桌好菜"},
{"title": "萧平旌的武力值到底有多高啊?"},
......
......
至此我们的爬虫已经完成了工作,下一步我们是根据爬取的内容生成词云。
二、生产词云
我们根据我以前的博文python生成词云,因此我们需要提前准备关键词文本、中文字体及一张图片。
1.准备
关键词来源于我们爬取的title,但我们使用的是json格式,因此需要换成csv格式
scrapy crawl langyabang -o langyabang.csv
中文字体我们使用simsun.ttc
图片我们在网上随便找了一张
因此,我们词云的准备如下:
.
└── wordcloud
├── langyabang.csv
├── langyabang.jpg
├── langyabang_new.jpg
├── langyabang.py
└── simsun.ttc
其中langyabang_new.jpg是基于langyabang.jpg生成的词云图片
2.编写脚本
vim langyabang.py
#!/home/yanggd/miniconda2/envs/wordcloud/bin/python
#-*- coding: utf-8 -*-
from os import path
from PIL import Image
from wordcloud import WordCloud
import numpy as np
import matplotlib.pyplot as plt
import jieba
#读取脚本所在目录
mulu = path.dirname(__file__)
#从文本中生成关键词
csv = open(path.join(mulu, 'langyabang.csv')).read()
seg_list = jieba.cut(csv, cut_all=True)
seg_split = " ".join(seg_list)
#读取图片
wordcloud_mask = np.array(Image.open(path.join(mulu, "langyabang.jpg")))
#字体位置
font = path.join(mulu, 'simsun.ttc')
#设置图片属性
wc = WordCloud(font_path=font, background_color="white", max_words=1000, mask=wordcloud_mask, max_font_size=50)
wc.generate(seg_split)
#生成新的图片
wc.to_file(path.join(mulu, "langyabang_new.jpg"))
#图片展示
plt.imshow(wc, interpolation='bilinear')
plt.axis("off")
plt.show()
3.运行脚本
python langyabang.py
生成图片: