异步爬虫

  • 基于线程池

    • 线程池

      1
      
      from multiprocessing.dummy import Pool
      
    • map(callback, list)

    • 可以使用callback对list中的每一个元素进行指定形式的异步操作

     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
    
    import requests
    import time
    from multiprocessing.dummy import Pool
    
    def get_request(url):
        page_text = requests.get(url=url).text
        return len(page_text)
    
    
    # if __name__ == "__main__":
    #     start = time.time()
    #     urls = [
    #         'http://127.0.0.1:5000/aoligei',
    #         'http://127.0.0.1:5000/jay',
    #         'http://127.0.0.1:5000/haha',
    #     ]
    #     for url in urls:
    #         res = get_request(url)
    #         print(res)
    #
    #     print('耗时', time.time()-start)
    
    # 异步代码
    
    
    if __name__ == "__main__":
        urls = [
            'http://127.0.0.1:5000/aoligei',
            'http://127.0.0.1:5000/jay',
            'http://127.0.0.1:5000/haha',
        ]
        start = time.time()
        pool = Pool(3)  # 3表示开启线程的数量
        result_list = pool.map(get_request, urls) # 使用get_request作为回调函数,需要基于异步的形式对urls列表中的没一个列表元素进行操作 回调函数要有一个参数和返回值
        print('耗时', time.time()-start)
    
  • 基于单线程+多任务的异步爬虫

    • 特殊的函数

      • 如果一个函数的定义被async修饰后,则该函数就变成了一个特殊的函数
        • 该特殊函数调用后,函数内部的实现语句不会被立即执行
        • 该特殊函数被调用后会返回一个协程对象
    • 协程对象

      • 通过特殊函数的调用返回一个协程对象。
      • 协程 == 一组特定的操作
    • 任务对象

      • 任务对象就是一个高级协程对象。(是对协程对象的进一步封装)
      • 任务 == 协程 == 特殊函数 == 指定操作
      • 创建一个任务对象
        • task = asyncio.ensure_future(协程对象)
      • 高级之处:可以给任务对象绑定回调:
        • 任务被执行结束后才可以调用回调函数:
          • 参数(只能有一个)就是该回调函数的调用者(任务对象)
          • result返回的就是特殊函数的返回值
    • 事件循环对象

      • 作用:
        • 可以将对个任务对象注册到事件循环对象中
        • 如果开启了事件循环后,则其内部注册/装在的任务对象所表示的指定的操作就会被基于异步的被执行
      • 创建方式
        • loop = asyncio.get_event_loop() /创建事件循环对象
        • loop.run_until_complete(task) /将任务对象注册到事件循环对象中并开始事件循环
       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
      
      import requests
      import asyncio
      import time
      import aiohttp
      
      urls = [
          'http://127.0.0.1:5000/aoligei',
          'http://127.0.0.1:5000/jay',
          'http://127.0.0.1:5000/haha',
      ]
      
      
      async def get_page(url):
          # requests.get是基于同步,必须使用基于异步的网络请求模块进行指定url的请求发送
          # aiohttp:基于异步网络求情的模块
          # response = requests.get(url)
          async with aiohttp.ClientSession() as session:
              # session. get()/post()
              # headers,params/data.proxy=''
              async with await session.get(url) as response:
                  # text()返回字符串形式的相应数据
                  # read()返回二进制形式的相应数据
                  # json()返回json对象
                  page_text = await response.text()
                  print(page_text)
      
      
      tasks = []
      if __name__ == '__main__':
          start = time.time()
      
          for url in urls:
              c = get_page(url)
              task = asyncio.ensure_future(c)
              tasks.append(task)
      
          loop = asyncio.get_event_loop()
          loop.run_until_complete(asyncio.wait(tasks))
          print(time.time() - start)
      
Licensed under CC BY-NC-SA 4.0
comments powered by Disqus