平時我們在對網(wǎng)站進行數(shù)據(jù)抓取的時候,可以抓取一部分頁面或者接口,這部分可能沒有設(shè)置登錄限制徘溢。但是如果要抓取大規(guī)模數(shù)據(jù)的時候吞琐,沒有登錄進行爬取會出現(xiàn)一些弊端。
- 對于一些設(shè)置登錄限制的頁面然爆,無法爬取
- 對于一些沒有設(shè)置登錄的頁面或者接口顽分,一旦IP訪問頻繁,會觸發(fā)網(wǎng)站的反爬蟲
所以我們可以構(gòu)建一個Cookies池施蜜,存儲用戶名和cookie的映射卒蘸。
以下是它的功能模塊
Cookies池架構(gòu).png
1 . 存儲模塊
功能:存儲著用戶名與密碼,用戶名與cookie翻默。這里我們使用redis中的散列的數(shù)據(jù)結(jié)構(gòu)來存儲關(guān)系映射缸沃。在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表中鍵值對的個數(shù))
- 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散列表中是否有對應(yīng)賬號的cookies,如果沒有柬唯,就調(diào)用模擬登錄程序去獲取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):
# 根據(jù)瀏覽器類型初始化一個瀏覽器并返回
def __del__(self):
self.close()
def close(self):
# 執(zhí)行關(guān)閉瀏覽器操作
def process_item(self,cookies):
# 遍歷所有的cookie,取出每一個cookie的name和value字段锄奢,
# 組成一個json并返回
def run(self,accounts,cookies):
# 判斷每一個賬號是否生成對應(yīng)的cookie
def new_cookies(self,username,password):
# 不同的站點獲取的cookie的方式不同失晴,所以不同的站點可以擴展該類
# 的子類,然后重寫這個方法拘央,實現(xiàn)各自獲取cookies的方法
3 . 檢測模塊
功能:通過迭代拿出所有賬號的Cookies涂屁,然后使用requets測試一下是否可用,如果返回的狀態(tài)碼不是200灰伟,那說明無效拆又,把對應(yīng)的用戶名與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):
# 測試對應(yīng)站點袱箱,返回200說明cookie有效
# 不同站點可以以此為父類進行擴展遏乔,重寫該方法,實現(xiàn)自己的測試邏輯
def run(self):
# 迭代拿出所有的cookies发笔,然后循環(huán)調(diào)用`test`方法測試是否可用
# 如果cookie失效,就在redis刪除對應(yīng)的鍵值對
4 . 接口模塊
功能:為爬蟲提供接口凉翻,用于獲取隨機cookie(Cookie池最終也是要被爬蟲使用的了讨,所以需要提供一個網(wǎng)頁接口用于獲取Cookies)
from flask import g,Flask
__all__ = ['app']
app=Flask(__name__)
def get_conn():
# 在g對象中設(shè)置屬性
# key:散列表的鍵名與value:RedisClient對象的映射
# eg accounts:weibo ---- RedisClient("accounts","weibo")
@app.route("/")
def index():
# 首頁內(nèi)容
return "<h2>Welcome to Cookies Pool System</h2>"
@app.route("/<website>/count")
def count(website):
# 獲取cookies的數(shù)量
@app.route("/<website>/add/<username>/<password>")
def add_attr(website,username,password):
# 通過在url中填入相應(yīng)信息為散列表中添加對應(yīng)站點的用戶名和密碼
@app.route("/<website>/random")
def random(website):
# 獲取隨機cookie
def run():
app.run()
5 . 調(diào)度模塊
功能:開啟三個進程,打開接口,生成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生成對應(yīng)的生成器對象,然后生成Cookies
except Exception as e:
raise e
@staticmethod
def verify_cookies(cycle=CYCLE):
print("開始檢查cookies")
while True:
# 通過eval動態(tài)生成對應(yīng)的測試類對象伶棒,然后執(zhí)行測試
def run(self):
# 開啟三個進程旺垒,調(diào)用上面三個方法