简介

我们可以从网上或者付费获取大量代理,但是这其中很多依然不可用,那么搭建高效的代理池,对代理ip进行筛选是十分必要的

准备工作

安装Redis数据库,还需要安装aiohttp、requests、redis-py、pyquery、Flask库,安装流程请百度自行查询

由于文件内容较多,所以就不一一讲解了,直接创建一个Python Package模块包,下次直接调用

创建一个Python Package包,取名为proxypool

一.创建一个setting.py文件,用于存放配置信息。代码如下:

# Redis数据库地址
REDIS_HOST = '127.0.0.1'# Redis端口
REDIS_PORT = 6379# Redis密码,如无填None
REDIS_PASSWORD = NoneREDIS_KEY = 'proxies'# 代理分数
MAX_SCORE = 100
MIN_SCORE = 0
INITIAL_SCORE = 10VALID_STATUS_CODES = [200, 302]# 代理池数量界限
POOL_UPPER_THRESHOLD = 50000# 检查周期
TESTER_CYCLE = 20
# 获取周期
GETTER_CYCLE = 300# 测试API,建议抓哪个网站测哪个
TEST_URL = 'http://www.baidu.com'# API配置
API_HOST = '0.0.0.0'
API_PORT = 5555

二.创建error.py文件,处理代理池枯竭情况

class PoolEmptyError(Exception):def __init__(self):Exception.__init__(self)def __str__(self):return repr('代理池已经枯竭')

三.创建存储模块,用于进行代理ip的存储,删除,更新等等操作

import redis
from proxypool.error import PoolEmptyError
from proxypool.setting import REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, REDIS_KEY
from proxypool.setting import MAX_SCORE, MIN_SCORE, INITIAL_SCORE
from random import choice
import reclass RedisClient(object):def __init__(self, host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD):"""初始化:param host: Redis 地址:param port: Redis 端口:param password: Redis密码"""self.db = redis.StrictRedis(host=host, port=port, password=password, decode_responses=True)def add(self, proxy, score=INITIAL_SCORE):"""添加代理,设置分数为最高:param proxy: 代理:param score: 分数:return: 添加结果"""if not re.match('\d+\.\d+\.\d+\.\d+\:\d+', proxy):print('代理不符合规范', proxy, '丢弃')returnif not self.db.zscore(REDIS_KEY, proxy):return self.db.zadd(REDIS_KEY, score, proxy)def random(self):"""随机获取有效代理,首先尝试获取最高分数代理,如果不存在,按照排名获取,否则异常:return: 随机代理"""result = self.db.zrangebyscore(REDIS_KEY, MAX_SCORE, MAX_SCORE)if len(result):return choice(result)else:result = self.db.zrevrange(REDIS_KEY, 0, 100)if len(result):return choice(result)else:raise PoolEmptyErrordef decrease(self, proxy):"""代理值减一分,小于最小值则删除:param proxy: 代理:return: 修改后的代理分数"""score = self.db.zscore(REDIS_KEY, proxy)if score and score > MIN_SCORE:print('代理', proxy, '当前分数', score, '减1')return self.db.zincrby(REDIS_KEY, proxy, -1)else:print('代理', proxy, '当前分数', score, '移除')return self.db.zrem(REDIS_KEY, proxy)def exists(self, proxy):"""判断是否存在:param proxy: 代理:return: 是否存在"""return not self.db.zscore(REDIS_KEY, proxy) == Nonedef max(self, proxy):"""将代理设置为MAX_SCORE:param proxy: 代理:return: 设置结果"""print('代理', proxy, '可用,设置为', MAX_SCORE)return self.db.zadd(REDIS_KEY, MAX_SCORE, proxy)def count(self):"""获取数量:return: 数量"""return self.db.zcard(REDIS_KEY)def all(self):"""获取全部代理:return: 全部代理列表"""return self.db.zrangebyscore(REDIS_KEY, MIN_SCORE, MAX_SCORE)def batch(self, start, stop):"""批量获取:param start: 开始索引:param stop: 结束索引:return: 代理列表"""return self.db.zrevrange(REDIS_KEY, start, stop - 1)if __name__ == '__main__':conn = RedisClient()result = conn.batch(680, 688)print(result)

四.创建一个importer.py文件,用于录入ip代理:

from proxypool.db import RedisClientconn = RedisClient()def set(proxy):result = conn.add(proxy)print(proxy)print('录入成功' if result else '录入失败')def scan():print('请输入代理, 输入exit退出读入')while True:proxy = input()if proxy == 'exit':breakset(proxy)if __name__ == '__main__':scan()

五.创建utils.py文件,用于抓取网页,代码如下:

import requests
from requests.exceptions import ConnectionErrorbase_headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36','Accept-Encoding': 'gzip, deflate, sdch','Accept-Language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7'
}def get_page(url, options={}):"""抓取代理:param url::param options::return:"""headers = dict(base_headers, **options)print('正在抓取', url)try:response = requests.get(url, headers=headers)print('抓取成功', url, response.status_code)if response.status_code == 200:return response.textexcept ConnectionError:print('抓取失败', url)return None

六.获取模块,创建crawler.py文件,用于从各大网站抓取代理

import json
import re
from .utils import get_page
from pyquery import PyQuery as pqclass ProxyMetaclass(type):def __new__(cls, name, bases, attrs):count = 0attrs['__CrawlFunc__'] = []for k, v in attrs.items():if 'crawl_' in k:attrs['__CrawlFunc__'].append(k)count += 1attrs['__CrawlFuncCount__'] = countreturn type.__new__(cls, name, bases, attrs)class Crawler(object, metaclass=ProxyMetaclass):def get_proxies(self, callback):proxies = []for proxy in eval("self.{}()".format(callback)):print('成功获取到代理', proxy)proxies.append(proxy)return proxiesdef crawl_daili66(self, page_count=4):"""获取代理66:param page_count: 页码:return: 代理"""start_url = 'http://www.66ip.cn/{}.html'urls = [start_url.format(page) for page in range(1, page_count + 1)]for url in urls:print('Crawling', url)html = get_page(url)if html:doc = pq(html)trs = doc('.containerbox table tr:gt(0)').items()for tr in trs:ip = tr.find('td:nth-child(1)').text()port = tr.find('td:nth-child(2)').text()yield ':'.join([ip, port])def crawl_ip3366(self):for page in range(1, 4):start_url = 'http://www.ip3366.net/free/?stype=1&page={}'.format(page)html = get_page(start_url)ip_address = re.compile('<tr>\s*<td>(.*?)</td>\s*<td>(.*?)</td>')# \s * 匹配空格,起到换行作用re_ip_address = ip_address.findall(html)for address, port in re_ip_address:result = address + ':' + portyield result.replace(' ', '')def crawl_kuaidaili(self):for i in range(1, 4):start_url = 'http://www.kuaidaili.com/free/inha/{}/'.format(i)html = get_page(start_url)if html:ip_address = re.compile('<td data-title="IP">(.*?)</td>')re_ip_address = ip_address.findall(html)port = re.compile('<td data-title="PORT">(.*?)</td>')re_port = port.findall(html)for address, port in zip(re_ip_address, re_port):address_port = address + ':' + portyield address_port.replace(' ', '')def crawl_xicidaili(self):for i in range(1, 3):start_url = 'http://www.xicidaili.com/nn/{}'.format(i)headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8','Cookie': '_free_proxy_session=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiJWRjYzc5MmM1MTBiMDMzYTUzNTZjNzA4NjBhNWRjZjliBjsAVEkiEF9jc3JmX3Rva2VuBjsARkkiMUp6S2tXT3g5a0FCT01ndzlmWWZqRVJNek1WanRuUDBCbTJUN21GMTBKd3M9BjsARg%3D%3D--2a69429cb2115c6a0cc9a86e0ebe2800c0d471b3','Host': 'www.xicidaili.com','Referer': 'http://www.xicidaili.com/nn/3','Upgrade-Insecure-Requests': '1',}html = get_page(start_url, options=headers)if html:find_trs = re.compile('<tr class.*?>(.*?)</tr>', re.S)trs = find_trs.findall(html)for tr in trs:find_ip = re.compile('<td>(\d+\.\d+\.\d+\.\d+)</td>')re_ip_address = find_ip.findall(tr)find_port = re.compile('<td>(\d+)</td>')re_port = find_port.findall(tr)for address, port in zip(re_ip_address, re_port):address_port = address + ':' + portyield address_port.replace(' ', '')def crawl_ip3366(self):for i in range(1, 4):start_url = 'http://www.ip3366.net/?stype=1&page={}'.format(i)html = get_page(start_url)if html:find_tr = re.compile('<tr>(.*?)</tr>', re.S)trs = find_tr.findall(html)for s in range(1, len(trs)):find_ip = re.compile('<td>(\d+\.\d+\.\d+\.\d+)</td>')re_ip_address = find_ip.findall(trs[s])find_port = re.compile('<td>(\d+)</td>')re_port = find_port.findall(trs[s])for address, port in zip(re_ip_address, re_port):address_port = address + ':' + portyield address_port.replace(' ', '')def crawl_iphai(self):start_url = 'http://www.iphai.com/'html = get_page(start_url)if html:find_tr = re.compile('<tr>(.*?)</tr>', re.S)trs = find_tr.findall(html)for s in range(1, len(trs)):find_ip = re.compile('<td>\s+(\d+\.\d+\.\d+\.\d+)\s+</td>', re.S)re_ip_address = find_ip.findall(trs[s])find_port = re.compile('<td>\s+(\d+)\s+</td>', re.S)re_port = find_port.findall(trs[s])for address, port in zip(re_ip_address, re_port):address_port = address + ':' + portyield address_port.replace(' ', '')def crawl_data5u(self):start_url = 'http://www.data5u.com/free/gngn/index.shtml'headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8','Accept-Encoding': 'gzip, deflate','Accept-Language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7','Cache-Control': 'max-age=0','Connection': 'keep-alive','Cookie': 'JSESSIONID=47AA0C887112A2D83EE040405F837A86','Host': 'www.data5u.com','Referer': 'http://www.data5u.com/free/index.shtml','Upgrade-Insecure-Requests': '1','User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36',}html = get_page(start_url, options=headers)if html:ip_address = re.compile('<span><li>(\d+\.\d+\.\d+\.\d+)</li>.*?<li class=\"port.*?>(\d+)</li>', re.S)re_ip_address = ip_address.findall(html)for address, port in re_ip_address:result = address + ':' + portyield result.replace(' ', '')

七.创建getter.py文件,用于动态的调用所有以crawl开头的方法,获取抓取到的代理,存储到数据库中

from proxypool.tester import Tester
from proxypool.db import RedisClient
from proxypool.crawler import Crawler
from proxypool.setting import *
import sysclass Getter():def __init__(self):self.redis = RedisClient()self.crawler = Crawler()def is_over_threshold(self):"""判断是否达到了代理池限制"""if self.redis.count() >= POOL_UPPER_THRESHOLD:return Trueelse:return Falsedef run(self):print('获取器开始执行')if not self.is_over_threshold():for callback_label in range(self.crawler.__CrawlFuncCount__):callback = self.crawler.__CrawlFunc__[callback_label]# 获取代理proxies = self.crawler.get_proxies(callback)sys.stdout.flush()for proxy in proxies:self.redis.add(proxy)

八.检测模块:创建tester.py文件,测试ip代理

import asyncio
import aiohttp
import time
import systry:from aiohttp import ClientError
except:from aiohttp import ClientProxyConnectionError as ProxyConnectionError
from proxypool.db import RedisClient
from proxypool.setting import *class Tester(object):def __init__(self):self.redis = RedisClient()async def test_single_proxy(self, proxy):"""测试单个代理:param proxy::return:"""conn = aiohttp.TCPConnector(verify_ssl=False)async with aiohttp.ClientSession(connector=conn) as session:try:if isinstance(proxy, bytes):proxy = proxy.decode('utf-8')real_proxy = 'http://' + proxyprint('正在测试', proxy)async with session.get(TEST_URL, proxy=real_proxy, timeout=15, allow_redirects=False) as response:if response.status in VALID_STATUS_CODES:self.redis.max(proxy)print('代理可用', proxy)else:self.redis.decrease(proxy)print('请求响应码不合法 ', response.status, 'IP', proxy)except (ClientError, aiohttp.client_exceptions.ClientConnectorError, asyncio.TimeoutError, AttributeError):self.redis.decrease(proxy)print('代理请求失败', proxy)def run(self):"""测试主函数:return:"""print('测试器开始运行')try:count = self.redis.count()print('当前剩余', count, '个代理')for i in range(0, count, BATCH_TEST_SIZE):start = istop = min(i + BATCH_TEST_SIZE, count)print('正在测试第', start + 1, '-', stop, '个代理')test_proxies = self.redis.batch(start, stop)loop = asyncio.get_event_loop()tasks = [self.test_single_proxy(proxy) for proxy in test_proxies]loop.run_until_complete(asyncio.wait(tasks))sys.stdout.flush()time.sleep(5)except Exception as e:print('测试器发生错误', e.args)

九.接口模块:用于对接数据库,创建api.py文件

from flask import Flask, gfrom .db import RedisClient__all__ = ['app']app = Flask(__name__)def get_conn():if not hasattr(g, 'redis'):g.redis = RedisClient()return g.redis@app.route('/')
def index():return '<h2>Welcome to Proxy Pool System</h2>'@app.route('/random')
def get_proxy():"""Get a proxy:return: 随机代理"""conn = get_conn()return conn.random()@app.route('/count')
def get_counts():"""Get the count of proxies:return: 代理池总量"""conn = get_conn()return str(conn.count())if __name__ == '__main__':app.run()

十.调度模块:将以上三大模块通过多进程的形式运行起来,创建scheduler.py文件

import time
from multiprocessing import Process
from proxypool.api import app
from proxypool.getter import Getter
from proxypool.tester import Tester
from proxypool.db import RedisClient
from proxypool.setting import *class Scheduler():def schedule_tester(self, cycle=TESTER_CYCLE):"""定时测试代理"""tester = Tester()while True:print('测试器开始运行')tester.run()time.sleep(cycle)def schedule_getter(self, cycle=GETTER_CYCLE):"""定时获取代理"""getter = Getter()while True:print('开始抓取代理')getter.run()time.sleep(cycle)def schedule_api(self):"""开启API"""app.run(API_HOST, API_PORT)def run(self):print('代理池开始运行')if TESTER_ENABLED:tester_process = Process(target=self.schedule_tester)tester_process.start()if GETTER_ENABLED:getter_process = Process(target=self.schedule_getter)getter_process.start()if API_ENABLED:api_process = Process(target=self.schedule_api)api_process.start()

运行

调用scheduler的run()方法就能启动整个代理池

然后打开浏览器http://127.0.0.1:5555可以看到首页

访问http://127.0.0.1:5555/random,可以获得随机可用代理

获取代码如下,并且使用网站http://httpbin.org/get进行模拟操作

import requestsPROXY_POOL_URL = "http://127.0.0.1:5555/random"def get_proxy():try:response = requests.get(PROXY_POOL_URL)if response.status_code == 200:return response.textexcept requests.exceptions.ConnectionError:#print("没有获取到代理ip,请检查代理池内部")return None#---------------------------------------------------------
proxy = get_proxy()
proxies = {"http":"http://"+proxy,"https":"https://"+proxy,
}
try:response = requests.get("http://httpbin.org/get",proxies=proxies)print(response.text)
except requests.exceptions.ConnectionError as e:print("Error",e.args)



付费代理

不同的付费代理各不相同,但是基本规则相差不大,比较常见的有讯代理,阿布云代理,大象代理等等

下面以大象代理为例,获取到代理接口链接,可以直接使用其中的代理ip,也可以将其放入代理池进行检验,放到crawler.py中,下次只需要重新添加链接即可使用

转载于:https://www.cnblogs.com/nikecode/p/11172045.html

python爬虫-代理池的维护相关推荐

  1. python爬虫代理池_python爬虫之ProxyPool(代理ip地址池的构建)

    ProxyPool 安装 安装Python 至少Python3.5以上 安装Redis 安装好之后将Redis服务开启 配置代理池 cd proxypool 进入proxypool目录,修改setti ...

  2. Python爬虫代理池

    爬虫代理IP池 在公司做分布式深网爬虫,搭建了一套稳定的代理池服务,为上千个爬虫提供有效的代理,保证各个爬虫拿到的都是对应网站有效的代理IP,从而保证爬虫快速稳定的运行,当然在公司做的东西不能开源出来 ...

  3. Python爬虫-代理池-爬取代理入库并测试代理可用性

    目的:建立自己的代理池.可以添加新的代理网站爬虫,可以测试代理对某一网址的适用性,可以提供获取代理的 API. 整个流程:爬取代理 ----> 将代理存入数据库并设置分数 ----> 从数 ...

  4. 介绍一种 Python 更方便的爬虫代理池实现方案

    现在搞爬虫,代理是不可或缺的资源 很多人学习python,不知道从何学起. 很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手. 很多已经做案例的人,却不知道如何去学习更加高深的知识 ...

  5. python 爬虫 ip池维护思路

    对于HTTP代理池的维护,可以从以下几个方面入手: 1.验证HTTP代理的可用性 可以通过requests库向目标网站发送请求,判断HTTP代理是否能够成功返回响应.如果返回成功,则说明HTTP代理可 ...

  6. 最新实用Python异步爬虫代理池(开源)

    --  Illustrations by Tom Haugomat -- 陈键冬 Python中文社区专栏作者,pyecharts开源项目核心开发者. GitHub:chenjiandongx 项目地 ...

  7. 免费IP代理池定时维护,封装通用爬虫工具类每次随机更新IP代理池跟UserAgent池,并制作简易流量爬虫...

    前言 我们之前的爬虫都是模拟成浏览器后直接爬取,并没有动态设置IP代理以及UserAgent标识,这样很容易被服务器封IP,因此需要设置IP代理,但又不想花钱买,网上有免费IP代理,但大多都数都是不可 ...

  8. Python爬虫——代理和代理池

    文章目录 Python爬虫--代理和代理池 1.代理 2.代理池 Python爬虫--代理和代理池 1.代理 代理用处: 突破自身IP访问限制,访问国外资源 访问单位或公司内部资源 提高访问速度 隐藏 ...

  9. Python获取代理池和提取可用IP

    Python获取代理池和提取可用IP 前言 正文 请求代理池 筛选代理ip 保存可用的代理ip 把代理ip转发到本地(可选) 总结 前言 最近在学习Python爬虫的编写,发现很多网站设置了ip限制, ...

  10. linux 部署proxy_pool爬虫代理池

    linux 部署proxy_pool爬虫代理池 文章目录 linux 部署proxy_pool爬虫代理池 一.介绍 二.准备工作 1.更换清华镜像源 2.安装Redis 3.安装python 三.在L ...

最新文章

  1. Oracle数据库知识要点
  2. SQL Server中的角色(服务器级别和数据库级别角色)
  3. 一个毕业生对大学爱情和奋斗的思考!
  4. java shiro登录实例_Shiro安全框架入门篇(登录验证实例详解与源码)
  5. 在银行存款被吞了,怎么能快速解决?
  6. 【科普】OFFICE 365 outlook 如何导入其他邮箱的联系人
  7. C++ 对象关系映射(ORM)介绍
  8. Misra-Gries 算法
  9. 阿里巴巴如何面试?网友分享出你不知道的真实面试流程(转发给有需要的人)
  10. Wireshark的下载安装及简单使用教程
  11. 应用StarRocks实现存储引擎的收敛,保障高查询并发及低延迟要求
  12. 基于lxr的源代码浏览系统
  13. Java项目源码SSM宿舍管理系统|寝室
  14. Bootstrap4使用教程
  15. matlab将矩阵数据归一化到[0,255]
  16. 【文献翻译】构建网络安全知识库的框架-A Framework to Construct Knowledge Base for Cyber Security
  17. 软考-软件设计师 笔记一(计算机组成与体系结构)
  18. 网管好助手--PSTOOLS
  19. 腾讯云域名与个人树莓派设备的动态域名解析
  20. Baxter环境安装

热门文章

  1. AXURE版富文本输入框(富文本编辑器)教程+下载
  2. iPhonexs文件连接服务器,iPhonexs黑屏了教你如何快速解决!
  3. FPGA设计中提高工作频率及降低功耗题目合集
  4. 如何用excel数据分析计算相关系数
  5. Asp.NET Core+ABP框架+IdentityServer4+MySQL+Ext JS之文件上传
  6. Word字体间距变大
  7. 微信抖音工具箱头像制作壁纸小程序带改图制图流量主功能搭建动态社群人脉助手
  8. 泰勒公式推导及多元泰勒展开式
  9. “00后”消费数据分析,一文教你撩动“00后”购物欲
  10. OSPF路由聚合(学习笔记+实验验证)