Scrapy-Jieba-WordCloud-Matplotlib从爬取数据到生成图表
目标
这个小项目的目的就是通过完成从爬取数据到分析数据一整个流程的工作,来对所需要用到的工具进行学习。
整个流程大致步骤为:
- 使用scrapy对网站进行爬取,获得每一条短评内容和日期
- 使用jieba分词对短评内容进行分词
- 使用wordcloud根据分词后的数据生成词云图
- 对短评的发表日期进行统计
- 使用matplotlib生成短评发表日期的线状图
在一切开始之前顺带提一句,本次使用的是python3.
Scrapy
Scrapy是一个开源合作的网页数据抽取框架。快速简单且延展性强。(官网介绍)
安装使用
通过pip安装是最简单的办法。只要在安装python时有同时安装pip就可以通过这个途径安装。
安装办法就是使用命令行,输入:
pip install scrapy
以下的其他包也是通过同样途径进行安装。但是需要提到的是,这个安装途径在下载安装包时不支持断点续传,也就是说如果在下载途中网络报错就要重来。在网络出问题的时候,可能会反复遇到网络报错导致无法下载。这时可以复制pip安装时控制台打印出的下载地址,通过浏览器或者下载工具进行下载。下载完成后,控制台cd到下载好的whl文件所在位置,然后输入:
pip install xxxx.whl
生成项目
Scrapy可以通过命令行命令快速生成项目。只需要在控制台cd到想要创建项目的文件夹,然后输入:
scrapy startproject project_name
输入命令之后在目标文件夹就会生成一个项目。项目内有多个py文件。下面是需要改动以达成目的的py文件的介绍。
items
项目items的定义文件。在这个文件里可以定义项目中的items的内容,用于存储爬取到的数据。
但在本项目中,一个item只要有评论和日期两项就够了。
import scrapy
class commentItem(scrapy.Item):
date = scrapy.Field()
comment = scrapy.Field()
pipelines
pipelines是用于定义爬取到的数据如何处理。数据被爬取后整理为多个item,然后被移交至pipeline这里进行后续处理。
在本项目中,pipeline负责将items存到txt文件中。
import os
class ScrapyspiderPipeline(object):
def process_item(self, item, spider):
base_dir = os.getcwd()
fileName_1 = base_dir + 'shawshank_douban_comment.txt'
fileName_2 = base_dir + 'shawshank_douban_date.txt'
with open(fileName_1,'a') as fp:
fp.write(item['comment'])
with open(fileName_2,'a') as fp:
fp.write(item['date'])
return item
需要注意的是,在pipelines.py文件自动生成的注释中也有提到,要在settings文件中增添pipeline的信息。
settings
设置文件,在这个文件中对爬虫进行各式各样的设置。比如上面说到的增添pipeline的信息:
# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
'scrapySpider.pipelines.ScrapyspiderPipeline': 300,
}
另外还有,在爬取时为了防止爬取请求频率过高触发网站反爬虫机制,需要让爬虫的爬取间歇性暂停,也可以在settings文件中设置:
DOWNLOAD_DELAY = 2
RANDOMIZE_DOWNLOAD_DELAY = True
另外还可以设置请求的user-agent:
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
还有是否遵守网站的robot规则:
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
spider
最后是爬虫的主体,这个文件不是跟随项目自动生成的,而是我们自己写的。
# -*- coding: utf-8 -*-
from scrapy import Request
import scrapy
from scrapySpider.items import commentItem
import jieba
class DoubanSpider(scrapy.Spider):
name = 'douban'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36',
}
def start_requests(self):
return [scrapy.FormRequest('https://accounts.douban.com/login', formdata={'form_email': 'username', 'form_password': 'password', 'login': '登录'}, callback = self.logged_in)]
def logged_in(self, response):
yield Request('https://movie.douban.com/subject/1292052/comments', callback = self.parse)
def parse(self, response):
item = commentItem()
comments = response.xpath('//div[@class="comment"]')
for comment in comments:
item['date'] = comment.xpath('.//span[@class="comment-time "]/text()').extract()[0][21:32]
item['comment'] = comment.xpath('.//span[@class="short"]/text()').extract()[0]+"\n"
yield item
next_url = response.xpath('//a[@class="next"]/@href').extract()
if next_url:
next_url = 'https://movie.douban.com/subject/1292052/comments' + next_url[0]
yield Request(next_url, headers=self.headers)
在这个文件中定义了本次项目的爬虫‘DoubanSpider’类,它继承自scrapy.spider类。类成员属性有它的名字name=‘douban’,这个名字会用于启动它。
爬虫的成员方法包括:
- start_requests:用于发起请求
- logged_in:用于登录,这在本个项目中需要用到,因为豆瓣短评只允许查看前十页,要登录后才能查看全部。这个方法用于模拟登录。发送的formdata的数据名‘form_email’和‘form_password’是在豆瓣登录页面查的。在豆瓣进行一次登录然后在开发者工具看它发出的postrequest的数据即可。
- parse:这个方法用于解析爬取到的页面。在logged_in函数中设置的回调函数就是它。
使用xpath对页面的内容进行抽取,获得短评内容和日期,并整理为item
最后在页面中获取下一页的url,并把url提交给scheduler。
启动爬虫
在控制台cd到爬虫项目所在文件位置,然后输入:
scrapy crawl douban
即可启动爬虫。‘douban’就是爬虫主体中的name属性的值。
在爬虫运行结束后,就可以获得两个存储了爬取到的数据的txt文件。
爬虫的工作就到此结束。
Jieba
结巴分词,是用于将短评内容进行分词,以便下一步统计词频生成词云。
结巴是现成的包,只要和scrapy一样通过pip安装然后在py文件中import就可以使用了。
pip install jieba
结巴分词有多种分词模式:
- jieba.cut 方法接受三个输入参数: 需要分词的字符串;cut_all 参数用来控制是否采用全模式;HMM 参数用来控制是否使用 HMM 模型
- jieba.cut_for_search 方法接受两个参数:需要分词的字符串;是否使用 HMM 模型。该方法适合用于搜索引擎构建倒排索引的分词,粒度比较细
待分词的字符串可以是 unicode 或 UTF-8 字符串、GBK 字符串。注意:不建议直接输入 GBK 字符串,可能无法预料地错误解码成 UTF-8 - jieba.cut 以及 jieba.cut_for_search 返回的结构都是一个可迭代的 generator,可以使用 for 循环来获得分词后得到的每一个词语(unicode),或者用
- jieba.lcut 以及 jieba.lcut_for_search 直接返回 list
- jieba.Tokenizer(dictionary=DEFAULT_DICT) 新建自定义分词器,可用于同时使用不同词典。jieba.dt 为默认分词器,所有全局分词相关函数都是该分词器的映射。
不过这次就只需要用到最简单的jieba.cut,将短评切分即可。
cut方法接收两个参数,第一个是需要被分词的字符串,第二是切分模式。模式有全模式和精确模式两种。全模式会将字符串中所有可能的词语都输出。比如“我来到北京清华大学”,全模式会输出“我/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学”,而精确模式只会输出“我/ 来到/ 北京/ 清华大学”。
本个项目选用精确模式。
WordCloud
词云也是现成的通过pip安装的包。只需要调用generate方法传入切好词的字符串,就能自动生成词云图。
text_from_file=open('scrapySpidershawshank_douban_comment.txt','r').read()
Word_spilt_jieba = jieba.cut(text_from_file,cut_all = False)
word_space = ' '.join(Word_spilt_jieba)
my_wordcloud = WordCloud(
background_color='white', #设置背景颜色
mask=img, #背景图片
max_words = 200, #设置最大显示的词数
stopwords = STOPWORDS, #设置停用词
#设置字体格式,字体格式 .ttf文件需自己网上下载,最好将名字改为英文,中文名路径加载会出现问题。
font_path = 'DFPKingGothicGB-Thin-2.ttf',
max_font_size = 100, #设置字体最大值
random_state=50, #设置随机生成状态,即多少种配色方案
).generate(word_space)
Matplotlib
这个包是用于绘制图表的。首先是将Wordcloud生成的词云图绘制出来。
import matplotlib.pyplot as plt
plt.imshow(my_wordcloud)
plt.axis('off')
plt.show()
可以看到,关于《肖申克的救赎》这部电影,短评最常提及的关键词除了“电影”“自己”这些没有意义的词外,就是“希望”“经典”“自由”。
下一步就是根据日期文件绘制线状图。
year = [2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018]
ycount = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
month = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
mcount = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
dates = open('scrapySpidershawshank_douban_date.txt').readlines()
for date in dates:
y = int(date[0:4])-2005
ycount[y] = ycount[y]+1
m = int(date[5:7])
mcount[m-1] = mcount[m-1]+1
pyplot.rcParams['font.sans-serif']=['SimHei']
pyplot.plot(year, ycount)
pyplot.xlabel('年')
pyplot.ylabel('短评数')
pyplot.title('《肖申克的救赎》每年短评数量')
pyplot.yticks([0, 20, 40, 60, 80, 100])
pyplot.xticks([2005, 2007, 2009, 2011, 2013, 2015, 2017, 2018])
pyplot.show()
pyplot.plot(month, mcount)
pyplot.xlabel('月份')
pyplot.ylabel('短评数')
pyplot.title('《肖申克的救赎》短评发表月份统计')
pyplot.yticks([0, 20, 40, 60, 80, 100])
pyplot.xticks([2, 4, 6, 8, 10, 12])
pyplot.show()
首先是读日期文件,统计短评的年份和月份,存储为两个数组。然后使用pyplot根据这两个数组分别绘制线状图,设置横竖坐标名称和刻度。pyplot就能绘制出相应的图表。
可以看出,《肖申克的救赎》从2005年以来一直到2015年,热度缓慢上升,在2010年至2012年到达高峰,然后逐渐下落。但是后来在2017年短评数量却突然爆发式地増长。
而短评发布的月份来看,总体还算平均,大致是前半年稍微多一些。
结束
这个项目到此就结束了。十分简单的一个项目,大部分过程都是使用现有的包达成目的。对数据的分析也不算是十分复杂,但得到的结果还算是比较有趣的。
作者:TaylorFall
来源链接:https://blog.csdn.net/weixin_38966732/article/details/84678494