python爬虫--代理的使用
代理的使用
- 代理池的维护
- 代理池
- 付费代理
- ADSL拨号代理
代理池的维护
基本模块:
- 存储模块: 使用Redis的有序集合负责存储抓取下来的代理,保证代理不重复
- 获取模块:需要定时在各大代理网站抓取代理,代理的形式都是IP加端口,尽量从不同来源获取,尽量抓取高匿代理。
- 检测模块:需要定时检测数据库中的代理,设置一个检测链接,最好是爬取哪个网站就检测哪个网站
- 接口模块:需要用API来提供对外服务的接口,由于可用代理可能有多个,那么我们可以设置一个随机返回某个可用代理的接口,这样就能保证每个可用代理都可以取到实现负载均衡
代理池
存储模块:使用redis的有序集合,有序集合的每个元素都有一个分数字段,分数是可以重复的。根据分数对集合进行排序,可以作为判断一个代理是否可用的标志。
操作数据库的有序集合
MAX_SCORE=100
MIN_SCORE=0
INITIAL_SCORE=10
REDIS_HOST='localhost'
REDIS_PORT=6379
REDIS_PADDWORD=None
REDIS_KEY='proxies'
import redis
from random import choiceclass RedisClient(object):def __init__(self,host=REDIS_HOST,port=REDIS_PORT,password=REDIS_PADDWORD):"""初始化: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 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 PoolEmptyError#检测代理无效时分数减1def 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)==None#设置代理分数def 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)
获取模块
import json
from .utils import get_page
from pyquery import PyQuery as pqclass ProxyMetaclass(type):def __new__(cls, name,bases,attrs):count=0attrs['__CrawlFunc__']=[]# 判断方法开头是否是Crawl,如果是则将其加入到__CrawlFunc__属性中,就成功将所有以crawl开头的方法定义成了一个属性,动态获取到所有以crawl开头的方法列表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_proxy360(self):"""获取Proxy360:return: 代理"""start_url='http://www.proxy360.cn/Regio.China'print('Crawling',start_url)html=get_page(start_url)if html:doc=pq(html)lines=doc('div[name="list_proxy_ip"]').items()for line in lines:ip=line.find('.tbBottomLine:nth-child(1)').text()port=line.find('.tbBottomLine:nth-child(2)').text()yield ':'.join([ip,port])def crawl_goubanjia(self):"""获取Goubanjia:return: 代理"""start_url='http://www.goubanjia.com/free/gngn/index.shtml'html=get_page(start_url)if html:doc=pq(html)tds=doc('td.ip').items()for td in tds:td.find('p').remove()yield td.text().replace(' ','')
#定义一个Getter类,用来动态调用所有以crawl开头的方法
from db import RedisClient
from crawler import Crawler
POOL_UPPER_THRESHOLD=10000class Getter():def __init__(self):self.redis=RedisClient()self.crawler=Crawler()def is_over_threshold(self):"""判断你是否达到了代理池的限制:return:"""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.__CrawFuncCount__):callback=self.crawler.CrawlFunc__[callback_label]proxies=self.crawler.get_proxies(callback)for proxy in proxies:self.redis.add(proxy)
检测模块
VALID_STATUS_CODES=[200]
TEST_URL='http://www.baidu.com'
BATCH_TEST_SIZE=100
class Tester(object):def __init__(self):self.redis=RedisClient()async def test_single_proxy(self,proxy):"""测试单个代理:param proxy: 单个代理:return: None"""conn=aiohttp.TCPConnector(verify_sal=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) as response:if response.status in VALID_STATUS_CODES:self.redis.max(proxy)print('代理可用',proxy)else:self.redis.decrease(proxy)print('请求响应码不合法',proxy)except(ClientError,clientConnectorError,TimeoutError,AttributeError):self.redis.decrease(proxy)print('代理请求失败',proxy)#获取所有的代理列表def run(self):"""测试主函数:return: None"""print('测试器开始运行')try:proxies=self.redis.all()loop=asyncio.get_event_loop()#批量测试for i in range(0,len(proxies),BATCH_TEST_SIZE):test_proxies=proxies[i:i+BATCH_TEST_SIZE]tasks=[self.test_single_proxy(proxy) for proxy in test_proxies]loop.run_until_complete(asyncio.wait(tasks))time.sleep(5)except Exception as e:print('测试器发送错误',e.args)
接口模块
from flask import Flask,g
from 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():"""获取随机可用代理:return: 随机代理"""conn=get_conn()return conn.random()
@app.route('/count')
def get_counts():"""获取代理池总量:return: 代理池总量"""conn=get_conn()return str(conn.count())
调度模块
TEST_CYCLE=20
GETTER_CYCLE=20
TESTER_ENABLD=True
GETTER_ENABLD=True
API_ENABLD=True
from multiprocessing import Process
from api import app
from getter import Getter
from tester import Testerclass Scheduler():def schedule_tester(self,cycle=TEST_CYCLE):"""定时测试代理:param cycle::return:"""tester=Tester()while True:print('测试器开始运行')tester.run()time.sleep(cycle)def schedule_api(self):"""开启API:return:"""app.run(API_HOST,API_PORT)def run(self):print('代理池开始运行')if TESTER_ENABLD:tester_process=Process(target=self.schedule_tester)tester_process.start()if GETTER_ENABLD:getter_process=Process(target=self.schedule_getter)getter_process=start()if API_ENABLD:api_process=Process(target=self.schedule_api())api_process.start()
if __name__ == '__main__':app.run()
付费代理
- 讯代理:提供接口获取海量代理,按天或者按量收费。
- 阿布云代理:搭建了代理隧道,直接设置固定域名代理。
ADSL拨号代理
ADSL通过拨号的方式上网,需要输入ADSL账号和密码,每次拨号就更换一个IP。
python爬虫--代理的使用相关推荐
- Python爬虫——代理和代理池
文章目录 Python爬虫--代理和代理池 1.代理 2.代理池 Python爬虫--代理和代理池 1.代理 代理用处: 突破自身IP访问限制,访问国外资源 访问单位或公司内部资源 提高访问速度 隐藏 ...
- python爬虫代理的使用_从零开始写Python爬虫 --- 2.4 爬虫实践:代理的爬取和验证...
爬网站的时候,由于各种原因,ip被锁了,这个时候我们就需要通过代理来突破封锁.网上有很多代理网站,付费和免费的都有,这次我们就来写一个scrapy爬虫,爬一些免费的代理下来用. 目标分析: 本次爬取了 ...
- python爬虫代理ip_Python爬虫如何获取代理ip及ip验证?
如何获取大量的公开数据信息,这是我们互联网在竞争激烈的环境中的生存之道,不管在什么环境下都要学习和了解用户市场,客户需求,竞争对手,如何能获取到大量的数据信息,那么就需要用到网络爬虫. 在我们从事py ...
- Python爬虫代理ip异常和超时解决方案
Python爬虫中的代理ip异常和超时如何解决?程序员在敲代码的过程中,一定会出现一定的错误,特别是像Python爬虫这种程序,并不能肯定每次请求都能保障稳定的返回同样的结果,例如反爬虫机制的强化,代 ...
- Python爬虫代理池
爬虫代理IP池 在公司做分布式深网爬虫,搭建了一套稳定的代理池服务,为上千个爬虫提供有效的代理,保证各个爬虫拿到的都是对应网站有效的代理IP,从而保证爬虫快速稳定的运行,当然在公司做的东西不能开源出来 ...
- python 代理ip池_GitHub - xuan525/proxy_pool: Python爬虫代理IP池(proxy pool)
ProxyPool 爬虫代理IP池 ______ ______ _ | ___ \_ | ___ \ | | | |_/ / \__ __ __ _ __ _ | |_/ /___ ___ | | | ...
- python 爬虫工具 butter_GitHub - TheButterflyOdor/proxy_pool: Python爬虫代理IP池(proxy pool)
爬虫IP代理池 ______ ______ _ | ___ \_ | ___ \ | | | |_/ / \__ __ __ _ __ _ | |_/ /___ ___ | | | __/| _// ...
- python 爬虫代理_python 爬虫 使用代理 的问题
刚刚在使用Python写爬虫,但是由于我在公司没有上网权限,所以借别人的账号用(opera 浏览器代理 可有上网),我将代理信息写在python脚本里面但是出现了下面的错误. 代码: import u ...
- python爬虫代理池_python爬虫之ProxyPool(代理ip地址池的构建)
ProxyPool 安装 安装Python 至少Python3.5以上 安装Redis 安装好之后将Redis服务开启 配置代理池 cd proxypool 进入proxypool目录,修改setti ...
- Python爬虫-代理ip池建立
代理IP池建立 前言 之前提到过urllib和requests的利用代理ip的访问方式 . https://blog.csdn.net/zhouchen1998/article/details/813 ...
最新文章
- STL中istream_iterator和ostream_iterator的基本用法
- 程序员计算器_GitHub 日收 7000 星,Windows 计算器项目开源即爆红!
- 永远不要在Linux执行的10个最危险的命令
- IOS开发笔记17-Object-C中的继承
- U-Boot移植教程之二:移植
- 【HDOJ】3948 The Number of Palindromes
- Lucene.net站内搜索—5、搜索引擎第一版实现
- Aho-Corasick automaton 模板
- nunjucks渲染富文本解析错误输出字符串而不是元素
- 【CodeForces - 471B】MUH and Important Things (模拟,细节)
- glibc交叉编译_TSN之linuxptp交叉编译
- JAVA入门级教学之(方法递归习题)
- js前端——滑稽官网的亮瞎眼系列滑稽大法
- 计算机视觉模型、学习和推理
- Mr.J-- jQuery学习笔记(三十一)--事件操作方法(onoff)
- linux命令详解——tee
- Keil MDK从未有过的详细使用讲解
- MyBatis3系列__03几个属性总结
- 【渝粤题库】陕西师范大学292111 社会学概论 作业
- qt5.15.1及以上版本进行编译(windows64位)