爬虫:异步(并行)数据爬取

原文地址

分类目录——爬虫

在进行网页爬取时,网页的响应速度慢于计算机的处理速度,在串行模式下访问多个网页,在通过网络获取一个网页的过程中,在这个过程之前,计算机只能闲置等待。而异步的方式就是让计算机可以在这个闲置时间先去做后面的工作,等这个网页响应完成再对它进行处理。

这里说的这种异步的方式是一种分时获得时间片的机制,有些像多线程,不同于多进程,私以为比较适合爬虫这种IO密集型操作。

  • 异步编程包——asyncio

    这里直接通过代码来说明它的语法

    async def job(t):                   # async 形式的功能
        print('Start job ', t)
        await asyncio.sleep(t)          # 等待 "t" 秒, 期间切换其他任务
        print('Job ', t, ' takes ', t, ' s')
    
    async def main(loop):                       # async 形式的功能
        tasks = [
            loop.create_task(job(t)) for t in range(1, 3)
        ]                                       # 创建任务, 但是不执行
        await asyncio.wait(tasks)               # 执行并等待所有任务完成
    
    t1 = time.time()
    loop = asyncio.get_event_loop()             # 建立 loop
    loop.run_until_complete(main(loop))         # 执行 loop
    loop.close()                                # 关闭 loop
    print("Async total time : ", time.time() - t1)
    # Start job  1
    # Start job  2
    # Job  1  takes  1  s
    # Job  2  takes  2  s
    # Async total time :  2.0259742736816406
    

    再做个非异步串行的对比操作

    def job(t):
        print('Start job ', t)
        time.sleep(t)               # wait for "t" seconds
        print('Job ', t, ' takes ', t, ' s')
    
    def main():
        [job(t) for t in range(1, 3)]
    
    t1 = time.time()
    main()
    print("NO async total time : ", time.time() - t1)
    # Start job  1
    # Job  1  takes  1  s
    # Start job  2
    # Job  2  takes  2  s
    # NO async total time :  3.001530647277832
    

    (注意rang(1,3)的结果是只有1,2两个值)

    可以看到异步方式的执行总时间是多个任务的最大时间,而非异步方式的执行总时间是多个任务的执行时间之和。当然这是在这种简单实例下的结果,在复杂问题或者非IO密集型的处理过程中,效果不会这么理想。

  • 将异步操作应用到爬虫——aiohttp

    对于aiohttp,可以简单的理解为异步形式的requests,(只是逻辑上的理解,语法并不同)

    还是通过代码来说明语法

    URL = 'https://blog.csdn.net/BBJG_001'
    async def job(session, url):
        response = await session.get(url)       # 等待并切换
        return str(response.url)
    
    async def main(loop):
        async with aiohttp.ClientSession() as session:      # 官网推荐建立 Session 的形式
            tasks = [loop.create_task(job(session, URL)) for _ in range(2)]
            finished, unfinished = await asyncio.wait(tasks)
            all_results = [r.result() for r in finished]    # 获取所有结果
            # print(all_results)
    
    t1 = time.time()
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main(loop))
    loop.close()
    print("Async total time:", time.time() - t1)
    # Async total time: 0.44501423835754395
    

    同样也进行非异步方式的对比

    URL = 'https://blog.csdn.net/BBJG_001'
    def normal():
        for i in range(2):
            r = requests.get(URL)
            url = r.url
            # print(url)
    
    t1 = time.time()
    normal()
    print("Normal total time:", time.time()-t1)
    # Normal total time: 0.7451720237731934
    

    可以看到在真正应用到网络环境中之后效果提速效果就不再像上面那样明显了,但是效率的提升还是很可观的。

  • 全部代码

  • 参考文献

    加速爬虫: 异步加载 Asyncio

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章