Python爬取网络信息的常用功能库打开网站
使用Python爬虫获取豆瓣影评,并用词云显示Python语言流行到现在,目前最受开发者喜爱的功能莫过于它的爬虫功能,以至于很多人以为Python的英语发音也是“爬虫”,其实它是读作“啪善”[‘paɪθɑn] 。而爬取网络信息,只是它的一个功能,它同时也涉及其它领域,比如说现在比较流行的人工智能、科学计算、网络开发等。而在爬取网络信息这个任务中,常用的是使用urllib库和bs4库打开网站并解析页面信息并分析,本文所要介绍的爬取豆瓣影评也是使用这两个库。另外,为了能形象的展示爬取的结果,在项目最后,使用了WordCloud词云对爬取的关键字进行了显示,在显示前,用jieba分词工具提取了影评中常用的关键字。
项目开始前,要做一些必要的准备,比如Python环境的安装,库的下载等。本项目是在Windows下运行,所以首先要在Windows下安装Python。由于这个过程比较简单,在本文中就不做介绍。Python安装完后,需要安装本项目所用的第三方库。如果python的基本环境安装完了,第三方库安装也很简单,直接使用pip工具即可下载安装(前提是机器必须能够连网):
由于本机已经在写文章之前安装过库,所以系统提示已经存在;如果没有安装过,运行“pip install xxx”的命令时可以看到下载和安装的过程及进度。其它所需的第三方库都可以使用此方法下载。环境和库准备完成后,就可以进行代码的实现了。
本项目的主要实现过程分为两个阶段,第一部分先获取豆瓣上某个电影的影评信息;第二部分通过jieba分词和WordCloud把结果用词云的方式展示出来。
Step:获取豆瓣影评,放到文本文件中:
使用python爬取网络信息,最基本的概念就是用urllib等工具打开网站,获取网页信息,然后对所需的信息进行解析并提取感兴趣的内容。在这个过程中,难点在于解析网页内容并获取感兴趣的内容。由于不同的网站页面结构是不一样的,所以需要针对特定的网页结构实现特定的解析代码。在代码实现之前,需要分析网页的内容。
从上面的图片可以看出,爬取之前首先要获取网页的url,通过url才能获得特定的网页内容用于解析。幸运的是,豆瓣上对于特定影片的影评的获取地址格式是固定的,比如:
这个网址中,是固定的,后面的“26787574”是影片的ID,是豆瓣给定的编号,它对于特定的影片也是固定的,比如这个网址中的ID对应的就是最近得分比较高的《头号玩家》,我们可以通过打开特定的页面提前获得这个ID;对于网址后的start参数,很明显能分析出,它是对应的影评的编号是从第一条影评开始,limit表示一页显示的影评条数,这是默认值,不可修改;sort表示按照最新的热门评论排序;status表示显示看过这个电影的网友的评论,没有看过这个电影的网友写的评论就不显示了。
网址分析完成后,就要开始解析网页结构了,我们需要通过分析网页结构,得到页面上图片中红色方框标出的影评内容,忽略所有其它内容。这个过程需要一定的html的知识。
我们首先借助chrome浏览器的开发者工具功能分析一下这个网页的html代码,然后找到影评所对应的项:
通过分析页面html代码,可以知道,评论内容在comment目录下对应的’p’字段中,所以我们后面解析的代码就要提取这部分的内容。
由于每部电影可能会有很多页的影评,我们不打算提取所有内容,只抓取最新的200条就可以,所以在处理网址的时候可以做循环处理,一次抓取20条,抓10页就可以。
每条影评的内容得到后,我们把它放到一个特定的文本文件中,比如content.txt中,便于后面使用jieba分词并用词云显示。
Step:从文本文件读取内容,分词后并显示
内容抓取后,剩下的就是解析并显示了。这部分代码对任何文本文件都是适用的。比如,我们不光可以分析影评,也可以分析歌词,新闻关键字等。
Jieba分词库的功能非常强大,其中常用的就是它的cut函数,它可以把给定的文本中整句或整段的文章,按照中文常用的单词进行切分,便于后续对关键字进行分析。另外WordCloud也是一个很棒的功能,能够以好看的样式显示出词云的形状,并根据每个词出现的频率,以不同的文字大小显示。词云图轮廓有’circle’, ‘cardioid’, ‘diamond’, triangle-forward’, ‘triangle’, ‘pentagon’, ‘star’可选,分别代表‘圆形’,‘心形’,‘菱形’,‘向前三角形’,‘向上三角形’,‘五边形’,‘星形’。
在获取到每个词的词频后,显示词云之前,有一个对词频进行排序的过程。由于关键词和词频是由字典组成的,所以排序时用到了sorted函数,把关键字按照词频由大到小进行排列。具体的实现过程,请参考下面的代码:
<p><pre class="prettyprint"> <code class=" hljs python"><span class="hljs-comment">#-----------------------------------------------------------------------------</span>
<span class="hljs-comment"># Name: douban.py</span>
<span class="hljs-comment"># Purpose: 读取豆瓣上关于某个电影的评论,并用词云显示出来</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment"># Author: ISS-XiangjianChen</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment"># Created: 16/04/2018</span>
<span class="hljs-comment"># Copyright: (c) ISS 2018</span>
<span class="hljs-comment">#-------------------------------------------------------------------------------</span>
<span class="hljs-keyword">import</span> urllib.request
<span class="hljs-keyword">import</span> jieba
<span class="hljs-keyword">from</span> bs4 <span class="hljs-keyword">import</span> BeautifulSoup <span class="hljs-keyword">as</span> bs
<span class="hljs-keyword">import</span> re
<span class="hljs-keyword">from</span> pyecharts <span class="hljs-keyword">import</span> WordCloud
<span class="hljs-comment">#获取评论放一个文本文件中</span>
<span class="hljs-comment">#名 ID</span>
<span class="hljs-comment">#阿甘正传 1292720</span>
<span class="hljs-comment">#无问西东 6874741</span>
<span class="hljs-comment">#红海行动 26861685</span>
<span class="hljs-comment">#捉妖记2 26575103</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">GetTxt</span><span class="hljs-params">(start)</span>:</span>
eachCommentList = []
requrl = <span class="hljs-string">'https://movie.douban.com/subject/26787574/comments?start='</span>+ \
str(start) + <span class="hljs-string">'&limit=20&sort=new_score&status=P'</span>
resp = urllib.request.urlopen(requrl)
html_data = resp.read().decode(<span class="hljs-string">'utf-8'</span>)
soup = bs(html_data, <span class="hljs-string">'html.parser'</span>)
comment_div_lits = soup.find_all(<span class="hljs-string">'div'</span>, class_=<span class="hljs-string">'comment'</span>)
<span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> comment_div_lits:
<span class="hljs-keyword">if</span> item.find_all(<span class="hljs-string">'p'</span>)[<span class="hljs-number">0</span>].string <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">None</span>:
eachCommentList.append(item.find_all(<span class="hljs-string">'p'</span>)[<span class="hljs-number">0</span>].string)
<span class="hljs-comment">#写到文本文件中</span>
f = open(<span class="hljs-string">'content.txt'</span>,<span class="hljs-string">'a'</span>,encoding=<span class="hljs-string">'utf-8'</span>)
<span class="hljs-keyword">for</span> comment <span class="hljs-keyword">in</span> eachCommentList:
f.write(comment)
f.close()
<span class="hljs-comment">#从文本文件中生成词云</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">Generator</span><span class="hljs-params">()</span>:</span>
<span class="hljs-keyword">with</span> open(<span class="hljs-string">'content.txt'</span>, <span class="hljs-string">'r'</span>, encoding=<span class="hljs-string">'utf-8'</span>) <span class="hljs-keyword">as</span> f:
text_body = f.read()
f.close()
<span class="hljs-comment">#使用jieba进行分词</span>
words_lst = jieba.cut(text_body.replace(<span class="hljs-string">'\n'</span>, <span class="hljs-string">''</span>).replace(<span class="hljs-string">' '</span>, <span class="hljs-string">''</span>))
<span class="hljs-comment">#统计词频</span>
total = {}
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> words_lst:
total = total.get(i, <span class="hljs-number">0</span>) + <span class="hljs-number">1</span>
<span class="hljs-comment">#按词频进行排序,只选取包含两个或两个以上字的词</span>
data = dict(sorted({k: v <span class="hljs-keyword">for</span> k, v <span class="hljs-keyword">in</span> total.items() <span class="hljs-keyword">if</span> len(k) >= <span class="hljs-number">2</span>}.items(),\
http://www.qianxianly.com/data/attachment/forum/20221127/1669496229147_2.png
key=<span class="hljs-keyword">lambda</span> x: x[<span class="hljs-number">1</span>], reverse=<span class="hljs-keyword">True</span>)[:<span class="hljs-number">200</span>])
name = data.keys()
value = <span class="hljs-comment">#获取列表对象</span>
<span class="hljs-comment">#构造一个词云对象,把所有的词放进去</span>
word_cloud = WordCloud(width=<span class="hljs-number">1600</span>, height=<span class="hljs-number">1024</span>)
<span class="hljs-comment">#pentagon表示用五角星的形状显示词云</span>
word_cloud.add(<span class="hljs-string">""</span>, name, value, word_size_range=[<span class="hljs-number">20</span>, <span class="hljs-number">100</span>], shape=<span class="hljs-string">'triangle'</span>)
<span class="hljs-comment">#把词云显示到一个html网页中</span>
word_cloud.render(<span class="hljs-string">'content.html'</span>)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>:</span>
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">201</span>,<span class="hljs-number">20</span>):
GetTxt(i)
Generator()
<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
main()</code></pre></p>
<p><pre> <code> 最终的词云显示效果如下图:
</code></pre></p>
Created by 陈祥俭
页:
[1]