经过Flask和Redis构造一个动态维护的代理池

代理池的维护

目前有不少网站提供免费代理,并且种类齐全,好比各个地区、各个匿名级别的都有,不过质量实在不敢恭维,毕竟都是免费公开的,可能一个代理无数我的在用也说不定。因此咱们须要作的是大量抓取这些免费代理,而后筛选出其中可用的代理存储起来供咱们使用,不可用的进行剔除。python

 

获取代理的途径

 维护一个代理池第一步就是要找到提供免费代理的站点,例如PROXY360,网页内容以下:git

 

 

并且能够看到网页里提供了一些免费代理列表,包括服务器地址、端口、代理种类、地区、更新时间等等信息。github

当前咱们须要的就是代理服务器和端口信息,将其爬取下来便可。redis

维护代理

那么问题来了,当咱们把这些免费的代理爬取下来后,该怎么去保存他们?
数据库

首先咱们须要确保这个数据库能够是咱们边存边取,另外还须要定时检查队列中那些过时的代理并将它们剔除,因此须要易于存取。服务器

另外怎么区分代理的新旧,若是按照代理网站上给出的代理的修改时间来标识是可行的,可是更简单的方法就是维护一个队列,确保只从一端存入,例如右端,这样就能确保最新的代理一直处于队列的右段,而在队列左端的则是存取时间较长的,那么在使用时咱们就能够提取队列右端的代理来使用。app

那么对于队列左端的代理咱们也不能就这么任其老化,还要作的操做就是把左端的代理提取出来,进行测试,将那些可使用的放入队列右端,不能使用了的则剔除队列。测试

经过以上操做,就保证了队列里的代理一直处于可用状态。网站

因此从目前来看,既能高效处理,又能够作到队列动态维护,合适的方法就是使用Redis数据库的队列。url

 

下面这张流程图就是整个代理队列须要具有的功能:

 

能够定义一个类来维护一个Redis队列,好比get方法是从左端取出,put方法是从右端放入,pop方法时从右端取出可用代理。

 

import redis
from proxypool.error import PoolEmptyError
from proxypool.setting import HOST,PORT,PASSWORD

class RedisClient(object):
  def __init__(self,host=HOST,port=PORT,password=PASSWORD):
    if password:
      self._db = redis.Redis(host,port,password)
    else:
      self._db = redis.Redis(host,port)

  def get(self, count=1):
    proxies = self._db.Irange("proxies",0, count - 1)
    self._db.Itrim("proxis", count, -1)
    return proxies

  def put(self,proxy):
    self._db.rpush("proxies", proxy)

  def pop(self,self):
    try:
      self._db.rpop("proxies").decode('utf-8')
    except:
      raise PoolEmptyError

 

 

  

 

检测代理

那么如何来检测代理是否可用呢?可使用这个代理来请求某个网站,若是返回的200则证实这个代理可用,不然代理不可以使用。

 

conn = RedisClient()
proxies = {'http': proxy}
r = requests.get(url,proxies=proxies)
if r.status_code == 200:
  conn.put(proxy)

  

例如在这里proxy就是要检测的代理,使用requests库设置好这个代理,而后请求百度,正常请求,那就能够将这个代理存入Redis。

 

 

获取可用代理

如今咱们维护了一个代理池,那么这个代理池须要是能够公用的。

好比如今有多个爬虫项目都须要用到代理,而代理池的维护做为另外的一个项目,他们之间若是要创建链接,最恰当的方式就是接口。

因此能够利用Web服务器来实现一个接口,其余的项目经过请求这个接口获得内容获取到一个可用代理,这样保证了代理池的通用性。

因此要实现这个还须要一个Web服务器,例如Flask,Tornado等等。

例如使用Flask,定义一个路由,而后调用的RedisClient的pop方法,返回结果便可。

 

@app.route('/get')
def get_proxy():
   conn = RedisClient()    
  return conn.pop()

  

这样一来,整个程序运行起来后,请求网页就能够看到一个可用代理了。  

 

 

使用代理

使用代理只须要请求这个站点,就能够拿到使用的代理了。

 

def get_proxy():
    r = requests.get('http://127.0.0.1:5000/get')
    proxy = r.text
    return proxy

def crawl(url, proxy):
    proxies = {'http': get_proxy()}
    r = requests.get(url, proxies=proxies)
    #do something
    

 

  

 

  

样例实现  

 

https://github.com/gzf1234/ProxyPool

相关文章
相关标签/搜索