Python基于asyncio的多任务异步爬虫框架

基本概念:

  • 单线程+多任务异步协程:pip install asyncio
    • 特殊的函数

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

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

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

      • 对象。
      • 作用:
        • 可以将多个任务对象注册/装载到事件循环对象中
        • 如果开启了事件循环后,则其内部注册/装载的任务对象表示的指定操作就会被基于异步的被执行
      • 创建方式:
        • loop = asyncio.get_event_loop()
      • 注册且启动方式:
        • loop.run_until_complete(task)
    • wait方法的作用:

      • 将任务列表中的任务对象赋予可被挂起的权限。只有任务对象被赋予了可被挂起的权限后,该任务对象才可以被挂起
        • 挂起:将当前的任务对象交出cpu的使用权。
    • 注意事项【重要】:

      • 在特殊函数内部不可以出现不支持异步模块对应的代码,否则会中断整个异步效果
    • await关键字

      • 在特殊函数内部,凡是阻塞操作前都必须使用await进行修饰。await就可以保证
        阻塞操作在异步执行的过程中不会被跳过!

多任务异步爬虫框架:

import requests
import asyncio
import time
import aiohttp
from lxml import etree
urls = [ # 用列表存储你想要爬取的网站
    'http://www.1.com',
    'http://www.2.com',
    'http://www.3.com' 
]

# requests是一个不支持异步的模块,需要使用aiohttp发起请求
# get_request()被async修饰后变成了一个特殊的函数
async def get_request(url):
    #实例化好了一个请求对象
    async with aiohttp.ClientSession() as sess:
        #调用get发起请求,返回一个响应对象
        #get/post(url,headers,params/data,proxy="http://ip:port")
        async with await sess.get(url=url) as response:
            #text()获取了字符串形式的响应数据
            #read()获取byte类型的响应数据
            page_text = await response.text()
            return page_text

#解析函数的封装
#参数t:就是该回调函数的调用者(任务对象)
def parse(t):
    #获取请求到页面源码数据
    page_text = t.result() # result返回的就是特殊函数的返回值
    tree = etree.HTML(page_text)
    parse_text = tree.xpath('//a[@id="feng"]/text()')[0]
    print(parse_text)

if __name__ == "__main__":
    start = time.time()
    tasks = []
    for url in urls:
        c = get_request(url) # c就是一个协程对象
        task = asyncio.ensure_future(c) # 任务对象就是对协程对象的进一步封装
        task.add_done_callback(parse) # 给task绑定一个回调函数
        tasks.append(task)
    loop = asyncio.get_event_loop() # 创建事件循环对象
    loop.run_until_complete(asyncio.wait(tasks)) # 将任务对象注册到事件循环中且开启事件循环
    print('总耗时:',time.time()-start)
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值