实战:异步爬取之初识异步

作者: 渔父歌 | 来源:发表于2018-08-16 13:50 被阅读15次

    一、为什么要用异步?

    许多之前没有听说过异步地朋友可能看到标题地第一反应就是:什么是异步?为什么要用异步?

    我们先来讲讲为什么要用异步,对于爬虫来说,在能够爬取到数据地前提下当然是越快越好,显然传统地同步代码不能满足我们对速度地需求。

    这时候我们想到了多线程,虽然多线程能够提高速度,但是单论效率来说多线程是不如同步代码的,因为还要花费资源来管理线程

    而且多线程还有资源竞争的问题,这就不得不使用资源锁来保证同一时间只有一个线程访问,而这使得多线程的速度更加慢,这也是为什么在上一篇我们使用十个线程却只达到 9倍速度的原因。

    而异步却没有这些问题,异步虽然被称作异步,但本质上异步代码都是同步的,它们都运行在一个线程里,这样就不需要考虑线程管理和资源竞争的问题了。

    并且异步的速度非常快,为什么是非常快而不是很快?因为异步真的太快了。

    不说废话,我们拿数据说事:

    正常情况下我们请求一个页面大概是 0.3到 0.8秒左右(带宽 100m)

    也就是说如果我们请求同一个页面 100次的话,最少也得花费 30秒

    如果换成异步呢?

    使用异步如果只请求一个页面的话,和同步差不多,也是在 0.3到 0.8之间

    但是如果请求同一个页面 100次的话,只需要要 3秒左右

    国外有人做过测试:

    请求次数 花费时间
    100 3.48s
    1000 7s
    10k 23s
    100k 53s
    1000k 9 min 3s

    (数据来源:Making 1 million requests with python-aiohttp)

    从表中的数据可以看出来异步的最大速度可以达到 100k每分钟,可以说是非常快了。

    在我的的测试中,最快达到了 2k每分钟,与上面的数据相差较大(难道是我的打开方式不对?)。

    不过不管怎样,我们能够确定异步很快。

    对于一些异步的基本概念不了解的朋友可以去看这篇文章: 深入理解 Python 异步编程(上)

    下面我们以一个简单的例子来了解一下异步的使用

    二、异步的简单使用

    在开始之前,大家要牢记异步是单线程的,所以代码中不能有非异步的 I/O 操作。

    像 requests、文件写入等 耗时的 I/O操作都不能直接使用。

    不过这些库都有对应的异步版本,比如 requests就可以使用 aiohttp代替。

    下面我们来看一个简单的例子,来感受一下异步的速度:

    首先我们使用 requests库来请求百度首页一次:

    import time
    import requests
    
    
    def getBaiduPage():
        url = 'https://www.baidu.com/'
        headers = {
            'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36'
        }
    
        r = requests.get(url, headers=headers)
    
        print(r.status_code)
    
    
    start = time.time()
    
    getBaiduPage()
    
    end = time.time()
    
    print(f'用时{end - start} s')
    

    输出:

    200
    用时0.5322993278503418 s
    

    我们再试试请求 10次:

    start = time.time()
    
    for i in range(10):
        getBaiduPage()
        
    end = time.time()
    
    print(f'用时{end - start} s')
    

    输出:

    200
    ...
    200
    用时3.976729393005371 s
    

    我们再来看看异步:

    请求一次:

    import time
    
    import asyncio
    import aiohttp
    
    
    async def getBaiduPageAsync():
        url = 'https://www.baidu.com/'
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36'
        }
        async with aiohttp.ClientSession() as session:
            async with session.get(url, headers=headers) as response:
                print(response.status)
    
    
    start = time.time()
    
    
    loop = asyncio.get_event_loop()
    
    loop.run_until_complete(asyncio.ensure_future(getBaiduPageAsync()))
    
    
    end = time.time()
    
    print(f'用时{end - start} s')
    

    输出:

    200
    用时0.599806547164917 s
    

    用异步请求 10次:

    start = time.time()
    
    loop = asyncio.get_event_loop()
    
    tasks = []
    for i in range(10):
        tasks.append(asyncio.ensure_future(getBaiduPageAsync()))
    
    loop.run_until_complete(asyncio.wait(tasks))
    
    end = time.time()
    
    print(f'用时{end - start} s')
    

    输出:

    200
    ...
    200
    用时0.512629508972168 s
    

    我们列个表格来看看,requests和 aiohttp之间的区别:

    请求一次 请求十次
    requests 0.5322993278503418 s 3.976729393005371 s
    aiohttp 0.599806547164917 s 0.512629508972168 s

    通过表格我们不难发现,在请求一次的时候 requests和 aiohttp相差不大,但是在请求十次的时候 requests和 aiohttp相差巨大,甚至 aiohttp请求十次所用的时间和请求一次的时间相当。

    其实这还不能体现出异步真正的速度,让我们来看看使用异步请求 100次:

    
    start = time.time()
    
    loop = asyncio.get_event_loop()
    
    tasks = []
    for i in range(100):
        tasks.append(asyncio.ensure_future(getBaiduPageAsync()))
    
    loop.run_until_complete(asyncio.wait(tasks))
    
    end = time.time()
    
    print(f'用时{end - start} s')
    

    输出:

    200
    ...
    200
    用时1.6467080116271973 s
    

    好像异步请求的页面越多速度越快(⊙o⊙)。

    别想多了ε=ε=ε=( ̄ ̄),其实异步的速度是有个上限的,从我们的第一个表格来看,这个上限是 100k每分钟。

    这里只写了一个简单的示例来测试异步请求的速度,关于异步的详细使用我们留到下一篇。

    想了解为什么异步如此快,可以阅读: 深入理解 Python 异步编程(上)

    相关文章

      网友评论

        本文标题:实战:异步爬取之初识异步

        本文链接:https://www.haomeiwen.com/subject/dcanbftx.html