目录
1. 概念讲解
2. 多任务异步协程理解
3.基于aiohttp模块异步网络请求实现数据爬取及数据解析
一、需要了解的概念
特殊函数:如果async修饰了一个函数的定义,那么该函数就变成了一个特殊函数,
特殊之处:特殊函数被调用后函数内部实现语句不会被立即执行
该函数调用之后会返回一个协程对象
协程对象:特殊函数调用后可以返回一个协程对象
协程 == 特殊函数
任务对象:对协程对象的进一步封装,就是一个高级协程对象
任务对象 == 协程对象 == 特殊的函数
绑定回调:task.add_done_callback(parse) #parse就是一个回调函数
parse的定义:
parse必须又一个参数,该参数表示的就是回调函数对应的任务对象
task.result(): 就是特殊函数的的返回值
事件循环对象:可以让特殊函数内部的语句执行
该对象内部必须注册的是任务对象,当事件循环开启后其内部注册的任务对象就可以基于异步被执行
ps: 在特殊函数每部不可以出现不支持异步代码对应的模块
定义如下:
import asyncio
import time
urls = [
'http://127.0.0.1:5000/jay',
'http://127.0.0.1:5000/tom',
'http://127.0.0.1:5000/jay',
'http://127.0.0.1:5000/tom',
]
# 特殊函数
async def get_request(url):
print('正在请求:',url)
time.sleep(2)
print('请求结束;',url)
return 'bobo'
#对调函数
def parse(task): #task 该回调函数对应的任务对象
print(' I am callback')
print(task.result()) #result返回的就是特殊函数的返回值
#返回了一个协程对象
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)
二、多任务异步协程过程理解
import asyncio
import time
urls = [
'http://127.0.0.1:5000/jay',
'http://127.0.0.1:5000/tom',
'http://127.0.0.1:5000/jay',
'http://127.0.0.1:5000/tom',
]
start = time.time()
# 特殊函数
#!!!特殊函数内部不可以出现不支持异步的模块代码,如果出现了则会中断所有的异步代码
async def get_request(url):
print('正在请求:',url)
#time.sleep(2)
await asyncio.sleep(2) #await 遇到阻塞的时候需要阻塞然后再走后续代码
print('请求结束;',url)
return 'bobo'
#任务列表
tasks = []
for url in urls:
c = get_request(url) #执行特殊函数得到一个协程对象
task = asyncio.ensure_future(c) #获取任务对象
tasks.append(task)
#一个任务对象和另一个任务对象所对应的代码是异步的
#某一个对象内部的代码是串行的
# 注册的任务对象 事件循环开启
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks)) #此处的wait当任务对象遇到阻塞的时候允许挂起,把cpu的使用权交出来
print('耗时',time.time()-start)
三、基于aiohttp模块异步网络请求实现数据爬取及数据解析
1. aiphttp模块使用详解
pip install aiohttp
编码:
基本架构:
with aiohttp.ClientSession() as s: #s就是一个请求对象
with s.get(url) as response:
page_text = response.text() #read() ==> content json没变
return page_text
补充细节
在每个with前加async
在每个阻塞前加await
async with aiohttp.ClientSession() as s: #s就是一个请求对象
async with await s.get(url) as response:
page_text = await response.text() #read() ==> content json没变
return page_text
2.aioihttp使用案列及说明及数据解析
import asyncio
import time
import requests
import aiohttp
from lxml import etree
urls = [
'http://127.0.0.1:5000/jay',
'http://127.0.0.1:5000/tom',
'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
async with aiohttp.ClientSession() as s: #s就是一个请求对象
async with await s.get(url) as response: #get/post(url,data/parms,headers,proxy='http://ip:port')
page_text = await response.text() #read() ==> content json没变
return page_text
#定义回调函数
def parse(task):
page_text = task.result()
tree = etree.HTML(page_text)
print(tree.xpath('//a/text()'))
#任务列表
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)