zoukankan      html  css  js  c++  java
  • python爬虫--多任务异步协程, 快点,在快点......

    多任务异步协程asyncio

    特殊函数:
    	- 就是async关键字修饰的一个函数的定义
    	- 特殊之处:
            - 特殊函数被调用后会返回一个协程对象
            - 特殊函数调用后内部的程序语句没有被立即执行
            
    - 协程
        - 对象。协程==特殊的函数。协程表示的就是一组特定的操作。
        
    - 任务对象
        - 高级的协程(对协程的进一步的封装)
            - 任务对象==协程==特殊的函数
                - 任务对象==特殊的函数
        - 绑定回调:
            - task.add_done_callback(task)
                - 参数task:当前回调函数对应的任务对象
                - task.result():返回的就是任务对象对应的特殊函数的返回值
                
    - 事件循环对象
        - 创建事件循环对象
        - 将任务对象注册到该对象中并且开启该对象
        - 作用:loop可以将其内部注册的所有的任务对象进行异步执行
    
    - 挂起:就是交出cpu的使用权。
    
    await:被用做在特殊函数的内部,在被阻塞的时候
    wait:给每一个任务赋予一个可被挂起的权限
    
    #【重点】在特殊函数内部的实现中,不可以出现不支持异步的模块(例如time,requests)代码,如果出现了,则会中断整个的异步效果!!!
    

    asyncio的使用

    import asyncio
    import time
    from time import sleep
    
    # 特殊函数
    async def get_request(url):
        print('正在下载: ',url)
        sleep(2)
        print('下载完毕: ',url)
        return 'page_text'
    
    # 回调函数,普通函数
    def parse(task):
        # 参数表示任务对象
        print('i am callback',task.result())
    
    
    start = time.time()
    # 调用特殊函数
    func = get_request('www.xx.com')
    
    # 创建任务对象
    task = asyncio.ensure_future(func)
    
    # 给任务对象绑定回调函数
    task.add_done_callback(parse)
    
    # 创建一个事件循环对象
    loop = asyncio.get_event_loop()
    
    # 让loop执行一个任务
    loop.run_until_complete(task)
    
    print("总耗时:",time.time()-start) #总耗时: 2.0017831325531006
    

    多任务协程

    import asyncio
    import time
    
    # 特殊函数
    async def get_request(url):
        print('正在下载',url)
        # time.sleep(2) 不支持异步的模块 会中断整个的异步效果
        await asyncio.sleep(2)
        print('下载完成',url)
        return 'page_text'
    
    def parse(task):
        print(task.result())
    
    
    start = time.time()
    urls = ['www.xxx1.com','www.xxx2.com','www.xxx3.com']
    
    tasks = []  #存放多任务
    for url in urls:
        # 调用特殊函数
        func = get_request(url)
    
        # 创建任务对象
        task = asyncio.ensure_future(func)
    
        # 给任务对象绑定回调函数
        task.add_done_callback(parse)
        tasks.append(task)
    
    # 创建事件循环对象
    loop = asyncio.get_event_loop()
    
    # 执行任务
    loop.run_until_complete(asyncio.wait(tasks))
    print('总耗时:',time.time()-start) #2.0015313625335693
    
    

    aiohttp的使用

    - requests一定是不支持异步
    - aiohttp是一个支持异步的网络请求模块
        - 环境安装
        - 编码流程:
            - 大致的架构:
                 with aiohttp.ClientSession() as s:
                    #s.get(url,headers,params,proxy="http://ip:port")
                    with s.get(url) as response:
                        #response.read()二进制(.content)
                        page_text = response.text()
                        return page_text
                    
        - 补充细节
             - 在每一个with前加上async
             - 需要在每一个阻塞操作前加上await
                    async with aiohttp.ClientSession() as s:
                        #s.get(url,headers,params,proxy="http://ip:port")
                        async with await s.get(url) as response:
                            #response.read()二进制(.content)
                            page_text = await response.text()
                            return page_text
    
    

    异步协程爬虫案例

    # 需求用多任务异步协程获取百度,搜狗,京东,淘宝的页面源码数据,并简单解析
    import asyncio
    import requests
    import time
    from lxml import etree
    urls = ['https://www.baidu.com','http://www.taobao.com/','http://www.jd.com/','https://www.sogou.com/']
    headers={
        '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'
    }
    # 特殊函数
    async def get_request(url):
        print('正在下载',url)
        page_text = requests.get(url,headers=headers).text
        print(url,'下载完成')
        return page_text
    
    # 回调函数
    def parse(task):
        page_text = task.result()
        tree = etree.HTML(page_text)
        div = tree.xpath('//div')
        print(div)
    
    start = time.time()
    tasks = []#存放多任务
    for url in urls:
        func = get_request(url)
        task = asyncio.ensure_future(func)
        task.add_done_callback(parse)
        tasks.append(task)
    
    # 创建事件要在循环外
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))
    
    print('总耗时:',time.time()-start)
    
    #根据结果发现执行并不是异步,原因是requests不是异步模块,所以整个程序不会异步执行
    

    基于aiohttp的多任务协程的爬虫

    # 需求用多任务异步协程获取百度,搜狗,京东,淘宝的页面源码数据,并简答解析
    import asyncio
    import requests
    import time
    import aiohttp
    from lxml import etree
    urls = ['https://www.baidu.com','http://www.taobao.com/','http://www.jd.com/','https://www.sogou.com/']
    headers={
        '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'
    }
    # 特殊函数
    async def get_request(url):
        async with aiohttp.ClientSession() as s:
            # s.get(url,headers,params,proxy="http://ip:port")
            async with await s.get(url,headers=headers) as response:
                print('正在下载', url)
                # response.read()二进制(.content)
                page_text = await response.text()
                print(url, '下载完成')
                return page_text
    
    # 回调函数
    def parse(task):
        page_text = task.result()
        tree = etree.HTML(page_text)
        div = tree.xpath('//div')
        print(div)
    
    start = time.time()
    tasks = []#存放多任务
    for url in urls:
        func = get_request(url)
        task = asyncio.ensure_future(func)
        task.add_done_callback(parse)
        tasks.append(task)
    
    # 创建事件要在循环外
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))
    
    print('总耗时:',time.time()-start) #总耗时: 3.0848371982574463
    
  • 相关阅读:
    URAL 2067 Friends and Berries (推理,数学)
    URAL 2070 Interesting Numbers (找规律)
    URAL 2073 Log Files (模拟)
    URAL 2069 Hard Rock (最短路)
    URAL 2068 Game of Nuts (博弈)
    URAL 2066 Simple Expression (水题,暴力)
    URAL 2065 Different Sums (找规律)
    UVa 1640 The Counting Problem (数学,区间计数)
    UVa 1630 Folding (区间DP)
    UVa 1629 Cake slicing (记忆化搜索)
  • 原文地址:https://www.cnblogs.com/tangjian219/p/12002525.html
Copyright © 2011-2022 走看看