爬虫提高效率方式
提高效率的方式
- 线程池
- map(func,alist)
 
- 多任务的异步协程
- asyncio
- 特殊的函数
- 协程
- 任务对象
- 任务对象绑定
 
- 事件循环
 
 
- 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():返回的就是任务对象对应的特殊函数的返回值
 
 
- task.add_done_callback(task)
 
- 高级的协程(对协程的进一步的封装)
- 
事件循环对象 - 创建事件循环对象
- 将任务对象注册到该对象中并且开启该对象
- 作用: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

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号