python3+re 爬虫爬取笔趣阁小说 斗罗大陆IV终极斗罗
爬取前准备
导入的模块
import redis #redis数据库 存储指纹
import re #正则查询
import pymongo # mongo数据库 存储数据
import requests #发请求
from hashlib import md5 #生成指纹(加密)
from fake_useragent import UserAgent #伪造 headers
分析
增量爬虫?
1】引言
当我们在浏览相关网页的时候会发现,某些网站定时会在原有网页数据的基础上更新一批数据,
例:1. 某电影网站会实时更新一批最近热门的电影
2. 小说网站会根据作者创作的进度实时更新最新的章节数据等等
当我们在爬虫的过程中遇到时,我们是否需要只爬取网站中最近更新的数据,而不每次都做全量爬虫呢?
【2】概念
通过爬虫程序监测某网站数据更新的情况,以便可以爬取到该网站更新出的新数据
增量实现
【1】原理
1.1》在发送请求之前判断这个URL是不是之前爬取过
适用场景:‘不断有新页面出现的网站,比如说小说的新章节,每天的最新新闻等’
1.2》在解析内容后判断这部分内容是不是之前爬取过
适用场景:‘页面内容会更新的网站’
【2】实现
2.1》将爬取过程中产生的url进行存储,存储在redis的set中。当下次进行数据爬取时,首先对即将要发起的请求对应的url在存储的url的set中做判断,如果存在则不进行请求,否则才进行请求。
2.2》对爬取到的网页内容进行唯一标识的制定,然后将该唯一表示存储至redis的set中。当下次爬取到网页数据的时候,在进行持久化存储之前,首先可以先判断该数据的唯一标识在redis的set中是否存在,在决定是否进行持久化存储
正则的贪婪与非贪婪
了解正则表达式
-
贪婪匹配(默认)
1、在整个表达式匹配成功的前提下,尽可能多的匹配 * + ? 2、表示方式:.* .+ .?
-
非贪婪匹配
1、在整个表达式匹配成功的前提下,尽可能少的匹配 * + ? 2、表示方式:.*? .+? .??
-
本次爬取使用的代码示例
# <a style="" href="/5_5607/3182286.html">第一章 那是什么?</a>
regex='<a style="" href="(.*?)">(.*?)</a>'
# 晒选需要的数据
- 了解完啦?准备发车了
附完整代码示例
# -*- coding: UTF-8 -*-
'''
PyCharm
@Project :
@File :redis_href.py
@Author :淮南子.
@Date :2021/1/1
'''
import time # 爬取时如果大量请求需要适当降低频率
# 本次发请求少没使用的
import redis #redis数据库 存储指纹
import re #正则
import pymongo # pymongo数据库 存储数据
import requests #发请求
from hashlib import md5 #生成指纹(加密)
from fake_useragent import UserAgent #伪造 headers
#笔趣阁小说 斗罗大陆IV终极斗罗
#增量爬虫
class NovelSpider:
def __init__(self):
self.headers={'User-Agent':UserAgent().random}
self.url='http://www.biquge6.com/5_5607/'
# 连接数据库
self.r=redis.Redis(host='localhost',port=6379,db=0)
#连接数据库
self.cont=pymongo.MongoClient('localhost',27017)
# Mongo库
self.db=self.cont['noveldb']
# Mongo表
self.myset=self.db['novelset']
def get_html(self,url):
'''获取页面'''
html=requests.get(url=url,headers=self.headers).text
return html
def md5_href(self,href):
'''生成指纹'''
m_href=md5()
m_href.update(href.encode())
# 返回加密后的数据
return m_href.hexdigest()
def databse(self,data):
'''数据库存储'''
self.myset.insert_one(data)
def data(self):
'''数据解析'''
html=self.get_html(url=self.url)
#使用正则获取需要的数据
regex='<a style="" href="(.*?)">(.*?)</a>'
result_list=re.findall(regex,html)
# print(result)
for result in result_list:
item={} #创建一个字典存放数据方便数据库存储
#正则获取的是元组
item['href']=result[0]
item['chapter']=result[1]
# print(item)
finger = self.md5_href(item['href'])
# redis 验证是否抓取过
if self.r.sadd('novel:spiders', finger) == 1:
print('章节有更新,开始抓取... ...')
# 拼接完整的详情url
# http://www.biquge6.com/5_5607/3182286.html
# http://www.biquge6.com/5_5607/3189896.html
print(self.url+item['href'].split('/',1)[1])
# 新章节可以继续处理
#这里存储 href chapter
self.databse(item)
else:
# 已抓取过的跳过
#
print('章节未更新,跳过此章节')
def crawl(self):
'''执行函数'''
self.data()
if __name__ == '__main__':
novel=NovelSpider()
novel.crawl()
查看数据存储
- redis 数据库
# 连接redis
redis-cli
## 查看所有键
keys *
## 查看集合中所有元素
SMEMBERS key
如图所示
数据过多截取展示部分
- Mongodb 数据库
## 进入命令行:
mongo
#查看所有库:
show dbs
#切换库:
use 库名
#查看库中集合:
show tables
#查看集合文档:
db.集合名.find().pretty()
#统计文档个数:
db.集合名.count()
如图所示:
每一年的今天,都是一个全新的开始,新的一年,愿大家万事顺遂,所得皆所愿!