zoukankan      html  css  js  c++  java
  • 高性能异步爬虫

    asyncio异步携程模块

    在python3.4之后新增了asyncio模块,可以帮我们检测IO(只能是网络IO【HTTP连接就是网络IO操作】),实现应用程序级别的切换(异步IO)。注意:asyncio只能发tcp级别的请求,不能发http协议。 

    - 异步IO:所谓「异步 IO」,就是你发起一个 网络IO 操作,却不用等它结束,你可以继续做其他事情,当它结束时,你会得到通知。
    
      - 实现方式:单线程+协程实现异步IO操作。
    
      - 异步协程用法
    
        协程的实现,从 Python 3.4 开始,Python 中加入了协程的概念,但这个版本的协程还是以生成器对象为基础的,在 Python 3.5 则增加了 async/await,使得协程的实现更加方便。首先需要了解下面几个概念: 
    
    event_loop:事件循环,相当于一个无限循环,我们可以把一些函数注册到这个事件循环上,当满足条件发生的时候,就会调用对应的处理方法。
    
    coroutine:中文翻译叫协程,在 Python 中常指代为协程对象类型,我们可以将协程对象注册到时间循环中,它会被事件循环调用。我们可以使用 async 关键字来定义一个方法,这个方法在调用时不会立即被执行,而是返回一个协程对象。
    
    task:任务,它是对协程对象的进一步封装,包含了任务的各个状态。
    
    future:代表将来执行或没有执行的任务的结果,实际上和 task 没有本质区别。
    
      从 Python 3.5 出现的async/await 关键字,专门用于定义协程。其中,async 定义一个协程,await 用来挂起阻塞方法的执行。
    相关概念

    aiohttp异步网络请求模块

      aiohttp是基于asyncio实现的HTTP框架,pip install aiohttp。 

     1 import aiohttp
     2 
     3 #简单的基本架构:
     4 async def request(url):
     5    async with aiohttp.ClientSession() as s:
     6        #s.get/post和requests中的get/post用法几乎一样:url,headers,data/prames
     7        #在s.get中如果使用代理操作:proxy="http://ip:port"
     8        async with await s.get(url) as response:
     9            #获取字符串形式的响应数据:response.text()
    10            #获取byte类型的:response.read()
    11            page_text = await response.text()
    12            return page_text
    aiohttp使用事例

    单线程+多任务异步协程

      协程协程对象。使用async关键字修饰一个函数的定义(特殊的函数),当该特殊的函数被调用后,就可以返回一个协程对象。当函数调用后,函数内部的实现语句不会被立即执行。协程就是一个用async关键字修饰的特殊函数。协程定义:async def func():pass,创建协程对象:c=func() 

     1 '''
     2 协程是一个用async关键字修饰的特殊函数;
     3 在这个特殊函数内不允许出现不支持异步模块的代码,否则异步非阻塞将失效;
     4 在特殊函数中遇到阻塞的代码前必须使用await关键字手动挂起(后续示例)
     5 
     6 '''
     7 #定义一个协程
     8 async def func():
     9     print('一个协程对象')
    10 
    11 #创建协程对象
    12 c=func()
    协程/协程对象---async/await

       任务对象:本质上就是对协程对象进一步封装,好比是一个特殊函数。任务对象task=asyncio.ensure_future(c)可以绑定一个回调函数:task.add_done_callback(func_callback)-----func_callback回调函数只能接受task任务对象执行结果返回值,类比进程池/线程池中submit提交任务后的回调函数使用! 

     1 '''
     2 任务对象是对协程对象进行封装后的一个特殊函数;
     3 任务对象可以绑定一个回调函数;
     4 '''
     5 import  asyncio
     6 #定义一个协程
     7 async def func(n):
     8     print(n)
     9 
    10 #定义任务对象的回调函数:只能接受以个参数,该参数为任务对象执行结果返回值
    11 def call_back(task):
    12     print(task.result())
    13 
    14 #创建协程对象
    15 c=func(-1)
    16 
    17 
    18 #创建任务对象
    19 task=asyncio.ensure_future(c)
    20 #任务对象绑定回调函数
    21 task.add_done_callback(call_back)
    22 
    23 # 创建多个任务对象并为其绑定回调函数
    24 task_list=[]
    25 for i in range(5):
    26     c=func(i)
    27     task=asyncio.ensure_future(c)
    28     task.add_done_callback(task)
    29     task_list.append(task)
    单个/多个任务对象创建与回调函数绑定

       事件循环:事件循环对象的创建loop=asyncio.get_event_loop()必须将任务对象注册到事件循环对象中,自动开启事件循环对象,在执行任务对象的时候是基于异步的。单个任务对象的注册:loop.run_until_complete(task);多个任务对象的注册:loop.run_and_complete(asyncio.wait(task_list))。 

     1 '''
     2 创建事件循环对象对任务对象进行注册调用;
     3 注册单个任务对象/注册多个任务对象并自动调用执行;
     4 
     5 '''
     6 import  asyncio
     7 #定义一个协程
     8 import time
     9 
    10 
    11 async def func(n):
    12     await asyncio.sleep(2)#必须使用支持异步模块的代码,同时在遇到阻塞的代码前必须使用await手动挂起
    13     print(n)
    14     return n
    15 
    16 #定义任务对象的回调函数:只能接受以个参数,该参数为任务对象执行结果返回值
    17 def call_back(task):
    18     print(task.result())
    19 
    20 #创建协程对象
    21 c=func(-1)
    22 
    23 start=time.time()
    24 #创建任务对象
    25 task0=asyncio.ensure_future(c)
    26 #任务对象绑定回调函数
    27 task0.add_done_callback(call_back)
    28 
    29 # 创建多个任务对象并为其绑定回调函数
    30 task_list=[]
    31 for i in range(5):
    32     c=func(i)
    33     task=asyncio.ensure_future(c)
    34     task.add_done_callback(call_back)
    35     task_list.append(task)
    36 
    37 #创建事件循环对象
    38 loop=asyncio.get_event_loop()
    39 #注册单个任务对象
    40 loop.run_until_complete(task0)
    41 #注册多个任务对象
    42 loop.run_until_complete(asyncio.wait(task_list))
    43 
    44 loop.close()
    45 print(time.time()-start)#2.00264573097229
    事件循环对象及任务对象注册

       注意事项:

    •   在特殊函数(协程)中不能出现不支持异步模块对应的代码;
    •   在特殊函数(协程)遇到阻塞的代码必须添加关键字await对其手动挂起;
    •   如果将多个任务对象注册到事件循环对象中,先将多个任务对象添加到一个列表中,在注册时必须使用asyncio.wait()将列表中的任务对象挂起后再进行注册!

     单线程多任务异步爬虫实例

      flask服务器脚本构建:

    import time
    from flask import Flask
    app=Flask(__name__)
    @app.route('/<id>')
    def func1(id):
        time.sleep(2)
        return id
    
    
    if __name__ == '__main__':
        app.run()
    server构建

      单线程多任务异步数据采集代码

     1 import time
     2 import asyncio  # pip install asyncio
     3 import aiohttp  #pip install aiohttp
     4 headers = {
     5     'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
     6 }
     7 #创建urls列表
     8 urls = []
     9 for i in range(500):
    10     urls.append(f'http://127.0.0.1:5000/{i}')
    11 
    12 #定义携程函数-----简单的基本架构
    13 async def request(url):
    14    async with aiohttp.ClientSession() as s:
    15        #s.get/post和requests中的get/post用法几乎一样:url,headers,data/prames
    16        #在s.get中如果使用代理操作:proxy="http://ip:port"
    17        async with await s.get(url) as response:
    18            #获取字符串形式的响应数据:response.text()
    19            #获取byte类型的:response.read()
    20            page_text = await response.text()
    21            return page_text
    22 
    23 #定义任务对象回调函数
    24 def parse(task):
    25     page_text = task.result()
    26     print(f'响应结果:{page_text}')
    27 
    28 
    29 #创建任务列表
    30 start = time.time()
    31 tasks = []
    32 for url in urls:
    33     c = request(url)
    34     task = asyncio.ensure_future(c)
    35     task.add_done_callback(parse)
    36     tasks.append(task)
    37 #创建事件循环对象并将任务对象列表进行注册
    38 loop = asyncio.get_event_loop()
    39 loop.run_until_complete(asyncio.wait(tasks))
    40 loop.close()
    41 print(time.time()-start)#3.4196295738220215
    单线程多任务异步数据采集代码
  • 相关阅读:
    TensorBoard中HISTOGRAMS和DISTRIBUTIONS图形的含义
    Ubuntu中百度网盘BaiduPCS-Go的安装及简单使用
    IDEA滚轮控制字体大小
    IDEA插件搜索失败
    VSCode生成HTML代码模板
    linux中nohup运行python程序无后台输出
    PyTorch余弦学习率衰减
    查看pip缓存路径
    《算法笔记》阅读笔记
    数据库课程资料
  • 原文地址:https://www.cnblogs.com/open-yang/p/11311791.html
Copyright © 2011-2022 走看看