• 5.第五部分 异步爬虫


    第五部分 : 异步爬虫

    知识点一 : 异步

    解释
    并行真的多任务
    并发假的多任务,只不过运行速度非常块,感觉上像是多个一起运行

    注释1 : 利用单线程的空闲时间即为异步.

    知识点二 : asyncio 模块

    asyncio模块最大的特点是只存在一个线程,在这个线程中可以实现个任务"一起执行".

    格式
    定义异步函数async def test():
    调用异步函数asyncio.run(test())
    创建协程对象,在这个协程对象中创建其他的协程对象来实现真正的任务代码async def main(): await asyncio.gather(test1(),test2())
    调用多个异步函数await asyncio.gather(test1(),test2())

    注释1 : 在异步爬虫中不要使用同步的模块

    知识点三 : 中级_01_对比同步函数

    import time
    
    
    def Hello():
        time.sleep(1)
    
    
    def run():
        for i in range(5):
            Hello()
            print(f"执行第{i+1}次所用时间:{time.time()}")
    
    
    if __name__ == '__main__':
        run()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    知识点四 : 中级_02_对比异步函数

    import time
    import asyncio
    
    
    async def Hello():
        await asyncio.sleep(1)
        print(f"执行所用时间:{time.time()}")
    
    
    # 定义异步函数(一个异步函数可以认为就是一个协程)
    async def run():  # 加async变为异步函数
        tasks = list()
        for i in range(5):
            tasks.append(Hello())
    
        await asyncio.wait(tasks)
    
    
    if __name__ == '__main__':
        asyncio.run(run())  # 调用异步函数
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    知识点五 : 中级_03_调用异步函数

    import asyncio
    
    
    def test1():
        """
        这是一个同步函数
        """
        print("test1")
        return 1
    
    
    async def test2():
        """
        这是一个异步函数
        """
        print("test2")
        return 2
    
    
    async def test3():
        """
        这是一个异步函数
        """
        print("test3")
        return 3
    
    
    async def test4():
        """
        这是一个异步函数
        """
        print("test4")
        return 4
    
    
    # 1.调用同步函数
    print(test1())
    print("-------------------------")
    
    # 2.调用异步函数
    print(asyncio.run(test4()))
    print("-------------------------")
    
    if __name__ == '__main__':
        # 创建一个事件循环
        loop = asyncio.get_event_loop()
        # 创建协程(此时test4这个协程中的任务代码并没有真正的开始执行)
        t3 = test3()
        # 进入事件循环
        print(loop.run_until_complete(t3))
        # 关闭事件循环
        loop.close()
    
    """
    print(test4())不是在调用函数,而是在创建对象
    """
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    知识点六 : 中级_04_调用异步函数 ( 方式二 )

    import asyncio
    
    async def test0():
        """
        这是一个异步函数
        """
        print("test0")
        return 0
    
    if __name__ == '__main__':
        # 创建一个事件循环
        loop = asyncio.get_event_loop()
        # 创建协程(此时test4这个协程中的任务代码并没有真正的开始执行)
        t0 = test0()
        # 进入事件循环
        print(loop.run_until_complete(t0))
        # 关闭事件循环
        loop.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    知识点七 : 中级_05_异步并发执行任务

    import asyncio
    
    
    async def test1():
        for i in range(3):
            print("协程A_1.0")
            await asyncio.sleep(0)
            print("协程A_2.0")
    
    
    async def test2():
        for i in range(5):
            print("协程B_1.0")
            """
            因为在test1协程中执行到了asyncio.sleep(),无论sleep时间是多少,此
            时event loop检查到进行延时,此时event loop就可以将代码的调度权限给
            test2协程对象,此时test2开始执行
            """
            await asyncio.sleep(0)      # 会导致event loop开始找下一个可以运行的协程对象
            print("协程B_2.0")
    
    
    async def main():
        # 2.创建了其他的协程对象,在这些协程对象中实现真正的任务代码
        await asyncio.gather(test1(), test2())
    
    
    if __name__ == '__main__':
        # 1.创建一个coroutine对象(协程)
        asyncio.run(main())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    知识点八 : 中级_06_异步 task 任务

    """
    	help1: asyncio 用 task(任务) 来实现异步.
    """
    
    
    import asyncio
    import time
    
    
    async def test1():
        print(f"协程A_StartTime: {time.time()}")
        for i in range(10):
            print(f"→执行第{i+1}次协程A")
            await asyncio.sleep(1)
        print(f"协程A_StopTime: {time.time()}")
    
    
    async def test2():
        print(f"协程B_StartTime: {time.time()}")
        for i in range(10):
            print(f"→执行第{i+1}次协程B")
            await asyncio.sleep(1)
        print(f"协程B_StopTime: {time.time()}")
    
    
    async def main():
        task1 = asyncio.create_task(test1())    # create_task()对协程对象进行封装,使其具备更高级的功能
        task2 = asyncio.create_task(test2())
        print("------------------------------")
        print(f"task1 is over? 状态为:{task1.done()}") # done()返回当前状态(True或False)
        print(f"task2 is over? 状态为:{task2.done()}")
    
        # 多个task任务
        tasks = [task1, task2]
        await asyncio.wait(tasks)   # wait()是等待列表中的内容执行完毕
        print("------------------------------")
        print(f"task1 is over? 状态为:{task1.done()}")
        print(f"task2 is over? 状态为:{task2.done()}")
    
    
    if __name__ == '__main__':
        start_time = time.time()
        asyncio.run(main())
        stop_time = time.time()
        print("------------------------------")
        print(f"总耗时:{stop_time-start_time}")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    知识点九 : 中级_07_异步 task 返回值

    import asyncio
    
    
    async def test():
        print("------------------------------")
        print("→执行test")
        return 100
    
    
    async def main():
        task = asyncio.create_task(test())
    
        # 单个task任务
        await task
        print("------------------------------")
        print(f"task is over? 状态为:{task.done()}")
        print(f"test的返回值为: {task.result()}")
    
    
    if __name__ == '__main__':
        asyncio.run(main())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    知识点十 : 中级_08_异步 task 添加回调函数

    import asyncio
    
    
    def callback_after_done(task_obj):
        # 该函数在test任务完成后自动调用,会自动将完成后的task对象当作参数传递
        print("------------------------------")
        print(f"→callback_after_done_1: {task_obj}")
        print(f"→callback_after_done_2: {task_obj.done()}")
        print(f"→callback_after_done_3: {task_obj.result()}")
    
    
    async def test():
        print("→执行test")
        return 100
    
    
    async def main():
        task = asyncio.create_task(test())
        task.add_done_callback(callback_after_done) # 注意该参数是函数名,不是函数名()
    
        # 单个task任务
        await task
        print("------------------------------")
        print(f"task is over? 状态为:{task.done()}")
        print(f"test的返回值为: {task.result()}")
    
    
    if __name__ == '__main__':
        asyncio.run(main())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    知识点十一 : 中级_09_异步 task 给回调函数传递参数

    import asyncio
    import functools
    
    
    def callback_after_done(task_obj, num1, num2):
        # 该函数在test任务完成后自动调用,会自动将完成后的task对象当作参数传递
        print("------------------------------")
        print(f"→callback_after_done_1: {task_obj}")
        print(f"→callback_after_done_2: {task_obj.done()}")
        print(f"→callback_after_done_3: {num1},{num2}")
    
    
    async def test():
        print("→执行test")
        return 100
    
    
    async def main():
        task = asyncio.create_task(test())
        # functools.partial()给回调函数传递参数
        task.add_done_callback(functools.partial(callback_after_done, num1=100, num2=200))
    
        # 单个task任务
        await task
        print("------------------------------")
        print(f"task is over? 状态为:{task.done()}")
        print(f"test的返回值为: {task.result()}")
    
    
    if __name__ == '__main__':
        asyncio.run(main())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    知识点十二 : 中级_10_aiohttp 的基本使用

    """
    	help1: request模块是同步的,而aiohttp相当于是异步版的request模块.
    """
    
    
    import asyncio
    import aiohttp
    
    
    tasks = []
    url = "https://www.baidu.com"
    
    
    async def get_Baidu(u):
        async with aiohttp.ClientSession() as session:      # async的意思是耗费时间太长就切换任务,with表示打开,as是取的别名
            async with session.get(url) as r:
                resp_text = await r.text()      # await等待其后面代码执行完毕
                print(resp_text)
    
    
    if __name__ == '__main__':
        # loop = asyncio.get_event_loop()   # 创建一个事件循环
        # loop.run_until_complete(get_Baidu(u=url))     # 进入事件循环
        asyncio.run(get_Baidu(url))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    知识点十三 : 中级_11_aiohttp 的并发使用

    import asyncio
    import aiohttp
    
    
    def dowload_completed_callback(task_obj):
        print(f"下载的内容为:{task_obj.result()}")
    
    
    async def baidu_spider():
        print("==========百度蜘蛛==========")
        url = "https://www.baidu.com"
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as r:
                return await r.text()
    
    
    async def sogou_spider():
        print("==========搜狗蜘蛛==========")
        url = "https://www.sogou.com"
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as r:
                return await r.text()
    
    
    async def jingdong_spider():
        print("==========京东蜘蛛==========")
        url = "https://www.jd.com"
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as r:
                return await r.text()
    
    
    async def main():
        # 创建多个task,且添加回调函数
        task_baidu = asyncio.create_task(baidu_spider())
        task_baidu.add_done_callback(dowload_completed_callback)
    
        task_sogou = asyncio.create_task(sogou_spider())
        task_sogou.add_done_callback(dowload_completed_callback)
    
        task_jingdong = asyncio.create_task(jingdong_spider())
        task_jingdong.add_done_callback(dowload_completed_callback)
    
        # 等待下载
        tasks = [task_baidu, task_sogou, task_jingdong]
        await asyncio.wait(tasks)
    
    
    if __name__ == '__main__':
        asyncio.run(main())
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
  • 相关阅读:
    CSS过渡效果
    时光机特效什么app好?建议收藏这些软件
    节流(Throttle)和防抖(Debounce)
    PAT A1006 Sign In and Sign Out
    SpringBoot实现扫码登录
    游戏史上五个定价最高的量产型游戏机
    k8s之三、pod生命周期/探针/调度策略/控制器
    高防服务器与高防IP区别
    pytorch迁移学习训练图像分类
    参数解析(牛客)
  • 原文地址:https://blog.csdn.net/m0_56126722/article/details/125985564