专栏名称: Python中文社区
致力于成为国内最好的Python开发者学习交流平台,这里有关于Python的国内外最新消息,每日推送有趣有料的技术干货和社区动态。 官方网站:www.python-cn.com
目录
相关文章推荐
51好读  ›  专栏  ›  Python中文社区

进击的爬虫:用Python搭建匿名代理池

Python中文社区  · 公众号  · Python  · 2016-11-28 21:41

正文

请到「今天看啥」查看全文


專 欄


苍冥 ,Python中文社区专栏作者,澳洲华裔,目前在墨尔本某国际咨询公司任职Splunk Developer,擅长网络安全及攻防,热爱Python及爬虫,同时在学习Machine Learning。

邮箱: [email protected]

Github: github.com/eastrd

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. for Raw_ProxyInfo in 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. class ProxyPool :

  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. if OrigionalIP != MaskedIP :

  19. return True

  20. else :

  21. return False

  22. except :

  23. return False


  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 info in self . 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. if OrigionalIP != MaskedIP :

  18. return True

  19. else :

  20. return False

  21. except :

  22. return False


04 反思

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

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

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

05 完整代码

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

ARTICLES
近期热门文章



生成器

关于生成器的那些事儿

爬虫代理

如何构建爬虫代理服务

地理编码

怎样用Python实现地理编码

nginx日志

使用Python分析nginx日志


淘宝女郎

一个批量抓取淘女郎写真图片的爬虫

IP代理池

突破反爬虫的利器——开源IP代理池

布隆去重

基于Redis的Bloomfilter去重(附代码)

QQ空间爬虫

QQ空间爬虫最新分享,一天 400 万条数据


在公众号底部回复上述关键词可直接打开相应文章



我 们 终 将 改 变 潮 水 的 方 向

§ §

Python中文社区
www.python-cn.com

致力于成为

国内最好的Python社区


QQ群:152745094

专栏作者申请邮箱

[email protected]

— Life is short,we use Python —













请到「今天看啥」查看全文


推荐文章
理想聚焦  ·  看起来,只有这招才能救美国了
8 年前
肌肉男训练营  ·  可能是最简单有效的增肌计划
8 年前
趣拾家  ·  马伊琍:有一种胜利来自煎熬
8 年前