平时我们在对网站进行数据抓取的时候,可以抓取一部分页面或者接口,这部分可能没有设置登录限制。但是如果要抓取大规模数据的时候,没有登录进行爬取会出现一些弊端。
- 对于一些设置登录限制的页面,无法爬取
- 对于一些没有设置登录的页面或者接口,一旦IP访问频繁,会触发网站的反爬虫
所以我们可以构建一个Cookies池,存储用户名和cookie的映射。
以下是它的功能模块
1 . 存储模块
功能:存储着用户名与密码,用户名与cookie。这里我们使用redis中的散列的数据结构来存储关系映射。在Python中使用redis这个库来获取连接。
redis库中对散列的操作方法
- hset(name,key,value) (为键名为name的hash表添加键值对)
- hget(name,key) (返回键名为name的hash表中key的值)
- hincrby(name,key,amount=1) (为键为name的hash表中key字段的值加上amount)
- hdel(name,*keys) (删除键名为name的hash表中的key的映射)
- hlen(name) (获取键名为name的hash表中键值对的个数)
- hkeys(name) (获取键名为name的hash表中的所有键值对的键名)
- hvals(name,key) (获取键名为name的hash表中的key的值)
- hgetall(name) (获取键名为name的所有键值对)
class RedisClient(object):
def __init__(self,type_,website):
self.client StrictRedis(host=REDIS_HOST,port=REDIS_PORT,\
password=REDIS_PASS)
self.website = website
self.type = type_
def name(self):
return "{type}:{website}".format(type=self.type,\
website=self.website)
def set(self,username,value):
return self.client.hset(self.name(),username,value)
def delete(self,username):
self.client.hdel(self.name(),username)
def count(self):
return self.client.hlen(self.name())
def get(self,username):
return self.client.hget(self.name(),username)
def username(self):
print(self.client.hkeys(self.name()))
return self.client.hkeys(self.name())
def all(self):
return self.client.hgetall(self.name())
def random(self):
return random.choice(self.client.hvals(self.name()))
2 . 生成模块
功能:是通过迭代取出accounts散列表(存储用户名和密码)中所有的用户名,判断在cookies散列表中是否有对应账号的cookies,如果没有,就调用模拟登录程序去获取cookie,然后写入redis中
class CookieGenator(object):
def __init__(self,website):
self.website = website
self.accounts = RedisClient('accounts',website)
self.cookies = RedisClient('cookies',website)
self.init_browser()
def init_browser(self):
# 根据浏览器类型初始化一个浏览器并返回
def __del__(self):
self.close()
def close(self):
# 执行关闭浏览器操作
def process_item(self,cookies):
# 遍历所有的cookie,取出每一个cookie的name和value字段,
# 组成一个json并返回
def run(self,accounts,cookies):
# 判断每一个账号是否生成对应的cookie
def new_cookies(self,username,password):
# 不同的站点获取的cookie的方式不同,所以不同的站点可以扩展该类
# 的子类,然后重写这个方法,实现各自获取cookies的方法
3 . 检测模块
功能:通过迭代拿出所有账号的Cookies,然后使用requets测试一下是否可用,如果返回的状态码不是200,那说明无效,把对应的用户名与cookie的映射删除。
class VerifyCookie(object):
def __init__(self,website="default"):
self.website = website
self.accounts = RedisClient("accounts",self.website)
self.cookies = RedisClient("cookies",self.website)
def test(self,username,cookie):
# 测试对应站点,返回200说明cookie有效
# 不同站点可以以此为父类进行扩展,重写该方法,实现自己的测试逻辑
def run(self):
# 迭代拿出所有的cookies,然后循环调用`test`方法测试是否可用
# 如果cookie失效,就在redis删除对应的键值对
4 . 接口模块
功能:为爬虫提供接口,用于获取随机cookie(Cookie池最终也是要被爬虫使用的,所以需要提供一个网页接口用于获取Cookies)
from flask import g,Flask
__all__ = ['app']
app=Flask(__name__)
def get_conn():
# 在g对象中设置属性
# key:散列表的键名与value:RedisClient对象的映射
# eg accounts:weibo ---- RedisClient("accounts","weibo")
@app.route("/")
def index():
# 首页内容
return "Welcome to Cookies Pool System
"
@app.route("//count")
def count(website):
# 获取cookies的数量
@app.route("//add//")
def add_attr(website,username,password):
# 通过在url中填入相应信息为散列表中添加对应站点的用户名和密码
@app.route("//random")
def random(website):
# 获取随机cookie
def run():
app.run()
5 . 调度模块
功能:开启三个进程,打开接口,生成Cookie,检测Cookie ,定时检测Cookie的可用性,生成Cookies,删除hash表中无用Cookies。
class Scheduler(object):
@staticmethod
def api():
print("API接口开始运行")
app.run(host=API_ADDRESS,port=API_PORT)
@staticmethod
def generate_cookies(cycle=CYCLE):
print("开始生成cookies")
while True:
try:
# 通过eval生成对应的生成器对象,然后生成Cookies
except Exception as e:
raise e
@staticmethod
def verify_cookies(cycle=CYCLE):
print("开始检查cookies")
while True:
# 通过eval动态生成对应的测试类对象,然后执行测试
def run(self):
# 开启三个进程,调用上面三个方法