0%

python爬虫:豆瓣短评

导入必要的包(package)

若没有下列的包,可使用pip install 包名命令安装

  • re: 使用正则表达式
  • json: 解析json内容
  • time: 爬虫间歇时间控制
  • jieba: 中文分词库
  • urlib: 将中文关键字编码(百分号+数字)
  • requests: 向网站发出请求
  • bs4: 解析网页内容
  • wordcloud: 生成词云
1
2
3
4
5
6
7
8
9
10
import re
import json
import time
import jieba
import requests
import numpy as np
from urllib.parse import quote
from wordcloud import WordCloud
from bs4 import BeautifulSoup
from matplotlib import pyplot as plt

项目需求:爬取豆瓣的书评和影评概要

  • 输入指定的书籍名称和电影名称,返回其评论构成的词云。

网站分析(豆瓣电影和豆瓣读书)

我们豆瓣电影为例,爬取豆瓣读书原理相仿。

首先我们打开谷歌浏览器的开发者工具,如果我们要搜索电影则在搜索框中键入搜索关键字是最近刚出的电影小丑,则会弹出下拉列表,并且旁边的Network中会显示出刚刚的响应:
xiaochou
我们可以发现出现了一个json文件,这个json文件即是下拉列表的信息:
list
我们再看看它的url,也就是我们爬虫目标网址,同时我们也能找到需要的请求头headers,可以发现它将我们的搜索关键字重新编码了(%+数字),这个我们稍后用urllib处理编码:
head
继续分析json文件,json文件中的内容就是每个电影的网址,列表中第一个地址即是我们要找的小丑的网址主页:
xiaochou
我们点进小丑的主页进行验证,网址中的那串数字就是我们需要解析出来的电影唯一标识:
zhuye
最后我们来看我们的目的地评论的网址,往下翻,点击全部评论:
com
com1
发现网址并没有什么规律,我们继续点击评论的下一页,规律出现了。每增加一页,start参数增加20,这便是我们批量爬取评论的根据:
page
好,我们继续看评论在html文件中的位置:
loc
ok,分析完毕,爬虫抓取大概就是这个流程,最终的目的就是找到需求信息的位置

爬虫设计

根据以上的分析,我们这样来设计我们的爬虫的爬虫流程:

  1. 将我们输入的关键字编码成网址中的编码类型。
  2. 获取json中电影的真实地址信息。
  3. 生成我们要访问的评论所在的网页地址
  4. 抓取评论信息。

代码编写

接下来给出几个关键步骤的代码说明

汉字编码

使用urllib.parse中的quote函数进行编码:

1
2
3
4
5
def __handle_name(self, name):
"""
编码中文关键字(%+[00-99])
"""
return str(quote(name))

解析json获取地址

使用json库中的loads函数解析json文件:

1
2
3
4
5
6
7
8
9
10
11
def __find_url(self, url, tp):
"""
获取真实主页地址和编号id
"""
r = requests.get(url, headers=self.headers[tp])
json_data = json.loads(r.text)
address_num = re.search('[0-9]+', json_data[0]['url'])
if tp == 0:
return self.movie_url % address_num, address_num.group(0) # 获取电影地址
else:
return self.book_url % address_num, address_num.group(0) # 获取书籍地址

使用WordCloud生成词云

使用WordCloud生成词云,用jieba进行中文分词。该函数中有两个变量需要解释:

  • bg_image: 为词云添加背景图片。
  • scale: 词云图片的清晰度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def __plot_wordcloud(self, name, bg_image=None):
"""
绘制词云
"""
file_name = str(name) + '.txt'
f = open(file_name, 'r', encoding='utf-8').read()
cut_text = " ".join(jieba.cut(f)) # 中文分词
print("正在生成词云...")
word_cloud = WordCloud(
scale=10,
font_path='C:/Windows/Fonts/simfang.ttf',
background_color="white", width=1000, height=1000
).generate(cut_text)
plt.imshow(word_cloud, interpolation='bilinear')
plt.axis('off')
plt.show()

完整代码及运行示例

将整个爬虫过程封装,根据上述爬取电影评论的方法同时也实现了爬取数据评论的方法,最后爬取了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import re
import json
import time
import jieba
import requests
import numpy as np
from urllib.parse import quote
from wordcloud import WordCloud
from bs4 import BeautifulSoup
import matplotlib.pyplot as plt


class DoubanCrawl:
def __init__(self, info_type):
self.info_type = info_type
self.headers = [
{
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
'Host': 'movie.douban.com'
}, # movie's headers
{
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
'Host': 'book.douban.com'
} # book's headers
]
self.movie_search_url = "https://movie.douban.com/j/subject_suggest?q="
self.movie_url = "https://movie.douban.com/subject/%s/"
self.movie_comment_url = "https://movie.douban.com/subject/%s/comments?start=%d&limit=20&sort=new_score&status=P"

self.book_search_url = "https://book.douban.com/j/subject_suggest?q="
self.book_url = "https://book.douban.com/subject/%s/"
self.book_comment_url = "https://book.douban.com/subject/%s/comments/hot?p=%d"

def info_crawl(self, name, bg_image=None):
name_str = self.__handle_name(name) # 获取url的gbk编码
text_list = []
if self.info_type == "movie":
print("-----爬取电影短评-----")
self.movie_search_url += name_str
self.movie_url, num_str = self.__find_url(self.movie_search_url, 0)
for i in range(0, 15):
url = self.movie_comment_url % (num_str, i*20)
time.sleep(np.random.randint(1, 3)) # 间隔1~3秒
print("正在获取第%d个页面" % i)
r = requests.get(url, headers=self.headers[0])
soup = BeautifulSoup(r.content, 'lxml')
comment_list = soup.find_all('span', class_='short')
for ct in comment_list:
text_list.append(ct.text)
self.__comment_to_txt(name, text_list) # 存储评论文字
self.__plot_wordcloud(name, bg_image) # 绘制词云
else:
print("-----爬取书籍短评-----")
self.book_search_url += name_str
self.book_url, num_str = self.__find_url(self.book_search_url, 1)
for i in range(1, 20):
url = self.book_comment_url % (num_str, i)
time.sleep(np.random.randint(1, 3)) # 间隔1~3秒
print("正在获取第%d个页面" % i)
r = requests.get(url, headers=self.headers[1])
soup = BeautifulSoup(r.content, 'lxml')
comment_list = soup.find_all('span', class_='short')
for ct in comment_list:
text_list.append(ct.text)
self.__comment_to_txt(name, text_list)
self.__plot_wordcloud(name, bg_image)

def __plot_wordcloud(self, name, bg_image=None):
"""
绘制词云
:param name:
:param bg_image:
:return:
"""
file_name = str(name) + '.txt'
f = open(file_name, 'r', encoding='utf-8').read()
cut_text = " ".join(jieba.cut(f))
print("正在生成词云...")
word_cloud = WordCloud(
scale=10,
font_path='C:/Windows/Fonts/simfang.ttf',
background_color="white", width=1000, height=1000
).generate(cut_text)
plt.imshow(word_cloud, interpolation='bilinear')
plt.axis('off')
plt.show()

def __comment_to_txt(self, name, clist):
file_name = str(name) + '.txt'
with open(file_name, 'a+', encoding='utf-8') as f:
for c in clist:
f.write(c)
f.close()

def __handle_name(self, name):
"""
编码中文关键字
:param name:
:return:
"""
return str(quote(name))

def __find_url(self, url, tp):
"""
获取真实主页地址和编号id
:param url:
:param tp:
:return:
"""
r = requests.get(url, headers=self.headers[tp])
json_data = json.loads(r.text)
address_num = re.search('[0-9]+', json_data[0]['url'])
if tp == 0:
return self.movie_url % address_num, address_num.group(0) # 获取电影地址
else:
return self.book_url % address_num, address_num.group(0) # 获取书籍地址


if __name__ == '__main__':
my_crawl = DoubanCrawl("movie")
my_crawl.info_crawl('千与千寻')

运行结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-----爬取电影短评-----
正在获取第0个页面
正在获取第1个页面
正在获取第2个页面
正在获取第3个页面
正在获取第4个页面
正在获取第5个页面
正在获取第6个页面
正在获取第7个页面
正在获取第8个页面
正在获取第9个页面
正在获取第10个页面
正在获取第11个页面
正在获取第12个页面
正在获取第13个页面
正在获取第14个页面
Building prefix dict from the default dictionary ...
Loading model from cache C:\Users\SkecisAI\AppData\Local\Temp\jieba.cache
Loading model cost 0.879 seconds.
Prefix dict has been built succesfully.
正在生成词云...

cloud

本文标题:python爬虫:豆瓣短评

文章作者:SkecisAI

发布时间:2019年11月28日 - 19:08:11

最后更新:2019年12月15日 - 16:09:25

原始链接:http://www.skecis.top/2019/11/28/python爬虫豆瓣短评/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

感谢你的支持,希望本文能助你一臂之力。