python的requests_html库和词云分析2018政府工作报告全文

627 阅读6分钟

用掘金半年多了,但是从来都没有写过文章,最近刚好有时间加上手痒痒所有就有了这第一篇掘金文章。

刚好最近在开十九大,2018政府工作报告全文出来了,在凤凰网能细细研读。作为一个程序员,怎么能忍受看那么多中文呢!所以果断来搞事啊!

思路大概就是:使用最近刚发布的for humans的requests_html库获取到报告全文,然后使用jieba来进行分词把分好的词就可以用wordcloud来做词云了。

1. 获取数据

百度关键字 2018政府工作报告 可以发现有很多,链接我就打出来了news.ifeng.com/a/20180305/… 那我们就来看看网页结构吧!

网页的html结构
划出重点了(懒人可以对着那一堆中文右键copy→copy xpath 一键获取xpath路径),获取到路径之后我们就可以愉快的使用chrome的xpath插件来查看路径对不对了(当然如果你想用beautifulsoup的话就是div#main_content p,个人不推荐用beautifulsoup,毕竟解析速度摆在那了)。

但是我们也需要注意,最后一个不是报告的内容,等会在代码里面处理就好了。

好了,获取到了我们就开始开心的写代码吧!

session= HTMLSession()
response= session.get(url)
report_text= response.html.xpath('//*[@id="main_content"]/p/text()')[:-1] if response.htmlis not None else 'NULL'
print(report_text)

上面这个图片就是返回的list,然后我们遍历一下取出全部数据后拼接返回给jieba分词。

def get_info(url):
    report= ''
    session= HTMLSession()
    response= session.get(url)
    report_text= response.html.xpath('//*[@id="main_content"]/p/text()')[:-1] if response.htmlis not None else 'NULL'
    print(report_text)
    for iin report_text:
        report+= i
    return report

2. jieba分词

分词其实很简单,只需要下面这一行代码就可以实现了。

words= [wordfor wordin jieba.cut(report,cut_all=True) if len(word) >= 2]

cut方法参数:(分词的字符串,cut_all是否打开全模式),全模式的意思就是会把一个词前后断句,比如:大傻逼,会分词成:大傻,傻逼和大傻逼 另外这里还做了下判断,长度大于等于2才算一个词。运行下把分词后list遍历下。

到了这里我突然想看一下高频词到底有哪些,所以用了一下collections的Count来计算一下

c = Counter(words)
for word_freq in c.most_common(10):
    word, freq = word_freq
    print(word, freq)

选出频率前10的词,于是得到了下面图片的数据

3.生成词云

python生成词云当然是用wordcloud,wordcloud是基于matplotlib的专门生成词云的库。

用这个库最关键的就是WordCloud构造函数:

参数详解:

font_path:字体路径,就是绘制词云用的字体,比如monaco.ttf

width:输出的画布宽度,默认400像素

height:输出的画布宽度,默认200像素

margin:画布偏移,默认2像素

prefer_horizontal: 词语水平方向排版出现的频率,默认0.9,垂直方向出现概率0.1

mask:如果参数为空,则使用二维遮罩绘制词云。如果 mask 非空,设置的宽高值将被忽略,遮罩形状被 mask,除全白(#FFFFFF)的部分将不会绘制,其余部分会用于绘制词云。如:bg_pic = imread('读取一张图片.png'),背景图片的画布一定要设置为白色(#FFFFFF),然后显示的形状为不是白色的其他颜色。可以用ps工具将自己要显示的形状复制到一个纯白色的画布上再保存,就ok了。

scale:按照比例进行放大画布,如设置为1.5,则长和宽都是原来画布的1.5倍

color_func:生成新颜色的函数,如果为空,则使用 self.color_func

max_words:显示的词的最大个数

min_font_size:显示的最小字体大小

stopwords:需要屏蔽的词(字符串集合),为空使用内置STOPWORDS

random_state:如果给出了一个随机对象,用作生成一个随机数

background_color:背景颜色,默认为黑色

max_font_size:显示的最大的字体大小

font_step:字体步长,如果步长大于1,会加快运算但是可能导致结果出现较大的误差

mode:当参数为"RGBA",并且background_color不为空时,背景为透明。默认RGB

relative_scaling:词频和字体大小的关联性,默认5

regexp:使用正则表达式分隔输入的文本

collocations:是否包括两个词的搭配

colormap:给每个单词随机分配颜色,若指定color_func,则忽略该方法

normalize_plurals:是否删除尾随的词语

常用的几个方法:

fit_words(frequencies) //根据词频生成词云

generate(text) //根据文本生成词云

generate_from_frequencies(frequencies[, ...]) #根据词频生成词云

generate_from_text(text) #根据文本生成词云

process_text(text) #将长文本分词并去除屏蔽词(此处指英语,中文分词还是需要自己用别的库先行实现,使用上面的 fit_words(frequencies) )

recolor([random_state, color_func, colormap]) # 对现有输出重新着色。重新上色会比重新生成整个词云快很多。

to_array() #转化为 numpy array

to_file(filename) #输出到文件

看到这里是不是懵了?反正我是看懵了,算了,直接写吧!

在这里我遇到了中文生成词云只出现框框没有字的bug!!!

path = r'simfang.tff'

查了一下路径要写成这样要不然会出现OSError: cannot open resource 的问题。 所以就有了下面的的代码

def word_cloud(word):
    path= r'C:\Windows\Fonts\simfang.ttf'  # 字体路径
    bg_pic= imread(r'D:\blog\20160303160528046.png')  # 读取模板图片
    image_colors= ImageColorGenerator(bg_pic)  # 从模板图片生成颜色值
    wc= WordCloud(font_path=path,
                  background_color="white",
                  mask=bg_pic,
                  stopwords=STOPWORDS.add("said"),
                  max_font_size=500,
                  color_func=image_colors,
                  scale=1.5)
    wc= wc.generate(word)
    wc.to_file(r'D:\blog\result.jpg')

根据官方的照片例子的出来的词云是这样的:

但是既然是政府工作报告,那肯定要上我的偶像,全世界最大公司的老总

哈哈,词云就这样生成了!

总结

词云还是很好玩的,很简单,对看数据很直观。话说今天把爬虫和数据分析小小结合起来,虽然都是皮毛,但是我们还是有未来的(是的,我偶像是这么说的)!今天跟一个朋友聊天,聊到了平常都在爬什么数据,然后他说你连视频都没爬过,被深深的鄙视了一番,估计这个星期会把爬视频这个技能学会,哈哈,下一篇文章就是爬视频的文章了(就决定是你了)!

照例在最后附一下全部的代码:

# -*- coding:utf-8 -*-
# 作者:Jason

import jieba
from requests_htmlimport HTMLSession
from collectionsimport Counter
from wordcloudimport WordCloud, STOPWORDS, ImageColorGenerator
from scipy.miscimport imread

target_url= 'http://news.ifeng.com/a/20180305/56472392_0.shtml'


def get_info(url):
    report= ''
    session= HTMLSession()
    response= session.get(url)
    report_text= response.html.xpath('//*[@id="main_content"]/p/text()')[:-1] if response.htmlis not None else 'NULL'
    print(report_text)
    for i in report_text:
        report+= i
    return report


def handle_word(report):
    words= [wordfor wordin jieba.cut(report,cut_all=True) if len(word) >= 2]
    # c = Counter(words)
    # for word_freq in c.most_common(10):
    #    word, freq = word_freq
    #    print(word, freq)
    return words


def word_cloud(word):
    path= r'C:\Windows\Fonts\simfang.ttf'  # 字体路径
    bg_pic= imread(r'D:\blog\20160303160528046.png')  # 读取模板图片
    image_colors= ImageColorGenerator(bg_pic)  # 从模板图片生成颜色值
    wc= WordCloud(font_path=path,
                  background_color="white",
                  mask=bg_pic,
                  stopwords=STOPWORDS.add("said"),
                  max_font_size=500,
                  color_func=image_colors,
                  scale=1.5)
    wc= wc.generate(word)
    wc.to_file(r'D:\blog\result.jpg')


if __name__== '__main__':
    words= handle_word(get_info(target_url))
    data= r" ".join(words)
    word_cloud(data)