zoukankan      html  css  js  c++  java
  • 单线程+异步协程的简单爬虫模型

    event_loop:事件循环,相当于一个无限循环(不清楚循环多少次),我们可以把一些特殊函数注册(放置)到这个事件循环上,当满足某些条件的时候,函数就会被循环执行。程序是按照设定的顺序从头执行到尾,运行的次数也是完全按照设定。当在编写异步程序时,必然其中有部分程序的运行耗时是比较久的,需要先让出当前程序的控制权,让其在背后(挂起)运行,让另一部分的程序先运行起来。当背后运行的程序完成后,也需要及时通知主程序已经完成任务可以进行下一步操作,但这个过程所需的时间是不确定的,需要主程序不断的监听状态,一旦收到了任务完成的消息,就开始进行下一步。loop就是这个持续不断的监视器。

    coroutine:中文翻译叫协程,在 Python 中常指代为协程对象类型,我们可以将协程对象注册到事件循环中,
    它会被事件循环调用。我们可以使用 async 关键字来定义一个方法,这个方法在调用时不会立即被执行,
    而是返回一个协程对象。

    task:任务,它是对协程对象的进一步封装,包含了任务的各个状态。

    future:代表将来执行或还没有执行的任务,实际上和 task 没有本质区别。

    另外我们还需要了解 async/await 关键字,它是从 Python 3.6 才出现的,专门用于定义协程。其中,async 定义一个协程,await 用来挂起阻塞方法的执行。

    import asyncio
    async def request(url):
        print('正在请求:',url)
        print('下载成功:',url)
    
    c = request('www.baidu.com')
    
    # 第一步:实例化一个事件循环对象
    loop = asyncio.get_event_loop()
    # 第二步:创建一个任务对象,将协程对象封装到了该对象中
    # task = loop.create_task(c)
    
    # 另一种形式实例化任务对象的方法   
    task = asyncio.ensure_future(c)
    
    #将协程对象注册到事件循环对象中,并且我们需要启动事件循环对象
    loop.run_until_complete(task)
    # 打印task可以看到任务对象状态
    print(task)

    绑定回调函数,在爬虫中必须用回调函数,因为在数据爬取下来后,用回调函数可以进行数据解析

    import asyncio
    
    async def request(url):
        print('正在请求:',url)
        print('下载成功:',url)
        return url
    
    #回调函数必须有一个参数:task
    #task.result():任务对象中封装的协程对象对应的特殊函数内部的返回值
    def callbak(task):
        print('this is callback!')
        print(task.result())
    
    c = request('www.baidu.com')
    
    #给任务对象绑定一个回调函数
    #  创建任务对象
    task = asyncio.ensure_future(c)
    # 绑定回调函数
    task.add_done_callback(callbak)
    
    # 注册到时间循环中
    loop = asyncio.get_event_loop()
    
    loop.run_until_complete(task)

    多任务异步协程

    from time import sleep
    import asyncio
    import time
    urls = ['www.baidu.com','www.sogou.com','www.goubanjia.com']
    start = time.time()
    async def request(url):
        print('正在请求:',url)
        #在多任务异步协程实现中,不可以出现不支持异步的相关代码。
        # sleep(2)
        await asyncio.sleep(2)
        print('下载成功:',url)
    
    loop = asyncio.get_event_loop()
    #任务列表:放置多个任务对象
    tasks = []
    for url in urls:
        c = request(url)
        task = asyncio.ensure_future(c)
        tasks.append(task)
    
    loop.run_until_complete(asyncio.wait(tasks))
    
    print(time.time()-start)

    单线程+多任务异步

    # 面试问题,如何提升爬取效率
    # 使用方向:数据量大,数据占内存大
    #aiohttp:支持异步的一个基于网络请求的模块
    # 和requests模块功能应用都一样,区别就是支持异步
    # pip install aiohttp
    
    import requests
    import asyncio
    import time
    import aiohttp
    #单线程+多任务异步协程
    urls = [
        'http://127.0.0.1:5000/jay',
        'http://127.0.0.1:5000/bobo',
        'http://127.0.0.1:5000/tom'
    ]
    # 异步效果,遇到阻塞,挂起阻塞,执行别的任务
    #代理操作:
    #async with await s.get(url,proxy="http://ip:port") as response:
    async def get_pageText(url):
        # 请求对象,with不关闭资源,
       async with aiohttp.ClientSession() as s:
          async with await s.get(url) as response:
              # 拿响应数据有可能阻塞所以需要await, 这里是text方法,request是text方法
               page_text = await response.text()
                # 借助于回调函数进行响应数据的解析操作
               return page_text
    #封装回调函数用于数据解析
    def parse(task):
        #1.获取响应数据
        page_text = task.result()
        print(page_text+',即将进行数据解析!!!')
        #解析操作写在该位置
    
    start = time.time()
    tasks = []
    for url in urls:
        c = get_pageText(url)
        task = asyncio.ensure_future(c)
        #给任务对象绑定回调函数用于数据解析
        task.add_done_callback(parse)
        tasks.append(task)
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))
    
    print(time.time()-start)



  • 相关阅读:
    hihocoder 1049 后序遍历
    hihocoder 1310 岛屿
    Leetcode 63. Unique Paths II
    Leetcode 62. Unique Paths
    Leetcode 70. Climbing Stairs
    poj 3544 Journey with Pigs
    Leetcode 338. Counting Bits
    Leetcode 136. Single Number
    Leetcode 342. Power of Four
    Leetcode 299. Bulls and Cows
  • 原文地址:https://www.cnblogs.com/wmh33/p/11037385.html
Copyright © 2011-2022 走看看