前言:
在我学习完python的基础知识之后,当然想要练练手,加深一下对python以及其语法的理解,
所以听说爬虫特别有成就感,非常有利于学习and娱乐,以及培养学习的兴趣,so就到处百度爬虫的相关文章,网上的确有很多相关的,但我还是决定自己写写,
只有自己写下了讲出来才能代表真的学会了这么技术
- 我也是第一次学python和抓包,是根据网上的各种讲解以及自己的摸索,慢慢学会的,有什么说的不对的,欢迎指正
- 刚开始的时候我的使用Anaconda管理包和环境(py3.6),然而后来我在学多线程的时候,就出现了问题:setdaemon(true)一直没效果(设置守护线程后,守护线程本来应该在所有非守护线程执行完就立马结束而不管守护线程是否结束的,but没用,网上各种查也查不到,后来我把代码写到.py文件里直接在cmd里执行该脚本就没问题了)
- 使用Anaconda是因为我打算入坑深度学习,所以提前熟悉熟悉这个管理工具,科科
本章目的: 抓取豆瓣电影网站正在上映列表的评价关键词,并使用词云表示出来
- 豆瓣正在上映列表如图
- 豆瓣电影《芳华》短评列表如图
- 最终获得的《芳华》短评词云如图
抓取步骤大致分为三步,具体的又分为下面几步:
1.访问并获取网页数据并抽取出来有用信息
获取豆瓣正在上映列表的网页数据
使用Python的urllib模块: 其提供了一个从指定的URL地址获取网页数据(创建一个表示远程url的类文件对象),通过该对象可以对其进行分析处理,获取想要的数据
- 函数原型
- url: 请求的地址(除了url,其他都可以不填)
- data: 访问url时请求的参数
- timeout: 超时时间
- python2.X写法:
1 | import urllib |
- python3.X写法:
1 | import urllib.request #from urllib import request |
- urlopen()方法返回值类型:
如果请求的是http或者https地址,则返回http.client.HTTPResponse对象
如果请求的是ftp或者Data URL地址(以及requests explicitly handled by legacyURLopener and FancyURLopener classes <-原谅我没看懂),则返回urllib.response.addinfourl对象
- 上面的对象包含多个方法可供我们使用
- geturl() :返回请求的网页地址
- info() :返回一个httplib.HTTPMessage对象,表示远程服务器返回的头信息
- getcode():返回HTTP状态码
- read() , readline() , readlines() , fileno() , close() 这些方法的使用方式与文件对象完全一样
实例
1 | import urllib |
找到网页上你要的电影列表的位置,看看有什么标签特点
我们发现所有的电影列表都在id为nowplaying的div下面的一个ul下,该ul的class为lists,并且每个电影的li标签的class为list-item
该li标签中有许多熟悉,我们发现data-title为电影标题,data-score为电影评分,data-star为打星…,最最重要的是id,每个电影都不同,可推测应该是电影的唯一标识(编号);
我们要通过某一个标识来查询该电影的短评, 通过查看电影主页的网址(https://movie.douban.com/subject/26862829/ )可知,这个id就是我们需要的
使用python的BeautifulSoup库进行网页信息的抓取(网页解析库)
BeautifulSoup 是一个可以从 HTML 或 XML 文件中提取数据的 Python 库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup 会帮你节省数小时甚至数天的工作时间.
- BeautifulSoup:Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。
它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。
Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不需要考虑编码方式,除非文档没有指定一个编码方式,这时,Beautiful Soup就不能自动识别编码方式了。然后,你仅仅需要说明一下原始编码方式就可以了。
Beautiful Soup已成为和lxml、html6lib一样出色的python解释器,为用户灵活地提供不同的解析策略或强劲的速度。(from http://beautifulsoup.readthedocs.io/zh_CN/latest/ )
- 使用BeautifulSoup解析代码,能够得到一个 BeautifulSoup 的对象,并能按照标准的缩进格式的结构输出
- Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种: Tag, NavigableString, BeautifulSoup, Comment
1
2
3
4Tag: <class 'bs4.element.Tag'>标签对象,两个属性:name, attribute (直接调用:tag.name,tag['class']), 如果是多值属性,则返回list,也可以赋值为多值属性(假的多值属性返回字符串,如id="aaa bbb")
NavigableString: <class 'bs4.element.NavigableString'> tag中的字符串对象,即tag.string; tag中包含的字符串不能编辑,但是可以被替换成其它的字符串,用 replace_with() 方法
BeautifulSoup : <class 'bs4.BeautifulSoup'>BeautifulSoup对象表示的是一个文档的全部内容.大部分时候,可以把它当作 Tag 对象,它支持 遍历文档树 和 搜索文档树 中描述的大部分的方法; 一个方法:soup.name # [document]
Comment : <class 'bs4.element.Comment'>文档的注释部分,Comment 对象是一个特殊类型的 NavigableString 对象
BeautifulSoup对象使用示例:
解析时,可以传入一段字符串或一个文件句柄.
1
2
3
4
5
6from bs4 import BeautifulSoup #导入模块
soup = BeautifulSoup(open("index.html"))
soup = BeautifulSoup("<html>data</html>")
#首先,文档被转换成Unicode,并且HTML的实例都被转换成Unicode编码
#然后,BeautifulSoup选择最合适的解析器来解析这段文档,如果手动指定解析器那么Beautiful Soup会选择指定的解析器来解析文档soup.title # 标签对象:<title>北京 - 在线购票&影讯
- soup.title.name # 标签名称:title
- soup.title.string # 标签内容:北京 - 在线购票&影讯
- soup.p # 第一个p标签对象:
豆瓣
- soup.p[‘class’] # 第一个p标签对象的类属性
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18原型:find_all( name , attrs , recursive , string , **kwargs ) 搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件
name: name 参数可以查找所有名字为 name 的tag,字符串对象会被自动忽略掉.
attrs: 通过属性选择器查询,有两种写法
1. soup.find_all(class_='value', id='value2')
2. soup.find_all(attrs={"class": "value", "id":"value2"})
limit: 限制查询结果个数
recursive: 调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False
string: 通过 string 参数可以搜搜文档中的字符串内容. soup.find_all("a", string="value") #查询标签中文字包含value的a标签
```
8. soup.find('a').get('href') # 找到第一个a标签 并返回其href属性内容 ( find_all() 方法的返回结果是值包含一个元素的列表,而 find() 方法直接返回结果.)
9. 更多用法见BeautifulSoup官网中文文档:http://beautifulsoup.readthedocs.io/zh_CN/latest/
* 解析网页代码,并编码为utf-8
```python
import urllib
urltext = urllib.request.urlopen('https://movie.douban.com/nowplaying/beijing/')
html_data = urltext.read().decode('utf-8')
print (html_data)
- 获取正在上映列表数据 nowplaying_movie_list列表(List)
1 | import urllib |
- 至此已经获得了最内部一层的电影数据, 可以直接获得每个电影的id了
1 | print (nowplaying_movie_list[0]['id'], '\n') #获取第一个电影的id数据 |
现在 我们需要获取其中某一个id,通过这个id获取对应电影的短评,然后就可以进行处理了
你也可以自由发挥,制作一个查询的功能,通过输入电影名称指定某一个电影进行分析
2.分析网页中有用信息并进行处理
首先按照上面的步骤访问电影首页,抽取短评信息,存放到一个List中
首先解析网页代码
1
2
3
4
5
6
7
8
9requrl = "https://movie.douban.com/subject/" + nowplaying_movie_list[0]['id'] + "/comments?start=0&limit=20"
resp = urllib.request.urlopen(requrl)
html_data = resp.read().decode('utf-8')
soup = bs(html_data, 'html.parser')
title = soup.find('title') # 直接获取title标签
print(title.string) #获取标签中内容
comment_div_list = soup.find_all('div', class_ = 'comment')
print (comment_div_list) #所有的短片标签列表通过下面的源码可知,所有的短评文字都放在class为comment-item的div下的一个p标签中,所有我们要得到所有的p标签并组成一个List
1 | commentList = [] #存放所有的短评内容数据 List |
- 已得短评List,但是该List中包含大量的单引号(List自带的),换行符等不需要的东西,并且由于我们要做成词云,所有的符号都不要,只要文字
1 | while True: |
词云展示的只是关键词,所以去除用户短评中的所有的标点符号(正则表达式)
1
2
3
4
5import re #正则表达式
pattern = re.compile(r'[\u4e00-\u9fa5]+') #去除标点符号(正则表达式)
filterdata = re.findall(pattern, comments)
cleaned_comments = ''.join(filterdata) # 把filterdata按照空字符串为间隔连接起来
print (cleaned_comments)目前所有的评价都没有间隔的展示在这里,我们需要把其中的词语取出来得到所有的关键词
使用jieba分词, 把字符串中的所有的词语分出来,组成一个List
结巴(jieba)是国人出的一个精品插件,可以对一段中文进行分词,有三种分词模式,可以适应不同需求。
1 | jieba.cut 方法接受三个输入参数: 需要分词的字符串;cut_all 参数用来控制是否采用全模式;HMM 参数用来控制是否使用 HMM 模型 |
1 | #代码示例 |
使用jieba分割短评,获取返回的分词List
1
2
3import jieba
segment = jieba.lcut(cleaned_comments)
print (segment)数据中有“的”、“是”、“我”、“你”等虚词(停用词),而这些词在任何场景中都是高频时,并且没有实际的含义,所以我们要他们进行清除。
使用pandas
1 | import pandas as pd |
我的停用词文件: http://p18j2ow6f.bkt.clouddn.com/static/file/stopwords.txt
- 清洗了关键词以后,我们把剩下的词语进行分类统计,观察每个词语的频率
使用numpy
1
2
3
4import numpy #numpy计算包
words_stat = words_df.groupby(by=['segment'])['segment'].agg({"计数":numpy.size}) # 按照segment分类
words_stat = words_stat.reset_index().sort_values(by=["计数"],ascending=False) #词频按照 计数 由大到小排列
words_stat.head()
3.制作为词云
1 | import matplotlib |
我的字体文件: http://p18j2ow6f.bkt.clouddn.com/static/file/simhei.ttf
最终效果
个人完整代码:
1 | from urllib import request #python3.X写法 |
别人家的代码【滑稽】:
1 | #coding:utf-8 |
转载自 链接地址: http://python.jobbole.com/88325/
个人博客 欢迎来访: http://blog.zj2626.com