因爲在爬蟲的時候經常經常會遇到封IP 的情況,那麼使用代理就可以解決這個問題。
池子裏面放一些代理,而且需要定期的檢查。
互聯網上公開了大量的免費代理,而且互聯網上也有付費的代理。
代理池的要求:
1.多站抓取,異步檢測
2.定時篩選,持續更新
3.提供接口,易於提取
代理池的架構
開始搭建代理池。
主要是借鑑 github上Germey的代理池的實現
https://github.com/germey/proxypool
下面看看介紹一下源碼。其實我也是看作者的視頻學習他的代碼的。
def main():
s = Schedule()
s.run()
app.run()
代碼在 run.py 中首先實例化了一個 調度器。 並且執行了run()方法。。
s.run() 是運行調度器,和檢驗,添加,刪去代理相關。
app.run() 是啓動起來flask框架。提供api接口相關的。實例化一個redisclient對象。並且可以調用redis的相關方法。
先說一下 redis的處理函數:
get() 從隊列左側拿出一個代理
put() 從隊列右側放進去一個代理
pop() 從右側彈出一個代理
queue_len() 獲得隊列長度
flush() 清空隊列
講解一下Schedule調度器的實現。
下面的代碼是 Schedule調度器的代碼:
class Schedule(object):
@staticmethod
def valid_proxy(cycle=VALID_CHECK_CYCLE):
"""
Get half of proxies which in redis
"""
conn = RedisClient()
tester = ValidityTester()
while True:
print('Refreshing ip')
count = int(0.5 * conn.queue_len)
if count == 0:
print('Waiting for adding')
time.sleep(cycle)
continue
raw_proxies = conn.get(count)
tester.set_raw_proxies(raw_proxies)
tester.test()
time.sleep(cycle)
@staticmethod
def check_pool(lower_threshold=POOL_LOWER_THRESHOLD,
upper_threshold=POOL_UPPER_THRESHOLD,
cycle=POOL_LEN_CHECK_CYCLE):
"""
If the number of proxies less than lower_threshold, add proxy
"""
conn = RedisClient()
adder = PoolAdder(upper_threshold)
while True:
if conn.queue_len < lower_threshold:
adder.add_to_queue()
time.sleep(cycle)
def run(self):
print('Ip processing running')
valid_process = Process(target=Schedule.valid_proxy)
check_process = Process(target=Schedule.check_pool)
valid_process.start()
check_process.start()
執行了run方法之後,開啓了兩個進程。
一個是定時檢測 代理池中的 ip是否有效,另一個是檢測池子中的ip個數是否滿足要求。
第一個 方法: 定時檢測代理池中的ip是否有效 。
def valid_proxy(cycle=VALID_CHECK_CYCLE): 是定時檢測方法。其中的VALID_CHECK_CYCLE 是循環檢測的週期間隔。
valid_proxy 方法在實例化連接redis之後,又實例化了一個檢測是否有效的一個類。每次取出一半隊列長度的代理。
具體的檢測過程是在以下代碼實現的。(這是一個異步檢測。py3.6 )
async def test_single_proxy(self, proxy):
"""
text one proxy, if valid, put them to usable_proxies.
"""
try:
async with aiohttp.ClientSession() as session:
try:
if isinstance(proxy, bytes):
proxy = proxy.decode('utf-8')
real_proxy = 'http://' + proxy
print('Testing', proxy)
async with session.get(self.test_api, proxy=real_proxy, timeout=get_proxy_timeout) as response:
if response.status == 200:
self._conn.put(proxy)
print('Valid proxy', proxy)
except (ProxyConnectionError, TimeoutError, ValueError):
print('Invalid proxy', proxy)
except (ServerDisconnectedError, ClientResponseError,ClientConnectorError) as s:
print(s)
pass
第二個 方法 : 檢測代理池中的代理ip是否夠用。不夠的話,就向一些代理網站上取一些代理ip。並且檢驗有效之後就添加進到代理池。
def add_to_queue(self):
print('PoolAdder is working')
proxy_count = 0
while not self.is_over_threshold():
for callback_label in range(self._crawler.__CrawlFuncCount__):
callback = self._crawler.__CrawlFunc__[callback_label]
raw_proxies = self._crawler.get_raw_proxies(callback)
# test crawled proxies
self._tester.set_raw_proxies(raw_proxies)
self._tester.test()
proxy_count += len(raw_proxies)
if self.is_over_threshold():
print('IP is enough, waiting to be used')
break
if proxy_count == 0:
raise ResourceDepletionError
這裏的 for callback_label in range(self._crawler.__CrawlFuncCount__): 是一個很厲害的實現。
他將getter.py裏的關於得到代理ip的網站的函數放到列表裏。然後挨個執行一遍。具體實現如下
"""
元類,在FreeProxyGetter類中加入
__CrawlFunc__和__CrawlFuncCount__
兩個參數,分別表示爬蟲函數,和爬蟲函數的數量。
"""
def __new__(cls, name, bases, attrs):
count = 0
attrs['__CrawlFunc__'] = []
for k, v in attrs.items():
if 'crawl_' in k:
attrs['__CrawlFunc__'].append(k)
count += 1
attrs['__CrawlFuncCount__'] = count
return type.__new__(cls, name, bases, attrs)
如果還想添加一個網站的抓取。
只要再添加一個crawl_開頭的一個方法就好了。