用Python搭建匿名代理池

来源:互联网 发布:淘宝运营托管 编辑:程序博客网 时间:2024/06/10 15:18

01 写在前面

       常听到很多人抱怨自己的IP因爬虫次数太多而被网站屏蔽,不得不频繁使用各种代理IP,却又因为网上的公开代理大部分都是不能使用,而又要花钱花精力去申请VIP代理,几番波折又遭屏蔽。特此写一篇如何利用Python搭建代理池的文章,以降低时间及精力成本,实现自动化获取活跃代理IP的功能。

 

02 运作原理

一、 网站代理获取

1.   爬免费代理网站的IP列表测试是否可用及是否是高匿

2.   若都是,则放进数据库,否则丢弃。

3.   重复第2步

 

二、 保证失效的代理能被尽快从代理池中挑出

1.   从爬虫数据库获取IP

2.   测试IP的可用性和匿名性

3.   如果可用且匿名,则保留,否则丢弃。

4.   重复第1步

 

说明①:可建立一个爬虫程序守护程序(Daemon),有此方面需要的小伙伴可自行谷歌,在此不多做介绍。

说明②:可建立一个对外代理信息接口,无论你用NodeJS或者Flask/Django或者PHP来写都没关系,在此也不多做介绍。

 

03 实现

       建议库: requests, BeautifulSoup, re, sqlite3。

       其中,用requests库获取代理网站页面,用BeautifulSoup和re两库来进行代理信息获取,用sqlite3来对这些信息进行存取。

       如果必要(如代理网站有反爬虫策略时),可用PhantomJS替代requests,或用相应库进行数据清理(如base64解码)。

 

下面简单展示一下各部分的代码:

       首先是选择多个能爬取代理且不容易被屏蔽IP的网站,此处以proxy-list.org为例:


  1. BASE_URL="https://proxy-list.org/english/index.php?p="


  2. #IP地址及端口的正则

  3. Re_Pattern_IP= re.compile("(.*):")

  4. Re_Pattern_PORT= re.compile(":(.*)")


  5. #网站有11页,所以循环11次获取所有代理IP及端口

  6. for startingURL_Param in range(1,11):

  7.    HTML_ProxyPage = requests.get(BASE_URL+str(startingURL_Param)).content

  8.    soup = bs(HTML_ProxyPage,"html.parser")

  9.    forRaw_ProxyInfoin soup.find_all("ul",{"class":None}):

  10.        #此网站有用Base64简单对代理进行了加密,所以这里对其解码

  11.        ip_port = base64.b64decode(Raw_ProxyInfo.find("li",{"class":"proxy"}).text.replace("Proxy('","").replace("')",""))

  12.        #接下来利用正则从网页数据中提取我们需要的信息

  13.        IP = re.findall(Re_Pattern_IP, ip_port)[0]

  14.        PORT = re.findall(Re_Pattern_PORT, ip_port)[0]

  15.        TYPE =Raw_ProxyInfo.find("li",{"class":"https"}).text

 

       接下来是一段简易代理池框架类的代码,提供代理数据库的添加、删除、可连接性检测、匿名性检测:

 

  1. classProxyPool:        

  2.    #初始化爬虫池数据库

  3.    def __init__(self,ProxyPoolDB):

  4.        self.ProxyPoolDB=ProxyPoolDB

  5.        self.conn= sqlite3.connect(self.ProxyPoolDB, isolation_level=None)

  6.        self.cursor=self.conn.cursor()

  7.        self.TB_ProxyPool="TB_ProxyPool"

  8.        self.cursor.execute("CREATE TABLE IF NOT EXISTS "+self.TB_ProxyPool+"(ip TEXT UNIQUE, port INTEGER, protocol TEXT)")


  9.    #添加代理IP进代理池的接口

  10.    def addProxy(self, IP, PORT, PROTOCOL):  

  11.        self.cursor.execute("INSERT OR IGNORE INTO "+self.TB_ProxyPool+"(ip, port, protocol) VALUES (?,?,?)",[IP,PORT,PROTOCOL])


  12.    #检查代理的匿名性及可连接性

  13.    def testConnection(self, IP, PORT, PROTOCOL):

  14.        proxies ={ PROTOCOL: IP+":"+PORT}

  15.        try:

  16.            OrigionalIP= requests.get("http://icanhazip.com", timeout=REQ_TIMEOUT).content

  17.            MaskedIP= requests.get("http://icanhazip.com", timeout=REQ_TIMEOUT, proxies=proxies).content

  18.            ifOrigionalIP!=MaskedIP:

  19.                returnTrue

  20.            else:

  21.                returnFalse

  22.        except:    

  23.            returnFalse


  24.    #删除代理IP对应的数据库记录

  25.    def delRecord(self, IP):

  26.        self.cursor.execute("DELETE FROM "+self.TB_ProxyPool+" WHERE ip=?",(IP,))



       下面是对代理池进行去“失效IP”的代码:   


  1.    #循环代理池,逐行测试IP地址端口协议是否可用

  2. def cleanNonWorking(self):

  3.    for infoinself.cursor.execute("SELECT * FROM "+self.TB_ProxyPool).fetchall():

  4.        IP = info[0]

  5.        PORT = str(info[1])

  6.        PROTOCOL = info[2].lower()


  7.        isAnonymous =self.testConnection(IP,PORT,PROTOCOL)

  8.        if isAnonymous==False:

  9.            #这条代理的可用性失效了,从数据库里删除

  10.            self.delRecord(IP)


  11. #通过检测icanhazip.com回显来检测可用性及匿名性

  12. def testConnection(self, IP, PORT, PROTOCOL):

  13.        proxies ={ PROTOCOL: IP+":"+PORT}

  14.        try:

  15.            OrigionalIP= requests.get("http://icanhazip.com", timeout=REQ_TIMEOUT).content

  16.            MaskedIP= requests.get("http://icanhazip.com", timeout=REQ_TIMEOUT, proxies=proxies).content

  17.            ifOrigionalIP!=MaskedIP:

  18.                returnTrue

  19.            else:

  20.                returnFalse

  21.        except:    

  22.            returnFalse


04 反思

       这个项目是我年初时用Python练手写的,以现在的程度再来回顾,逻辑不够严谨,各类功能太过耦合,不少段落需要重写,因为代码是在校园网内所跑,所以还需要考虑到网络连接的稳定性,这就造成部分代码之间的混乱关系。

       通过icanhazip.com来检测代理匿名性的方法或许有效,但却忽略了X-Forwarded-For的HTTP头,所以有很大风险,必须改进。

       验证代理池内代理的有效性,需要多线程,目前的方案效率太低。

 

05 完整代码

       放在此文章中的是代理池的核心代码,旨在提供各位读者能够自己实现的思路及参考。完整代码可在作者的Github主页中找到,Ubuntu 16.04及Kali下用Python 2.7测试可运行。


0 0