使用爬虫的时候肯定会有频繁访问某一网站的情况,这个时候有些服务器会识别到这是非正常访问,就会把请求的IP禁掉,这个时候就需要用代理了。就好比现实生活中,我需要向A借一件东西,但是我跟A是仇人,直接向他借的话他不会借给我,这个时候我就让B帮我向A借,就说他要用,然后B借到东西之后再把东西给我用,这时,B就是我的代理了。
代理选择
针对不需要用户登录,cookie验证的网站,一般选择动态高匿代理。
对于需要用户登录,身份认证的。一般选择静态IP。
代理获取
使用代理时一般需要建一个代理池,从代理池中获取有效代理,然后通过代理去访问内容网站。
本节将结合代码介绍代理池的使用。
为了使用方便,web框架简单使用flask。api接口类如下:
from flask import Flask, jsonify
from proxy.ProxyManager import ProxyManager
app = Flask('ProxyPool')
@app.route("/")
def hello():
return "Hello coder"
# 随机返回一个代理
@app.route("/get")
def get():
return jsonify(ProxyManager().get())
# 返回所有有效代理
@app.route("/get_all")
def get_all():
return jsonify(ProxyManager().get_all())
# 返回代理数据库代理数量
@app.route("/get_status")
def get_status():
return jsonify(ProxyManager().get_status())
if __name__ == '__main__':
app.run()
代理管理类ProxyManager如下:
# coding=utf-8
from ProxyGetter import ProxyGetter
from dao.RedisClient import RedisClient
class ProxyManager(object):
"""
代理管理类
"""
def __init__(self):
self.db_client = RedisClient()
def refresh(self):
for proxy in ProxyGetter.get_proxy_one():
self.db_client.put(proxy, 'raw')
def get(self):
return self.db_client.get()
def get_all(self):
return self.db_client.get_all()
def get_status(self):
return self.db_client.get_status()
if __name__ == '__main__':
m = ProxyManager()
m.refresh()
print(m.get_all())
print(m.get_status())
db使用redis做数据库:
# coding: utf-8
from base.base_redis import redis_client
class RedisClient(object):
def __init__(self):
self.redis_client = redis_client
def get(self):
# 随机返回集合成员
proxy = self.redis_client.srandmember('useful')
if proxy:
return proxy.decode('ascii')
return None
def put(self, proxy, sname='useful'):
return self.redis_client.sadd(sname, proxy)
def get_all(self):
# 返回全部集合成员
proxies = self.redis_client.smembers('useful')
if proxies:
proxy_list = []
for i in proxies:
proxy_list.append(i.decode('ascii'))
return proxy_list
return None
def get_status(self):
status = dict()
# 获取集合的成员数
status['useful'] = self.redis_client.scard('useful')
status['raw'] = self.redis_client.scard('raw')
return status
if __name__ == '__main__':
r = RedisClient()
print r.get()
redis_client如下:
import redis
import settings
redis_host = settings.get('redis', 'host')
redis_port = settings.get('redis', 'port')
redis_client = redis.Redis(redis_host, redis_port)
其中settings为配置解析文件,在config配置文件中配置参数,通过settings进行解析。settings文件在博主之前的ORM框架之Sqlalchemy一文中介绍过。
代理获取类如下:
import logging
from util.UtilFunction import get_html_tree
class ProxyGetter(object):
def __init__(self):
pass
@classmethod
def get_proxy_one(cls):
url = "http://www.xicidaili.com/nn/"
html_tree = get_html_tree(url)
proxies = html_tree.xpath('//table[@id="ip_list"]//tr')[1::]
for p in proxies:
try:
ip = p.xpath('.//td[2]/text()')[0]
port = p.xpath('.//td[3]/text()')[0]
yield ip + ":" + port
except Exception, e:
logging.exception(e)
if __name__ == '__main__':
for i in ProxyGetter.get_proxy_one():
print i
这里以西刺为例,获取其提供的高匿代理。当然,实际上免费代理很多都是无效的,无法使用的,因此在使用之前需要进行验证代理有效性。
代理解析工具类UtilFunction.py如下:
from WebRequest import WebRequest
from lxml import etree
def get_html_tree(url):
wr = WebRequest()
html = wr.get(url).content
return etree.HTML(html)
WebRquest类如下:
# coding:utf-8
import requests
class WebRequest(object):
def __init__(self):
pass
@property
def header(self):
headers = {
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Connection': 'keep-alive',
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) ' \
'Chrome/62.0.3202.94 Safari/537.36'
}
return headers
def get(self, url, header=None):
headers = self.header # 公共header
if header and isinstance(header, dict):
headers.update(header)
html = requests.get(url, headers=headers)
return html
至此一个简单的原始代理收集模块已经完成,执行ProxyManager主函数之后,就从代理网站获取到原始代理,并存储到redis数据库中了。查询redis中数据:
运行程序后通过api接口返回get_status,结果如下:
{"raw":100,"useful":0}
原始代理库中有100条代理记录,有效代理库中无代理记录。
接下来就需要进一步对原始代理进行验证,移除掉无效代理,将有效代理保存到useful表中。
参考资料
[1]https://blog.csdn.net/sinat_34200786/article/details/79451499