程序主代码(详情标注)
# -*- coding: utf-8 -*-
__author__ = '木之易'
__date__ = '2018/8/7 11:20'
from urllib import request
import re
import sqlite3
from tools import StrTools
"""
QsbkSpider
url 地址
html 网页源代码
headers 请求头
conn 数据库连接
cursor 数据库游标
connect_sql() 连接数据库
close_sql() 关闭数据库
create_table() 创建数据表
get_html() 获取网页源代码
parse_html() 解析网页源代码,提取数据
save_data() 保存数据
get_next_link() 获取下一页链接
run()启动程序
"""
class QsbkSpider(object):
def __init__(self):
# 1.准备请求的url地址
self.url = 'https://www.qiushibaike.com/hot/'
self.html = ''
# 如果不加请求头,默认情况下User-Agent是Python开头的
# 会导致对方服务器发现你是一段爬虫程序,拒绝返回数据
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0'
}
self.conn = None
self.cursor = None
self.create_table()
def connect_sql(self):
"""连接数据库,获取游标"""
self.conn = sqlite3.connect('sqbk.db')
self.cursor = self.conn.cursor()
def close_sql(self):
"""关闭数据库"""
# 提交操作
self.conn.commit()
# 关闭游标
self.cursor.close()
# 关闭数据库
self.conn.close()
def create_table(self):
# 1.链接数据库
self.connect_sql()
# 2.准备sql语句
sql = 'CREATE TABLE IF NOT EXISTS qsbk(id INTEGER PRIMARY KEY, author CHAR, age INTEGER ,content TEXT, smile_num INTEGER ,comments INTEGER)'
# 3.执行sql
self.cursor.execute(sql)
# 4.关闭
self.close_sql()
def get_html(self):
"""构建请求,发送请求,接收响应数据"""
# 构建请求对象
req = request.Request(url=self.url, headers=self.headers)
# 发请求,获取源代码
response = request.urlopen(req)
# 将返回的数据读取并转换为字符串,赋值给对象的html属性
self.html = response.read().decode('utf-8')
def parse_html(self):
"""准备正则,提取网页数据"""
# 准备正则
pattern = re.compile(r'<h2>(.*?)</h2>.*?<div class="articleGender.*?>(.*?)</div.*?<div class="content".*?<span>(.*?)</span>.*?<i class="number">(.*?)</i.*?<i class="number">(.*?)</i>', re.S)
# 使用findall()函数 查找所有用户
results = re.findall(pattern, self.html)
for r in results:
# 处理字符串
author = StrTools.process_str(r[0])
age = r[1]
content = StrTools.process_str(r[2])
smile_num = r[3]
comments = r[4]
self.save_data(author, age, content, smile_num, comments)
def save_data(self, *args):
"""保存数据"""
# 1.连接数据库
self.connect_sql()
# 2.准备sql语句
sql = "INSERT INTO qsbk(author,age,content,smile_num,comments)VALUES('%s',%s,'%s',%s,%s)" % args
# 3.执行sql
self.cursor.execute(sql)
# 4.关闭
self.close_sql()
def get_next_link(self):
"""
获取下一页链接"
:return: True 表示找到下一页,可以继续执行循环 False表示没有找到下一页,可以结束循环
"""""
# 1.找到ul标签部分的html代码
pattern = re.compile(r'<ul class="pagination".*?</ul>', re.S)
# search() 1.正则表达式 2.要进行查找的字符串
res = re.search(pattern, self.html)
# 若找到
if res:
# group() 获取分组信息
# 获取ul包裹的标签代码
ul_html = res.group()
# 再次使用正则从ul包裹的标签代码中提取所有页的链接
links = re.findall(re.compile(r'<li.*?<a href="(.*?)"', re.S), ul_html)
# 判断链接地址是否包含page字符,若包含则有下一页,若不包含则无下一页
if 'page' in links[-1]:
# 拼接下一页完整地址
self.url = 'https://www.qiushibaike.com' + links[-1]
return True
else:
return False
else:
return False
def run(self):
# 爬取页数初始值为零,每爬完一页,页数加1
count = 0
while True:
self.get_html()
count += 1
print('正在爬取第%s页数据,请稍后.....' % count)
self.parse_html()
print('第%s页数据爬取完成,已入库!' % count)
is_next = self.get_next_link()
if not is_next:
print('数据爬取完毕,已存入数据库中!')
break
if __name__ == '__main__':
qsbk = QsbkSpider()
qsbk.run()
新建一个tools文件,内写入工具类,用来清理正则表达式中无法在写正则时过滤的字符
# -*- coding: utf-8 -*-
__author__ = '木之易'
__date__ = '2018/8/7 11:20'
import re
class StrTools(object):
"""
建立一个工具类
"""
@staticmethod
# 静态函数,可用类直接调用函数,不必再创建对象
def process_str(string):
"""
处理字符串中的特殊字符
:param string: 要进行处理的字符串
:return: 处理之后的字符串
"""
string = string.strip('\n')
# 准备替换br的正则
pattern = re.compile(r'<br/><br/>|<br/>|<br>')
string = re.sub(pattern, '\n', string)
return string