使用爬蟲的時候肯定會有頻繁訪問某一網站的情況,這個時候有些服務器會識別到這是非正常訪問,就會把請求的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