笔记10
1,代理池
2,scrapy 文件下载,图片下载
3,ajax--qq
进程--线程--协程:
例子:1、1洗衣房--有10台洗衣机--有一个洗衣工
进程 协程 一个线程
进程>线程>协程
async关键字----开启异步方法
def b():
1
2---等待--整个线程都是等待
3
b()---这个方法不是异步方法,所以执行的过程中不会等待。
async a():---这个方法就是一个异步方法。
1
2 ---等待--请求的时候,等待响应---异步方法就会在这里挂起,去执行别的方法
3
await --等待(让挂起)--等待的终止条件
代理池应用
db----->第一步
redis----list实现
list如何来设计? 如何保证从list中获取的代理是最新的?
1,从尾部插入最新的可用的代理。
2,代理池数量很多的时候,代理池中之前验证的代理还需要继续验证(有可能失效),每次从头部取出一片(一半),在重新验证,可用的在放在尾部。
3,将来从代理池选取代理使用的时候,只需要从尾部获取一个最新最可用的即可
第二步 getter--#去网上爬取免费代理-->Internet
添加器 + 校验器--》db
第三步 校验器---》
1,实现一个对外的入口,校验的方法都是私有的,不能对外开放。这个入口就相当于一个篮子,只需要向里面放代理,校验器就可以自动从里面获取来校验。
2,真正的添加逻辑,就是在校验成功的时候才添加的。--校验的同时,也是添加。
3,代理的有效验证是消耗时间的,不能用同步请求来做,效率非常差--异步请求
第四步
添加器--》
1,判断代理池是否达到上限和下限。当上限达到,停止添加,当下限达到,开始添加
2,添加器主要调用校验来校验的同时添加
代码
import redis
from proxypool.settings import PASSWORD,HOST,PORT
class Redis_Client(object):
#设置密码选择功能
def __init__(self,host=HOST):
#判断是否有密码:
if PASSWORD:
self._db=redis.Redis(host=host,port=port,password=PASSWORD)
else:
self._db=redis.Redis(host=host,port=port)
#将代理添加到代理池的尾部
def put(self,proxy):
self._db.rpush(PROXIES,proxy)
#将头部获取count这个代理,并将其删除
def get(self,count=1):
#lrange:获取指定范围的内容
#ltrim:保留指定范围内的内容,其他删除
proxies=self._db.lrange(PROXIES,0,count-1)
self._db.ltrim(PROXIES,count,-1)
return proxies
#从尾部获取一个最新代理
def pop(self):
#从redis中获取来的数据是bytes类型
return self._db.rpop(PROXIES).decode('utf-8')
#计算代理池长度
@property
def queue_len(self):
return self._db.lien(PROXIES)
def flush(self):
self._db.flushall()#清空所有
if __name__='__main__':
r=Redis_Client()
print(r.queue_len)
cmd中复习
redis-cli
lrange proxies 0 5
ltrim proxies 6 -1
lrange proxies 0 -1
配置文件(密码)
创建setting
#密码:如果为空,就没有密码
PASSWORD = ''
#主机ip和端口号
HOST = 'localhost'
PORT = 6379
#代理池的名称
PROXIES = 'proxies'
#测试代理的网址
TSET_API = 'https://www.baidu.com/'
#配置测试网址的请求头
TEST_REQUEST_HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36',
}
#测试代理的超时时间
TSET_TIME_OUT = 30
第二步
getter中
class ProxyGetter(object):
#爬取代理方法,名称统一为crawl
def crawl_66ip(self):
第三步
Scheduler中
import aiohttp
from Requests01.proxypool.settings import TSET_API,TEST_REQUEST_HEADERS,TSET_TIME_OUT
import asyncio
from Requests01.proxypool.db import Reids_Client
class VaildityTester(object):
def __init__(self):
#篮子
self._raw_proxies = []
#向篮子放东西
def set_raw_proxies(self,proxies):
self._raw_proxies = proxies
# 数据的所有连接,用的时候在创建。
self._conn = Reids_Client()
#校验代理,要使用异步 请求
async def test_single_proxy(self,proxy):
try:
# 创建一个session对象
async with aiohttp.ClientSession() as session:
# 参数校验,如果proxy参数是一个bytes类型,就给他转成字符串
if isinstance(proxy, bytes):
proxy = proxy.decode('utf-8')
real_proxy = 'http://' + proxy
try:
async with session.get(TSET_API,
headers=TEST_REQUEST_HEADERS,
proxy=real_proxy,
timeout=TSET_TIME_OUT) as response:
if response.status == 200:
# 该代理可用
# 添加到代理池
self._conn.put(proxy)
print('有效代理!', proxy)
except Exception:
print('无效代理!',proxy)
except Exception as e:
print(e)
def test(self):
print('代理池开始启动!')
#创建一个loop(任务执行链)
loop=asyncio.get_event_loop()
#执行任务
tasks=[self.test_single_proxy(proxy)for proxy in self._raw_proxies]
#启动loop ---循环链
loop.run_until_complete(asyncio.wait(tasks))
第四步
#添加器
class PoolAdder(object):
#threshold--阀值--代理池最大值
def __init__(self,threshold):
self.threshold=threshold
#校验
self._tester=VaildityTester()
#db
self._conn=Redis_Client()
self._crawler=FreeProxyGetter()
#判断代理池数量是否达到最大值
def is_over_threshold(self):
"""
:return: True:达到 False不能
"""
if self._conn.queue_len>=self._theshold:
return True
#添加代理到代理池的方法
def add_to_queue(self):
#代理的获取是从getter组件中获取的
print('添加器开始工作……')
while True:
#当添加到代理池达到最大值就不添加了
if self.is_over_threshold():
break
#1、先从网上获取免费代理
#问题:现在只能调用单一的爬取代理的方法,无法从各个网站都获取代理
#如何实现?
proxies=self._crawler.crawl_ip3366()
#proxies=self._crawler.crawl_66ip()
#2、用校验器校验(校验的同时在添加)
#2.1先把代理放到篮子
self._tester.set_raw_proxies(proxies)
#2.2test方法就自动从篮子中获取代理校验
self._tester.test()
demo_with中
import requests
response=requests.get('https://www.baidu.com/')
with requests.get('https://www.baidu.com/')as response:
print(response.text)
print(response.status_code)
一、元类
1,什么是类?
类是一个对象,可以创建对象的对象就是类。
object=class()
2,什么是元类?
可以创建类的对象就是元类。
class=metaclass()
object=class()
3,python提供了用class方法来创建类。
也提供了一个元类,我们可以通过这个元类来自定义类。–这个类就叫做type
type(
类的名字
(,),类的继承
{,}类的属性
)–>class
4,一个对象在创建的时候,如果想要让这个对象包含一些内容。
new
init