利用Python实现简单HTTP代理验证
2017-03-05
原创作品:首发u3v3, 转载请保留
地址:https://www.u3v3.com/ar/1274
作者ID:noomrevils
首发日期:2017.3.5
Python学习群:278529278 (欢迎交流)
前言
需求
相信用python写过爬虫的人都有听说或使用过代理的经历,网络上提供了很多免费的代理,也有很多收费代理提取接口,但是实际在使用这些代理的时候,往往会有速度慢,无法连接,非高匿,插入广告或统计代码等种种问题,本文的初衷就是提供一个验证代理的思路和简版的代码实现,通过定时的任务可以验证代理的有效性,维护一个可用的代理池。
思路
为了实现验证的功能,需要有一个页面能够展示通过代理的请求信息,比如说,ip地址,请求头。 这些信息可以帮助判断代理是否高匿,同时检查这个页面返回html, 可以知道,代理是否向其中添加了额外的信息(广告,统计)
然后在client端,我们通过代理请求这个页面,解析返回的页面内容,完成代理可用性的验证
验证接口&页面实现
处理请求函数
Python的Web框架选用的是Bottle, 简单但能够说明问题。
from bottle import request, route, run, template
@route('/')
def index():
headers = {}
for key in request.headers.keys():
headers[key] = request.headers.get(key)
ip = request.environ.get('HTTP_X_FORWARDED_FOR') \
or request.environ.get('REMOTE_ADDR')
return template('proxy', headers=headers, ip=ip)
run(host='0.0.0.0', port=8000)
Bottle中requests.headers
是类似字典的class,为了能够在模板中使用请求头信息,把它拿到读取到python字典对象中,作为传入模板的参数,然后通过request.environ
,可以拿到真实请求的ip
请求信息页面
<html>
<head>
<title>proxy</title>
<style type="text/css">
body {font-family:arial, sans-serif;}
table {border-width: 1px; border-color: black; border-style: solid;}
.head {background-color:#6666ff; color:#ffffff;font-size:12pt;}
.http-header {background-color:#ffffff; color:#000000; border: 1px solid black;}
.meta {background-color:#eeeeee; color:#000000; border: 1px solid black;}
.small {font-size:9pt;}
</style>
</head>
<body>
<table border="0" cellpadding="2">
<tr>
<td class='meta'>Remote IP Address</td>
<td class='meta'><b>{{ip}}</b></td>
</tr>
<tr>
<th class="head">HTTP Header<b><sup>*</sup></b></th>
<th class="head">Value</th>
</tr>
% for key, value in headers.items():
<tr>
<td class='http-header'>{{ key }}</td>
<td class='http-header'><b>{{ value }}</b></td>
</tr>
% end
</table>
</html>
模板中我们只使用了table元素,没有额外的div,或者javascript src 引入,这是为了后面检查代理服务器是否对页面进行了修改。
...
% for key, value in headers.items():
<tr>
<td class='http-header'>{{ key }}</td>
<td class='http-header'><b>{{ value }}</b></td>
</tr>
% end
...
采用了Bottle自带模板语法,相信使用过django template 或者 jinja2的同学也不会陌生。
把服务跑起来
整个项目的结构,如下:
├── app.py
└── views
└── proxy.tpl
在终端执行 `python app.py` 就可以浏览器输入 http://127.0.0.1:8000 看到页面效果
验证请求端实现
有了代理请求访问的页面,下面来实现代理验证部分的内容,我们采用requests库来写一个验证脚本。 本篇的内容不包含如何获取免费代理,代理存储维护等细节,但是欢迎大家提出自己的想法和实现, 也许我们可以一起实现一个更好的版本
import requests
import re
ip_addr = re.compile(r'[0-9]+(?:\.[0-9]+){3}')
ad_inject = re.compile(r'iframe|src|div')
valided_proxies = []
headers = {
"Host": "http://example.com/proxy_verify/",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:50.0) Gecko/20100101 Firefox/50.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate, br",
"Content-Type": "text/plain",
"Connection": "keep-alive"
}
url='http://example.com/proxy_verify/'
proxies = [
"http://120.26.143.53:80",
"http://112.74.72.1:8080",
"http://60.178.165.222:8998",
"http://121.8.170.53:9797",
"http://144.0.68.46:808"
]
def run():
s = requests.session()
s.headers.update(headers)
for proxy in proxies:
s.proxies.update({'http': proxy})
r = s.get(url)
if r.status_code == requests.codes.ok:
content = r.text
proxy_ip = ip_addr.search(proxy).group()
match = ip_addr.search(content)
request_ip = match.group() if match else ''
if request_ip and proxy_ip == request_ip:
if not ad_inject.search(content):
valided_proxies.append(proxy)
print (valided_proxies)
if __name__ == '__main__':
run()
脚本中proxies是写死的,可以动态的可以从文件,缓存,数据库,接口等别的形式加载,下面来看下处理部分的逻辑
...
content = r.text
proxy_ip = ip_addr.search(proxy).group()
match = ip_addr.search(content)
request_ip = match.group() if match else ''
if request_ip and proxy_ip == request_ip:
if not ad_inject.search(content):
valided_proxies.append(proxy)
...
首先使用正则re.compile(r'[0-9]+(?:\.[0-9]+){3}')
从代理地址中提取代理的地址。
这个地址是我们预期被接口显示的地址, 然后再从http请求返回的html中解析出来服务端真实记录的ip,将这两个ip相比较我们就可以知道代理是否高匿。
然后我们再通过正则 ad_inject = re.compile(r'iframe|src|div')
来判断页面是否被插入了可疑的element。 完成这两个步骤后,我们可以将这个代理记录到有效代理的列表中。后续可以用来更新原有存储介质。
TODO
上面的方案,我们只是给出的思路和一个乞丐版的实现。可以探索的点非常多。可以以此为基础 探寻下去,相信能够学习到更多的知识。
- 使用异步的请求的框架,比如
aiohttp
,并行的验证大量代理地址。 - 使用
tornado
,aiohttp
等支持异步IO的web框架,提高接口页面的并发能力。 - 验证代理的请求头信息,和计算代理的连接速度。
- 做一个代理展示界面。把有效的代理可视化的展示出来。
- 爬取免费代理,去除重复,存在合适的地方,redis or mongodb?
- 支持https代理验证
- 通过cron等工具设置定时任务
欢迎大家留言讨论,或者加入我们的Python的QQ学习群(278529278)讨论,给出自己的实现。