爬虫提高效率方式

提高效率的方式

  • 线程池
    • map(func,alist)
  • 多任务的异步协程
    • asyncio
      • 特殊的函数
      • 协程
      • 任务对象
        • 任务对象绑定
      • 事件循环
  • from multiprocessing.dummy import Pool
  • map(func,alist):
    • 可以让func回调函数处理alist中的每一个列表元素,这个处理的过程是基于异步
特殊函数:
    - 就是async关键字修饰的一个函数的定义
    - 特殊之处:
        - 特殊函数被调用后会返回一个协程对象
        - 特殊函数调用后内部的程序语句没有被立即执行
        
- 协程
    - 对象。协程==特殊的函数。协程表示的就是一组特定的操作。
    
- 任务对象
    - 高级的协程(对协程的进一步的封装)
        - 任务对象==协程==特殊的函数
            - 任务对象==特殊的函数
    - 绑定回调:
        - task.add_done_callback(task)
            - 参数task:当前回调函数对应的任务对象
            - task.result():返回的就是任务对象对应的特殊函数的返回值
            
- 事件循环对象
    - 创建事件循环对象
    - 将任务对象注册到该对象中并且开启该对象
    - 作用:loop可以将其内部注册的所有的任务对象进行异步执行

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

await:被用做在特殊函数的内部,在被阻塞的时候
wait:给每一个任务赋予一个可被挂起的权限

#【重点】在特殊函数内部的实现中,不可以出现不支持异步的模块(例如time,requests)代码,如果出现了,则会中断整个的异步效果!!!

单线程+多任务异步协程

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

  • 特殊函数:

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

    • 对象。协程==特殊的函数。协程表示的就是一组特定的操作。
  • 任务对象

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

    • 创建事件循环对象
    • 将任务对象注册到该对象中并且开启该对象
    • 作用:loop可以将其内部注册的所有的任务对象进行异步执行
  • 挂起:就是交出cpu的使用权。

  • 【重点】在特殊函数内部的实现中,不可以出现不支持异步的模块代码,如果出现了,
    则会中断整个的异步效果!!!

  • requests一定是不支持异步

  • aiohttp是一个支持异步的网络请求模块

    • 环境安装

    • 编码流程:

      • 大致的架构:
        with aiohttp.ClientSession() as s:

        s.get(url,headers,params,proxy="http://ip:port")

        with s.get(url) as response:
        #response.read()二进制(.content)
        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

协程基础

将一个任务对象注册到 事件循环对象中 并且开启该任务对象

import asyncio
from time import sleep

#特殊的函数  步骤1
async def get_request(url):
    print('正在下载:',url)
    sleep(2)
    print('下载完毕:',url)

    return 'page_text'


#特殊函数的调用 步骤2 此时特殊函数 不远行 并将对象返回给c
c = get_request('www.1.com')

#创建一个任务对象  步骤3  高级的协程(对协程的进一步的封装) 任务对象==协程==特殊的函数
task = asyncio.ensure_future(c)

#创建一个事件循环对象 步骤4 作用:loop可以将其内部注册的所有的任务对象进行异步执行 提高效率
loop = asyncio.get_event_loop()

#将任务对象注册到该对象中并且开启该对象 步骤5
loop.run_until_complete(task)#让loop执行了一个任务


ps注册好后 这个任务对象 就可以异步了

绑定回调

绑定回调函数 可以使 任务函数执行完 自动执行回调函数

import asyncio
from time import sleep

#特殊的函数  步骤1
async def get_request(url):
    print('正在下载:',url)
    sleep(2)
    print('下载完毕:',url)

    return 'page_text'

#回调函数的定义(普通的函数) 步骤3  
def parse(task):
    #参数表示的就是任务对象  task.result():返回的就是任务对象对应的特殊函数的返回值  比如爬取到的文本数据
    print('i am callback!!!',task.result())

#特殊函数的调用 步骤2 此时特殊函数 不远行 并将对象返回给c
c = get_request('www.1.com')

#创建一个任务对象  步骤3  高级的协程(对协程的进一步的封装) 任务对象==协程==特殊的函数
task = asyncio.ensure_future(c)

#给任务对象绑定一个回调函数  步骤3 加了回调函数 parse是一个普通函数 也是回调函数
task.add_done_callback(parse)

#创建一个事件循环对象 步骤4 作用:loop可以将其内部注册的所有的任务对象进行异步执行 提高效率
loop = asyncio.get_event_loop()

#将任务对象注册到该对象中并且开启该对象 步骤5
loop.run_until_complete(task)#让loop执行了一个任务

多任务协程+回调

import asyncio
from time import sleep
import time
#特殊的函数
async def get_request(url):
    print('正在下载:',url)
    await asyncio.sleep(2) #注意
    print('下载完毕:',url)

    return 'i am page_text!!!'
def parse(task):
    page_text = task.result()#拿到任务对象返回值
    print(page_text)

start = time.time()
urls = ['www.1.com','www.2.com','www.3.com']

tasks = []#存储的是所有的任务对象。多任务!
for url in urls:
    c = get_request(url)#特殊函数的调用
    task = asyncio.ensure_future(c)#创建任务对象
    task.add_done_callback(parse)#增加回调函数
    tasks.append(task)

loop = asyncio.get_event_loop()

#asyncio.wait(tasks):给每一个任务对象赋予一个可被挂起的权限  将列表的任务对象 注册到 事件循环对象
loop.run_until_complete(asyncio.wait(tasks))

print('总耗时:',time.time()-start)

ps
在特殊函数内部的实现中,不可以出现不支持异步的模块代码,如果出现了,
则会中断整个的异步效果!!!

实践

requests 不支持异步模块

换aiohttp

  • aiohttp是一个支持异步的网络请求模块

    • 环境安装

    • 编码流程:

      • 大致的架构:
        with aiohttp.ClientSession() as s:

        s.get(url,headers,params,proxy="http://ip:port")

        with s.get(url) as response:
        #response.read()二进制(.content)
        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

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):
    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 = task.result()
    soup = BeautifulSoup(page_text,'lxml')
    data = soup.find('div',class_="tang").text
    print(data)
tasks = []
for url in urls:
    c = get_request(url)
    task = asyncio.ensure_future(c)
    task.add_done_callback(parse)
    tasks.append(task)

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

print('总耗时:',time.time()-start)

aiohttp学习

  • aiohttp是一个支持异步的网络请求模块

    • 环境安装

    • 编码流程:

      • 大致的架构:
        with aiohttp.ClientSession() as s:

        s.get(url,headers,params,proxy="http://ip:port")

        with s.get(url) as response:
        #response.read()二进制(.content)
        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

大致的架构:
with aiohttp.ClientSession() as s:
   #s.get(url,headers,params,proxy="http://ip:port")
   with s.get(url) as response:
       #response.read()二进制(.content)
       page_text = response.text()
       return page_text

补充
在每一个with前加上async
需要在每一个阻塞操作前加上await
async def get_request(url):
    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
posted @ 2020-03-04 13:06  一起奥利给  阅读(528)  评论(0编辑  收藏  举报