zoukankan      html  css  js  c++  java
  • 爬虫入门四(提升爬取数据的效率:线程池和异步协程)

    1、提升爬取数据的效率:线程池

    简述

    from multiprocessing.dummy import Pool
    map(func,alist): # func 函数 alist 可迭代元素 分别将里面的值 传入func中
        可以让func回调函数处理alist中的每一个列表元素,这个处理的过程是基于异步。
    

    示例1:线程池的应用

    import requests
    import time
    from multiprocessing.dummy import Pool
    start = time.time()
    #开启线程池
    pool = Pool(3)
    # 要访问的url
    urls = [
        'http://127.0.0.1:5000/index',
        'http://127.0.0.1:5000/index',
        'http://127.0.0.1:5000/index'
    ]
    #用作与网络请求(耗时) 
    def req(url):
        return requests.get(url).text
    # 开启 进程池里面有三个进程 分别将url中元素 传入req函数中 
    # 最后 page_text_list 是线程池结果 类型是列表
    page_text_list = pool.map(req,urls)
    print(page_text_list)
    print('总耗时:',time.time()-start)
    

    2、单线程+多任务异步协程asyncio

    1、特殊函数

    就是async关键字修饰的一个函数的定义
    特殊之处:
    	特殊函数被调用后会返回一个协程对象
    	特殊函数调用后内部的程序语句没有被立即执行
    

    2、协程

    对象:协程=特殊的函数 协程表示就是一组特定的操作
    

    3、任务对象

    高级协程(对协程进一步的封装)
    	任务对象 == 协程 == 特殊的函数
    		任务对象 == 特殊得函数
    	
    绑定回调
    	task.add_done_callback(task)
    		- 参数task:当前回调函数对应的任务对象
    		- task.result():返回的就是任务对象对应的特殊函数的返回值
    		
    

    4、事件循环对象

    - 创建事件循环对象
    - 将任务对象注册到对象中并开启该对象
    - 作用:loop可以将其内部注册的所有任务对象进行异步执行
    

    5、挂起

    挂起:就是交出cpu的使用权。
    

    重点:不支持异步模块,则会中断异步效果

    在特殊函数内部的实现中,不可以出现不支持异步的模块代码,如果出现了,
        则会中断整个的异步效果!!!
        
     requests模块不支持 使用 aiohttp模块
     time.sleep不支持 使用 await asyncio.sleep(2)
    

    示例1:协程的基础

    import asyncio
    from time import sleep
    
    #特殊的函数
    async def get_request(url):
        print('正在下载:',url)
        sleep(2)
        print('下载完毕:',url)
    
        return 'page_text'
    #回调函数的定义(普通的函数)
    def parse(task):
        #参数表示的就是任务对象  task.result()就是 get_request的返回值
        print('i am callback!!!',task.result())
    
    #特殊函数的调用 c 就是一个协程
    c = get_request('www.1.com')
    
    #创建一个任务对象
    task = asyncio.ensure_future(c)
    #给任务对象绑定一个回调函数
    task.add_done_callback(parse)
    
    #创建一个事件循环对象
    loop = asyncio.get_event_loop()
    #将任务对象注册到该对象中并且开启该对象
    loop.run_until_complete(task)#让loop执行了一个任务
    

    示例二:多任务异步爬虫

    import asyncio
    import requests
    import time
    from bs4 import BeautifulSoup
    #将被请求的url全部整合到一个列表中
    urls = ['http://127.0.0.1:5000/bobo','http://127.0.0.1:5000/jay','http://127.0.0.1:5000/tom']
    # 计算开始事件
    start = time.time()
    
    #特殊函数
    async def get_request(url):
        #requests模块不支持异步,中断了整个的异步效果
        page_text = requests.get(url).text
        return page_text
    # 回调函数 普通的函数
    def parse(task):
        page_text = task.result()
        soup = BeautifulSoup(page_text,'lxml')
        data = soup.find('div',class_="tang").text
        print(data)
        
    tasks = []
    # 循环urls 
    for url in urls:
        # 将参数带入 get_request 并执行 c就是协程
        c = get_request(url)
        # 创建一个任务对象
        task = asyncio.ensure_future(c)
        # 给任务对象绑定一个回调函数
        task.add_done_callback(parse)
        # 并将 任务对象 添加到tasks列表中
        tasks.append(task)
    # 创建一个事件循环对象
    loop = asyncio.get_event_loop()
    #将任务对象列表注册到该对象中并且开队该对象列表 当有多个对象时 假如遇见io阻塞 则必须执行完这个任务才执行下一个 所以这时候用到了 wait 挂起 遇见io阻塞则执行下一个
    loop.run_until_complete(asyncio.wait(tasks))
    # 输出总耗时
    print('总耗时:',time.time()-start)
    
    # 执行结果为 6 秒多 因为requests模块不支持异步所以 中断了异步结果  这时候需要用aiohttp模块
    

    aiohttp的用法

    # aiohttp时一个支持异步的网络请求模块
    # 环境安装
    # 编码流程
    		# 大致框架
        	with aiohttp.ClientSession() as s:
               # 代理使用方法 #s.get(url,headers,params,proxy="http://ip:port")
                    with s.get(url) as response:
                        # 二进制读取方法 requests则是用.content
                        #response.read()二进制(.content)
                        
                        # aiohttp中获取文本是方法不是属性
                        page_text = response.text()
                        return page_text
                    
                    
                    
     # 细节补充
    - 在每一个with前加上async
                - 需要在每一个阻塞操作前加上await
                    async with aiohttp.ClientSession() as s:                   #s.get(url,headers,params,proxy="http://ip:port")
                        async with await s.get(url) as response:
                            #response.read()二进制(.content)
                            page_text = await response.text()
                            return page_text
    

    示例三:基于aiohttp多任务异步爬虫

    import asyncio
    import aiohttp
    import time
    from bs4 import BeautifulSoup
    #将被请求的url全部整合到一个列表中
    urls = ['http://127.0.0.1:5000/bobo','http://127.0.0.1:5000/jay','http://127.0.0.1:5000/tom']
    # 开始事件
    start = time.time()
    
    # 特殊函数
    async def get_request(url):
        # 基于上下文管理 来使用 aiohttp 
        async with aiohttp.ClientSession() as s:
            #s.get(url,headers,params,proxy="http://ip:port")
            async with await s.get(url) as response:
                #response.read()二进制(.content)
                page_text = await response.text()
                return page_text
    # 回调函数
    def parse(task):
        # 获取 特殊函数的返回值 并赋值给page_text
        page_text = task.result()
        # 生成bs4的对象
        soup = BeautifulSoup(page_text,'lxml')
        # 获取该位置的文本
        data = soup.find('div',class_="tang").text
        # 输出该文本
        print(data)
    
    tasks = []
    # 循环urls
    for url in urls:
        # 执行特殊函数 并给了c 其实就是一个协程
        c = get_request(url)
        # 创建一个任务对象
        task = asyncio.ensure_future(c)
        # 绑定回调函数
        task.add_done_callback(parse)
        # 并将任务对象添加到列表中
        tasks.append(task)
    # 创建事件循环对象
    loop = asyncio.get_event_loop()
    #将任务对象列表注册到该对象中并且开队该对象列表 当有多个对象时 假如遇见io阻塞 则必须执行完这个任务才执行下一个 所以这时候用到了 wait 挂起 遇见io阻塞则执行下一个
    loop.run_until_complete(asyncio.wait(tasks))
    
    print('总耗时:',time.time()-start)
    # 结果为 2s多点
    
  • 相关阅读:
    获取ocx运行路径的另一种方法
    使用D3D渲染YUV视频数据
    C++(MFC)中WebBrowser去除3D边框的方法(实现IDocHostUIHandler接口)
    ActiveX控件的安全初始化和脚本操作 和 数字签名SIGN
    解决Eclipse中的卡死现象
    Http请求头和响应头
    HTTP请求头与响应头
    centos7 Mariadb5.5升级到Mariadb10.2
    window下利用navicat访问Linux下的mariadb数据库
    在Linux上安装及配置MariaDB
  • 原文地址:https://www.cnblogs.com/zhangdadayou/p/11999920.html
Copyright © 2011-2022 走看看