完全小白篇-用python爬取豆瓣影评打开豆瓣电影随机电影的所有影评网页跳转逻辑
分析影评内容获取方法
逐一正则提取影评针对标签格式过于多样的处理针对提出请求的频率的限制
存储方式(本次sqlite3)
附:豆瓣短评的正则提取逻辑
python爬虫5天速成
这一个项目其实是受B站的课程启发的,里面讲述了用python爬取豆瓣评分top250的各类信息,这也是我最初选择学习爬虫的启蒙教程。另外一点就是和爬网络小说也比较像,用python爬取网络小说因为是最最单纯的爬取文本数据
所以就有这一次我自己想到的项目:爬取任意豆瓣电影的所有影评。
打开豆瓣电影
随机电影的所有影评网页
本次打开的是《信条》
影评是实时更新的(本图发布时间是2020/9/7 8:47),从表面来看各个影评摘要部分摆在这个网页还是相当整齐的,这对于正则提取来说相对友好。
第x页其实是基于每一页都只存放20条影评摘要的,实际上我们对网页栏写入"?start=x"就会令豆瓣服务器返回一个从第x条影评摘要开始的网页:
我们检查网页源代码,在中间部分会发现各个存放摘要信息的盒子:
跳转逻辑
分析一下当前这种页面的特点:每一页固定只有20条影评摘要
每一条影评摘要都会相对应有一个a标签以供跳转到影评人具体影评
可以通过"start="来获取指定序列的网页
所以我们可以制定一个基本爬取方案:
1. 获取该电影影评网站的网页源代码
2. 正则提取a标签跳转链接(并存入一个列表)
3. 根据列表跳转到具体影评人影评,获取那个页面的源代码
4. 从中正则提取需要的内容
5. 寻找方法存储提取的内容
分析影评内容获取方法
我们打开第一个影评人的影评,并检查源代码:
他的网页其实已经相当复杂了,因为我们不仅仅要剔除什么样式也没有的p标签,还要针对性去处理有data-page、data-align样式的p标签。(先用个小本本记下来这些特点)
我们再打开另几个影评的源代码。下图是第三篇影评的形式:
他居然还会在p标签里内置span标签另加样式。。。所以我们的任务就额外多了一个去除span标签
往下翻几条,发现所有的网页无外乎就以上几种了:啥内容也没有的p标签
有data-page="0"样式的p标签
有 data-align="" 或 data-align=“left” 的p标签
data-page和data-align两种样式都有的p标签
p标签里内置的span标签(且一旦有居然都是< span style=“font-weight: bold;” >这样的标签)
逐一正则提取影评
针对标签格式过于多样的处理
由于每个网页的提取规则都不同,实在难以实现可移植性高的代码,所以只能针对这个项目针对性地写代码调整:正则提取所有p标签内容
将内容化为string形式并删除< p data-align data-page>、< span style=“font-weight: bold;” >这样的东西
整合好每一篇标题+影评,进行存储
针对提出请求的频率的限制
豆瓣的反爬虫这么严格了现在?
豆瓣也是多少年的老网站了,反爬机制估计也是很成熟,实际情况就是,经过试验,全功率无限制运行程序(while循环速度)会导致豆瓣在你爬到第40篇时就对你的IP关闭服务,设置1s一次请求的话会在140篇的位置对你的IP关闭服务,2s一次请求的话会在520-530篇对你的IP关闭服务。3s相对安全,能爬1080左右的影评,4s一次请求不用担心访问被拒的。
方法很简单,调用python自带 time 库的 time.sleep() 函数即可
存储方式(本次sqlite3)
干爬不存有点浪费这个项目。本次采用创建+写数据库的形式存储爬取的信息。因为内容很多所以采用边爬边存调用sqlite3库 import sqlite3
在程序运行最开始创建这个数据库:
# 删除先前的数据库方便直接建表
if os.path.exists("TENET.db"):
os.remove("TENET.db")
# 连接数据库
TENET = sqlite3.connect("TENET.db")
c = TENET.cursor() #游标
sql = '''
create table Review
(
id int primary key,
title text not null,
review text nut null
);
'''
c.execute(sql)# 执行sql操作
TENET.commit() # 提交数据库操作
TENET.close() # 关闭数据库
每当获取好一个影评,就调用插入当前表单:
# 调用saveData([j,title,text])
def saveData(review_text):
TENET = sqlite3.connect("TENET.db")
c = TENET.cursor() #游标