海西州电子商务网站建设,北京优化词网站,百度平台交易,谁会在阿里云建网站一、协程
概念 协程 又称微线程(纤程)#xff0c;是一种用户态的轻量级线程 子程序 在所有的语言中都是层级调用的#xff0c;比如A中调用B#xff0c;B在执行过程中调用C#xff0c;C执行完返回#xff0c;B执行完返回#xff0c;最后是A执行完毕。这是通过栈实现的是一种用户态的轻量级线程 子程序 在所有的语言中都是层级调用的比如A中调用BB在执行过程中调用CC执行完返回B执行完返回最后是A执行完毕。这是通过栈实现的一个函数就是一个执行的子程序子程序的调用总是有一个入口、一次返回调用的顺序是明确的 理解协程 普通理解线程是系统级别的它们是由操作系统调度。协程是程序级别由程序员根据需求自己调度。我们把一个线程中的一个个函数称为子程序那么一个子程序在执行的过程中可以中断去执行别的子程序这就是协程。也就是说同一个线程下的一段代码1执行执行着就中断然后去执行另一段代码2当再次回来执行代码1时接着从之前的中断的位置继续向下执行 优点 a、最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换而是由程序自身控制因此没有线程切换的开销和多线程比线程数量越多协程的性能优势就越明显。 b、不需要多线程的锁机制因为只有一个线程也不存在同时写变量冲突在协程中控制共享资源不加锁只需要判断状态就好了所以执行效率比多线程高很多。 缺点 a、无法利用多核CPU协程的本质是单个线程它不能同时将多个CPU的多个核心使用上失去了标准线程使用多CPU的能力。 b、进行阻塞操作(操作IO)会阻塞整个程序 二、同步与异步
1、同步与异步的概念 前言 python由于GIL全局锁的存在不能发挥多核的优势其性能一直饱受诟病。然而在IO密集型的网络编程里异步处理比同步处理能提升成百上千倍的效率 IO密集型就是磁盘的读取数据和输出数据非常大的时候就是属于IO密集型 由于IO操作的运行时间远远大于cpu、内存运行时间所以任务的大部分时间都是在等待IO操作完成IO的特点是cpu消耗小所以IO任务越多cpu效率越高当然不是越多越好有一个极限值。 同步 指完成事务的逻辑先执行第一个事务如果阻塞了会一直等待直到这个事务完成再执行第二个事务顺序执行 异步 是和同步相对的异步是指在处理调用这个事务的之后不会等待这个事务的处理结果直接处理第二个事务去了通过状态、通知、回调来通知调用者处理结果
2、同步与异步代码 同步 import time
def run(index):print(lucky is a good man, index)time.sleep(2)print(lucky is a nice man, index)
for i in range(1, 5):run(i) 异步 说明后面的课程中会使用到asyncio模块现在的目的是使同学们理解异步思想 import time
import asyncio
async def run(i): print(lucky is a good man, i) # 模拟一个耗时IO await asyncio.sleep(2) print(lucky is a nice man, i)
if name main: loop asyncio.get_event_loop() tasks [] t1 time.time() for url in range(1, 5):coroutine run(url)task asyncio.ensure_future(coroutine)tasks.append(task)loop.run_until_complete(asyncio.wait(tasks))t2 time.time()print(总耗时%.2f % (t2 - t1))
## 三、asyncio模块
### 1、概述
- asyncio模块
是python3.4版本引入的标准库直接内置了对异步IO的操作
- 编程模式
是一个消息循环我们从asyncio模块中直接获取一个EventLoop的引用然后把需要执行的协程扔到EventLoop中执行就实现了异步IO
- 说明
到目前为止实现协程的不仅仅只有asyncio,tornado和gevent都实现了类似功能
- 关键字的说明
| 关键字 | 说明 || ----------- | ---------------------------------------- || event_loop | 消息循环程序开启一个无限循环把一些函数注册到事件循环上当满足事件发生的时候调用相应的协程函数 || coroutine | 协程对象指一个使用async关键字定义的函数它的调用不会立即执行函数而是会返回一个协程对象。协程对象需要注册到事件循环由事件循环调用 || task | 任务一个协程对象就是一个原生可以挂起的函数任务则是对协程进一步封装其中包含了任务的各种状态 || async/await | python3.5用于定义协程的关键字async定义一个协程await用于挂起阻塞的异步调用接口 |
### 2、asyncio基本使用
- 定义一个协程pythonimport asyncioimport time
# 通过async关键字定义了一个协程协程是不能直接运行的需要将协程放到消息循环中async def run(x):print(waiting%d%x)await asyncio.sleep(x)print(结束run)
#得到一个协程对象coroutine run(2)asyncio.run(coroutine)
等同于 import asyncioimport time
# 通过async关键字定义了一个协程协程是不能直接运行的需要将协程放到消息循环中async def run(x):print(waiting%d%x)await asyncio.sleep(x)print(结束run)
#得到一个协程对象coroutine run(2)
# 创建一个消息循环loop asyncio.get_event_loop()
#将协程对象加入到消息循环loop.run_until_complete(coroutine) 创建一个任务 import asyncio
import time
async def run(x):print(waiting%d%x)await asyncio.sleep(x)print(结束run)
coroutine run(2)
#创建任务
task asyncio.ensure_future(coroutine)
loop asyncio.get_event_loop()
# 将任务加入到消息循环
loop.run_until_complete(task) 阻塞和await async可以定义协程使用await可以针对耗时操作进行挂起就与生成器的yield一样函数交出控制权。协程遇到await消息循环会挂起该协程执行别的协程直到其他协程也会挂起或者执行完毕在进行下一次执行 获取返回值 import time
import asyncio
async def run(url):print(开始向%s要数据……%(url))# 向百度要数据网络IOawait asyncio.sleep(5)data %s的数据%(url)print(给你数据)return data
# 定义一个回调函数
def call_back(future):print(call_back:, future.result())
coroutine run(百度)
# 创建一个任务对象
task asyncio.ensure_future(coroutine)
# 给任务添加回调在任务结束后调用回调函数
task.add_done_callback(call_back)
loop asyncio.get_event_loop()
loop.run_until_complete(task)
3、多任务 同步 同时请求百度, 阿里, 腾讯, 新浪四个网站假设响应时长均为2秒 import time
def run(url):print(开始向%s要数据……%(url))# 向百度要数据网络IOtime.sleep(2)data %s的数据%(url)return data
if __name__ __main__:t1 time.time()for url in [百度, 阿里, 腾讯, 新浪]:print(run(url))t2 time.time()print(总耗时%.2f%(t2-t1)) 异步 同时请求百度, 阿里, 腾讯, 新浪四个网站假设响应时长均为2秒 使用ensure_future创建多任务 import time
import asyncioasync def run(url):print(开始向%s要数据……%(url))await asyncio.sleep(2)data %s的数据%(url)return datadef call_back(future):print(call_back:, future.result())if __name__ __main__:loop asyncio.get_event_loop()tasks []t1 time.time()for url in [百度, 阿里, 腾讯, 新浪]:coroutine run(url)task asyncio.ensure_future(coroutine)task.add_done_callback(call_back)tasks.append(task)# 同时添加4个异步任务# asyncio.wait(tasks) 将任务的列表又变成 coroutine object wait at 0x7f80f43408c0loop.run_until_complete(asyncio.wait(tasks))t2 time.time()print(总耗时%.2f % (t2 - t1)) 封装成异步函数 import time
import asyncio
async def run(url):print(开始向%s要数据…… % (url))await asyncio.sleep(2)data %s的数据 % (url)return data
def call_back(future):print(call_back:, future.result())
async def main():tasks []t1 time.time()for url in [百度, 阿里, 腾讯, 新浪]:coroutine run(url)task asyncio.ensure_future(coroutine)task.add_done_callback(call_back)tasks.append(task)# 同时添加4个异步任务await asyncio.wait(tasks)t2 time.time()print(总耗时%.2f % (t2 - t1))if __name__ __main__:loop asyncio.get_event_loop()loop.run_until_complete(main())
使用loop.create_task创建多任务 import timeimport asyncioasync def run(url):print(开始向%s要数据…… % (url))await asyncio.sleep(2)data %s的数据 % (url)return datadef call_back(future):print(call_back:, future.result())if __name__ __main__:loop asyncio.get_event_loop()tasks []t1 time.time()for url in [百度, 阿里, 腾讯, 新浪]:coroutine run(url)# task asyncio.ensure_future(coroutine)task loop.create_task(coroutine)task.add_done_callback(call_back)tasks.append(task)# 同时添加4个异步任务loop.run_until_complete(asyncio.wait(tasks))t2 time.time()print(总耗时%.2f % (t2 - t1)) 封装成异步函数 import time
import asyncio
async def run(url):print(开始向%s要数据…… % (url))await asyncio.sleep(2)data %s的数据 % (url)return data
def call_back(future):print(call_back:, future.result())
async def main():tasks []t1 time.time()for url in [百度, 阿里, 腾讯, 新浪]:coroutine run(url)task loop.create_task(coroutine)task.add_done_callback(call_back)tasks.append(task)# 同时添加4个异步任务await asyncio.wait(tasks)t2 time.time()print(总耗时%.2f % (t2 - t1))if __name__ __main__:# asyncio.run(main())loop asyncio.get_event_loop()loop.run_until_complete(main())
使用asyncio.create_task创建多任务 import timeimport asyncioasync def run(url):print(开始向%s要数据…… % (url))await asyncio.sleep(2)data %s的数据 % (url)return datadef call_back(future):print(call_back:, future.result())async def main():tasks []t1 time.time()for url in [百度, 阿里, 腾讯, 新浪]:coroutine run(url)task asyncio.create_task(coroutine)task.add_done_callback(call_back)tasks.append(task)# 同时添加4个异步任务await asyncio.wait(tasks)t2 time.time()print(总耗时%.2f % (t2 - t1))if __name__ __main__:# asyncio.run(main())loop asyncio.get_event_loop()loop.run_until_complete(main())
4、Task 概念及用法 Task是 python 中与事件循环进行交互的一种主要方式。 创建 Task意思就是把协程封装成 Task 实例并追踪协程的 运行 / 完成状态用于未来获取协程的结果。 Task 核心作用: 在事件循环中添加多个并发任务; 具体来说是通过 asyncio.create_task() 创建 Task让协程对象加入事件循环中等待被调度执行。 注意:Python 3.7 以后的版本支持 asyncio.create_task() 在此之前的写法为 loop.create_task() 开发过程中需要注意代码写 法对不同版本 python 的兼容性。 需要指出的是协程封装为 Task 后不会立马启动当某个代码 await 这个 Task 的时候才会被执行。 当多个 Task 被加入一个 task_list 的时候添加 Task 的过程中 Task 不会执行必须要用 await asyncio.wait()或 await asyncio.gather() 将 Task 对象加入事件循环中异步执行。 一般在开发中常用的写法是这样的: -- 先创建 task_list 空列表; -- 然后用 asyncio.create_task() 创建 Task; -- 再把 Task 对象加入 task_list ; -- 最后使用 await asyncio.wait 或 await asyncio.gather 将 Task 对象加入事件循环中异步执行。 注意: 创建 Task 对象时除了可以使用 asyncio.create_task() 之外还可以用最低层级的 loop.create_task() 或 asyncio.ensure_future() 他们都可以用来创建 Task 对象其中关于 ensure_future 相关内容本文接下来会一起讲。 Task 简单用法
import asyncioasync def func():print(1)await asyncio.sleep(2)print(2)return testasync def main():print(main start)# python 3.7及以上版本的写法task1 asyncio.create_task(func())task2 asyncio.create_task(func())# python3.7以前的写法# task1 asyncio.ensure_future(func())# task2 asyncio.ensure_future(func())print(main end)ret1 await task1ret2 await task2print(ret1, ret2)
# python3.7以后的写法
asyncio.run(main())# python3.7以前的写法
# loop asyncio.get_event_loop()
# loop.run_until_complete(main())
在创建task的时候就将创建好的task添加到了时间循环当中所以说必须得有时间循环才可以创建task否则会报错task用法实例 import asyncio
import arrowdef current_time():获取当前时间:return:cur_time arrow.now().to(Asia/Shanghai).format(YYYY-MM-DD HH:mm:ss)return cur_time
async def func(sleep_time): func_name_suffix sleep_time # 使用 sleep_time (函数 I/O 等待时长)作为函数名后缀以区分任务对象 print(f[{current_time()}] 执行异步函数 {func.name}-{func_name_suffix}) await asyncio.sleep(sleep_time) print(f[{current_time()}]函数{func.name}-{func_name_suffix} 执行完毕) return f【[{current_time()}] 得到函数 {func.name}-{func_name_suffix} 执行结果】
async def run(): task_list [] for i in range(5): task asyncio.create_task(func(i)) task_list.append(task) done, pending await asyncio.wait(task_list) for done_task in done: print((f[{current_time()}]得到执行结果 {done_task.result()})) def main(): loop asyncio.get_event_loop() loop.run_until_complete(run())
if name main: main() 代码执行结果如下:python/usr/local/bin/python3.7 /Users/xialigang/PycharmProjects/爬虫/123.py[2022-07-01 16:44:57] 执行异步函数 func-0[2022-07-01 16:44:57] 执行异步函数 func-1[2022-07-01 16:44:57] 执行异步函数 func-2[2022-07-01 16:44:57] 执行异步函数 func-3[2022-07-01 16:44:57] 执行异步函数 func-4[2022-07-01 16:44:57]函数func-0 执行完毕[2022-07-01 16:44:58]函数func-1 执行完毕[2022-07-01 16:44:59]函数func-2 执行完毕[2022-07-01 16:45:00]函数func-3 执行完毕[2022-07-01 16:45:01]函数func-4 执行完毕[2022-07-01 16:45:01]得到执行结果 【[2022-07-01 16:44:59] 得到函数 func-2 执行结果】[2022-07-01 16:45:01]得到执行结果 【[2022-07-01 16:44:57] 得到函数 func-0 执行结果】[2022-07-01 16:45:01]得到执行结果 【[2022-07-01 16:45:00] 得到函数 func-3 执行结果】[2022-07-01 16:45:01]得到执行结果 【[2022-07-01 16:44:58] 得到函数 func-1 执行结果】[2022-07-01 16:45:01]得到执行结果 【[2022-07-01 16:45:01] 得到函数 func-4 执行结果】Process finished with exit code 0
5、协程嵌套与返回值
使用async可以定义协程协程用于耗时的io操作我们也可以封装更多的io操作过程这样就实现了嵌套的协程即一个协程中await了另外一个协程如此连接起来 import time
import asyncioasync def run(url):print(开始向%s要数据……%(url))await asyncio.sleep(2)data %s的数据%(url)return datadef call_back(future):print(call_back:, future.result())async def main():tasks []for url in [百度, 阿里, 腾讯, 新浪]:coroutine run(url)task asyncio.ensure_future(coroutine)# task.add_done_callback(call_back)tasks.append(task)# #1、可以没有回调函数# dones, pendings await asyncio.wait(tasks)# #处理数据类似回调建议使用回调# for t in dones:# print(数据%s%(t.result()))# #2、可以没有回调函数# results await asyncio.gather(*tasks)# # 处理数据类似回调建议使用回调# for result in results:# print(数据%s%(result))# 3、有无回调函数均可以# return await asyncio.wait(tasks)# 4、有无回调函数均可以# return await asyncio.gather(*tasks)if __name__ __main__:t1 time.time()loop asyncio.get_event_loop()#1、# loop.run_until_complete(main())# asyncio.run(main()) # 等同于上面两行代码#2、# loop.run_until_complete(main())# # 3、# dones, pendings loop.run_until_complete(main())# #处理数据类似回调建议使用回调# for t in dones:# print(数据%s%(t.result()))# 4、# results loop.run_until_complete(main())# for result in results:# print(数据%s%(result))t2 time.time()print(总耗时%.2f % (t2 - t1)) asyncio.wait和asyncio.gather的异同 异同点综述 相同:从功能上看 asyncio.wait 和 asyncio.gather 实现的效果是相同的都是把所有 Task 任务结果收集起来。 不同: asyncio.wait 会返回两个值: done 和 pending done 为已完成的协程 Task pending 为超时未完成的协程 Task 需通过 future.result 调用 Task 的 result ;而 asyncio.gather 返回的是所有已完成 Task 的 result 不需要再进行调用或其他操作就可以得到全部结果。 asyncio.wait 用法: 最常见的写法是: await asyncio.wait(task_list) 。 import asyncio
import arrowdef current_time():获取当前时间:return:cur_time arrow.now().to(Asia/Shanghai).format(YYYY-MM-DD HH:mm:ss)return cur_timeasync def func(sleep_time):func_name_suffix sleep_time # 使用 sleep_time (函数 I/O 等待时长)作为函数名后缀以区分任务对象print(f[{current_time()}] 执行异步函数 {func.__name__}-{func_name_suffix})await asyncio.sleep(sleep_time)print(f[{current_time()}]函数{func.__name__}-{func_name_suffix} 执行完毕)return f【[{current_time()}] 得到函数 {func.__name__}-{func_name_suffix} 执行结果】async def run():task_list []for i in range(5):task asyncio.create_task(func(i))task_list.append(task)done, pending await asyncio.wait(task_list)for done_task in done:print((f[{current_time()}]得到执行结果 {done_task.result()}))def main():loop asyncio.get_event_loop()loop.run_until_complete(run())if __name__ __main__:main() 代码执行结果如下: /usr/local/bin/python3.7 /Users/xialigang/PycharmProjects/爬虫/123.py
[2022-07-04 15:31:47] 执行异步函数 func-0
[2022-07-04 15:31:47] 执行异步函数 func-1
[2022-07-04 15:31:47] 执行异步函数 func-2
[2022-07-04 15:31:47] 执行异步函数 func-3
[2022-07-04 15:31:47] 执行异步函数 func-4
[2022-07-04 15:31:47]函数func-0 执行完毕
[2022-07-04 15:31:48]函数func-1 执行完毕
[2022-07-04 15:31:49]函数func-2 执行完毕
[2022-07-04 15:31:50]函数func-3 执行完毕
[2022-07-04 15:31:51]函数func-4 执行完毕
[2022-07-04 15:31:51]得到执行结果 【[2022-07-04 15:31:49] 得到函数 func-2 执行结果】
[2022-07-04 15:31:51]得到执行结果 【[2022-07-04 15:31:47] 得到函数 func-0 执行结果】
[2022-07-04 15:31:51]得到执行结果 【[2022-07-04 15:31:50] 得到函数 func-3 执行结果】
[2022-07-04 15:31:51]得到执行结果 【[2022-07-04 15:31:48] 得到函数 func-1 执行结果】
[2022-07-04 15:31:51]得到执行结果 【[2022-07-04 15:31:51] 得到函数 func-4 执行结果】Process finished with exit code 0 asyncio.gather 用法: 最常见的用法是: await asyncio.gather(*task_list) 注意这里 task_list 前面有一个 *。 import asyncio
import arrowdef current_time():获取当前时间:return:cur_time arrow.now().to(Asia/Shanghai).format(YYYY-MM-DD HH:mm:ss)return cur_timeasync def func(sleep_time):func_name_suffix sleep_time # 使用 sleep_time (函数 I/O 等待时长)作为函数名后缀以区分任务对象print(f[{current_time()}] 执行异步函数 {func.__name__}-{func_name_suffix})await asyncio.sleep(sleep_time)print(f[{current_time()}]函数{func.__name__}-{func_name_suffix} 执行完毕)return f【[{current_time()}] 得到函数 {func.__name__}-{func_name_suffix} 执行结果】async def run():task_list []for i in range(5):task asyncio.create_task(func(i))task_list.append(task)results await asyncio.gather(*task_list)for result in results:print((f[{current_time()}]得到执行结果 {result}))def main():loop asyncio.get_event_loop()loop.run_until_complete(run())if __name__ __main__:main() 代码执行结果如下: /usr/local/bin/python3.7 /Users/xialigang/PycharmProjects/爬虫/123.py
[2022-07-04 15:33:24] 执行异步函数 func-0
[2022-07-04 15:33:24] 执行异步函数 func-1
[2022-07-04 15:33:24] 执行异步函数 func-2
[2022-07-04 15:33:24] 执行异步函数 func-3
[2022-07-04 15:33:24] 执行异步函数 func-4
[2022-07-04 15:33:24]函数func-0 执行完毕
[2022-07-04 15:33:25]函数func-1 执行完毕
[2022-07-04 15:33:26]函数func-2 执行完毕
[2022-07-04 15:33:27]函数func-3 执行完毕
[2022-07-04 15:33:28]函数func-4 执行完毕
[2022-07-04 15:33:28]得到执行结果 【[2022-07-04 15:33:24] 得到函数 func-0 执行结果】
[2022-07-04 15:33:28]得到执行结果 【[2022-07-04 15:33:25] 得到函数 func-1 执行结果】
[2022-07-04 15:33:28]得到执行结果 【[2022-07-04 15:33:26] 得到函数 func-2 执行结果】
[2022-07-04 15:33:28]得到执行结果 【[2022-07-04 15:33:27] 得到函数 func-3 执行结果】
[2022-07-04 15:33:28]得到执行结果 【[2022-07-04 15:33:28] 得到函数 func-4 执行结果】Process finished with exit code 0 四、aiohttp与aiofiles
1、安装与使用
pip install aiohttp
2、简单实例使用
aiohttp的自我介绍中就包含了客户端和服务器端所以我们分别来看下客户端和服务器端的简单实例代码。
客户端
import aiohttp
import asyncioasync def fetch(session, url):async with session.get(url) as response:return await response.text()async def main():async with aiohttp.ClientSession() as session:html await fetch(session, http://httpbin.org/headers)print(html)asyncio.run(main())输出结果
{headers: {Accept: */*, Accept-Encoding: gzip, deflate, Host: httpbin.org, User-Agent: Python/3.7 aiohttp/3.6.2}
}这个代码是不是很简单一个函数用来发起请求另外一个函数用来下载网页。
3、入门
简单示范
首先是学习客户端也就是用来发送http请求的用法。首先看一段代码会在代码中讲述需要注意的地方
import aiohttp
import asyncioasync def main():async with aiohttp.ClientSession() as session:async with session.get(http://httpbin.org/get) as resp:print(resp.status)print(await resp.text())asyncio.run(main())
代码解释
在网络请求中一个请求就是一个会话然后aiohttp使用的是ClientSession来管理会话所以第一个重点看一下ClientSession:
class ClientSession:First-class interface for making HTTP requests.
在源码中这个类的注释是使用HTTP请求接口的第一个类。然后上面的代码就是实例化一个ClientSession类然后命名为session然后用session去发送请求。这里有一个坑那就是ClientSession.get()协程的必需参数只能是str类和yarl.URL的实例。
当然这只是get请求其他的请求都是支持的
session.post(http://httpbin.org/post, datadata)
session.get(http://httpbin.org/get)
4、在URL中传递参数
有时候在发起网络请求的时候需要附加一些参数到url中这一点也是支持的。
import aiohttp
import asyncioasync def main():async with aiohttp.ClientSession() as session:params {key1: value1, key2: value2}async with session.get(http://httpbin.org/get,paramsparams) as resp:print(resp.url)asyncio.run(main())
我们可以通过params参数来指定要传递的参数
同时如果需要指定一个键对应多个值的参数那么MultiDict就在这个时候起作用了。你可以传递两个元祖列表来作为参数
import aiohttp
import asyncioasync def main():async with aiohttp.ClientSession() as session:params [(key, value1), (key, value2)]async with session.get(http://httpbin.org/get,paramsparams) as r:expect http://httpbin.org/get?keyvalue2keyvalue1# assert str(r.url) expectprint(r.url)
asyncio.run(main())
5、读取响应内容
我们可以读取到服务器的响应状态和响应内容这也是使用请求的一个很重要的部分。通过status来获取响应状态码text()来获取到响应内容当然也可以之计指明编码格式为你想要的编码格式
async def main():async with aiohttp.ClientSession() as session:async with session.get(http://httpbin.org/get) as resp:print(resp.status)print(await resp.text(encodingutf-8)) 输出结果
200
!doctype html
html langzh-CN
head
......
6、非文本内容格式
对于网络请求有时候是去访问一张图片这种返回值是二进制的也是可以读取到的
await resp.read()
将text()方法换成read()方法就好。
7、请求的自定义
ClientResponse客户端响应对象含有request_info(请求信息)主要是url和headers信息。 raise_for_status结构体上的信息会被复制给ClientResponseError实例。
(1) 自定义Headers
有时候做请求的时候需要自定义headers主要是为了让服务器认为我们是一个浏览器。然后就需要我们自己来定义一个headers
headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36}
await session.post(url, headersheaders)
(2) 如果出现ssl验证失败的处理
import aiohttp
import asyncio
from aiohttp import TCPConnectorasync def main():async with aiohttp.ClientSession(connectorTCPConnector(sslFalse)) as session:pass
asyncio.run(main())
(3) 自定义cookie
发送你自己的cookies给服务器你可以为ClientSession对象指定cookies参数:
url http://httpbin.org/cookies
cookies {cookies_are: working}
async with ClientSession(cookiescookies) as session:async with session.get(url) as resp:assert await resp.json() {cookies: {cookies_are: working}}
(4) 使用代理
有时候在写爬虫的时候需要使用到代理所以aiohttp也是支持使用代理的我们可以在发起请求的时候使用代理只需要使用关键字proxy来指明就好但是有一个很难受的地方就是它只支持http代理不支持HTTPS代理。使用起来大概是这样
proxy http://127.0.0.1:10809
async with aiohttp.ClientSession(headersheaders) as session:async with session.get(urllogin_url, proxyproxy) as response:resu await response.text()
使用起来大概是这样然后代理记得改成自己的。 8、aiofiles文件读写
8.1 概述
平常使用的file操作模式为同步并且为线程阻塞。当程序I/O并发次数高的时候CPU被阻塞形成闲置。
线程开启文件读取异步模式
用线程Thread方式来解决。硬盘缓存可以被多个线程访问因此通过不同线程访问文件可以部分解决。但此方案涉及线程开启关闭的开销而且不同线程间数据交互比较麻烦。
from threading import Thread
for file in list_file:tr Thread(targetfile.write, args(data,))tr.start()
使用已编写好的第三方插件-aiofiles支持异步模式
使用aio插件来开启文件的非阻塞异步模式。
8.2 安装方法
pip install aiofiles
这个插件的使用和python原生open 一致而且可以支持异步迭代
8.3 实例
打开文件
import asyncio
import aiofilesasync def main():async with aiofiles.open(first.m3u8, moder) as f:contents await f.read()print(contents)if __name__ __main__:asyncio.run(main())
迭代import asyncio
import aiofilesasync def main():async with aiofiles.open(filename) as f:async for line in f:print(line)if __name__ __main__:asyncio.run(main())
9、并发控制
semaphore控制并发
semaphore asyncio.Semaphore(10)
实例
#!/usr/bin/pythonimport asyncio
import os
import aiofiles
import aiohttp
import requests
from bs4 import BeautifulSoupdef get_page_source(web):headers {user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36}response requests.get(web, headersheaders)response.encoding utf-8return response.textdef parse_page_source(html):book_list []soup BeautifulSoup(html, html.parser)a_list soup.find_all(div, attrs{class: mulu-list quanji})for a in a_list:a_list a.find_all(a)for href in a_list:chapter_url href[href]book_list.append(chapter_url)return book_listdef get_book_name(book_page):book_number book_page.split(/)[-1].split(.)[0]book_chapter_name book_page.split(/)[-2]return book_number, book_chapter_nameasync def aio_download_one(chapter_url, signal):number, c_name get_book_name(chapter_url)for c in range(10):try:async with signal:async with aiohttp.ClientSession() as session:async with session.get(chapter_url) as resp:page_source await resp.text()soup BeautifulSoup(page_source, html.parser)chapter_name soup.find(h1).textp_content soup.find(div, attrs{class: neirong}).find_all(p)content [p.text \n for p in p_content]chapter_content \n.join(content)if not os.path.exists(f{book_name}/{c_name}):os.makedirs(f{book_name}/{c_name})async with aiofiles.open(f{book_name}/{c_name}/{number}_{chapter_name}.txt, modew,encodingutf-8) as f:await f.write(chapter_content)print(chapter_url, 下载完毕!)return except Exception as e:print(e)print(chapter_url, 下载失败!, 重新下载. )return chapter_urlasync def aio_download(url_list):tasks []semaphore asyncio.Semaphore(10)for h in url_list:tasks.append(asyncio.create_task(aio_download_one(h, semaphore)))await asyncio.wait(tasks)if __name__ __main__:url https://www.51shucheng.net/daomu/guichuidengbook_name 鬼吹灯if not os.path.exists(book_name):os.makedirs(book_name)source get_page_source(url)href_list parse_page_source(source)loop asyncio.get_event_loop()loop.run_until_complete(aio_download(href_list))loop.close()