糗事百科属于静态文章
爬取静态网站关键点:写正则表达式
引包:
sqlite3数据库包: import sqlite3
正则表达式: import re
负责打开浏览url内的html 文本: from urllib.request import Request, urlopen
随机生成代理ip(浏览器请求头): from fake_useragent import UserAgent
建类:
1.工具类
对提取的元组中的数据,进行整理,删除无效的字符的类(\n.<br/>)
思路:先用正则表达式对爬取出的数据进行二次爬取,将要整理的字符串用sub方法进行替换,最后将结果重新封装成一个元组。
origin_tuple_data:爬取出的一次数据。
data: 爬取出的二次数据
sub(参数1,参数2,参数3): 替换规则,替换结果,替换元组
=================================================================================
class DataTool(object):
pattern_n = re.compile(r'\n', re.S)
pattern_br = re.compile(r'<br/>', re.S)
def process_tuple_data(self,origin_tuple_data):
nick_name = re.sub(self.pattern_n, '', origin_tuple_data[0])
content = re.sub(self.pattern_n, '', origin_tuple_data[2])
content = re.sub(self.pattern_br, '', content)
data = (nick_name, origin_tuple_data[1], content, origin_tuple_data[3], origin_tuple_data[4])
return data
==================================================================================
2.数据库工具类
操作数据库:
1.创建数据库的连接对象,创建游标,这两个对象一般连接一次即可;
2.数据的增删改查;
3.关闭数据库、关闭游标对象,一般都是在数据保存完毕之后关闭即可。
==================================================================================
class DBTool(object):
connect = None
cursor = None
@classmethod
def create_db_cursor(cls):
cls.connect = sqlite3.connect('qsbk.db') 数据库连接
cls.cursor = cls.connect.cursor() 创建游标
@classmethod
def insert_db_cursor(cls, tuple_data): 传入元组,用insert插入语句将元组中的数据加入表中(qs为表名,表需要自己在数据库中建立)
sql_str = 'INSERT INTO qs (nick_name, level, content, vote_number, comment_number) VALUES("%s","%s","%s","%s","%s")' % (tuple_data[0],tuple_data[1],tuple_data[2],tuple_data[3],tuple_data[4])
cls.cursor.execute(sql_str) 执行sql语言
cls.connect.commit() 提交到数据库
@classmethod
def close_db_cursor(cls):
cls.cursor.close() 关闭游标
cls.connect.close() 关闭连接
===================================================================================
3.爬虫类:对象属性
===================================================================================
class QSBKSpider(object):
def __init__(self):
self.base_url = 'https://www.qiushibaike.com/hot/page/' 页面路径
# self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'} 浏览器请求头
self.tool = DataTool() 实例化工具类DataTool的对象
self.ua = UserAgent() 实例化ua对象
def get_list_html(self,page_num): 如果有多页,获取每一个列表页的html网络源代码
page_url = self.base_url + str(page_num) 构造每一页的url地址
headers = {'User-Agent': self.ua.random } random属性:从ie、firefox、chrome等浏览器的ua中,随机获取一个ua即user-agent
request = Request(page_url, headers=headers)
try:
response = urlopen(request) 实现对目标url的访问
except Exception as e:
print('请求失败:地址{},原因{}'.format(page_url, e))
return None
else:
return response.read().decode()
def parse_list_html(self, html): 解析上一个函数请求的html源代码
if html:
# 使用正则表达式开始解析网页源代码
# 写正则注意事项:
# 1.尽量找到要匹配的零散数据所在的标签,而且这个标签必须和这些零散的数据一样能够循环。因为findall在循环匹配数据的时候,是按照整个正则表达式规则循环匹配的。
# 2.在参考网页中"审查元素"来设置正则匹配规则的时候,一定要确认是否和"网页源代码"中的标签顺序、属性顺序等保持一致,如果不一致的话,必须参考“网页源代码”来设置正则匹配规则。因为“审查元素”中的html代码是经过JS渲染之后的源代码。
pattern = re.compile(r'<div class="article block.*?>.*?<div class="author clearfix">.*?<h2>(.*?)</h2>.*?<div class="articleGender.*?">(.*?)</div>.*?<div class="content".*?<span>(.*?)</span>.*?<div class="stats">.*?<i class="number">(.*?)</i>.*?<i class="number">(.*?)</i>',re.S)
results_list = re.findall(pattern, html)
for data in results_list:
new_data = self.tool.process_tuple_data(data) 用工具类对爬取出的数据进行二次处理
DBTool.insert_db_cursor(new_data) 存入数据库
print(new_data)
else:
print('html源代码为None')
if __name__ == '__main__':
DBTool.create_db_cursor() 创建数据库对象、游标对象
obj = QSBKSpider() 创建类对象
for x in range(1,10): 循环爬取多页数据,当然这个爬取的总页码也是可以通过爬取首页的页面得到
html = obj.get_list_html(x) range()取1到10之间的整数,能取到1,无法取到10
obj.parse_list_html(html)
DBTool.close_db_cursor() 关闭数据库、游标对象
fake_user_agent: pip install fake-useragent 这个第三方库,它维护了各种主流浏览器的UA标识,并且会定期的更新这个库,淘汰一些过期的UA。
数据库表:数据库保存在和.py文件同一文件夹下
运行结果:
数据库中保存信息: