异步爬虫
<!doctype html>
异步爬虫
基于线程池
搭建模拟网站,基于Flask框架
templates设置如下图,Flask框架只能使用jinja2进行渲染
第二步:
在templates中创建test.html
下面是python搭建Flask框架
#!/usr/bin/env python # -*- coding:utf-8 -*-
from flask import Flask,render_template
from time import sleep实例化一个app
app = Flask(name)
创建视图函数&路由地址
@app.route('/bobo')
def index_1():
sleep(2)
return render_template('test.html')@app.route('/jay')
def index_2():
sleep(2)
return render_template('test.html')@app.route('/tom')
def index_3():
sleep(2)
return render_template('test.html')
if name == "main":
#debug=True表示开启调试模式:服务器端代码被修改后按下保存键会自动重启服务
app.run(debug=True)
线程池,异步爬取网站
import requests
import time
from multiprocessing.dummy import Poolurls = [
'http://127.0.0.1:5000/bobo',
'http://127.0.0.1:5000/jay',
'http://127.0.0.1:5000/tom',
]def get_request(url):
page_text = requests.get(url=url).text
return len(page_text)异步代码
if name == "main":
start = time.time()
pool = Pool(3) #开启线程的数量
#使用get_requests作为回调函数,需要基于异步的形式对urls列表元素进行操作
result_list = pool.map(get_request, urls)
pool.map(parse, result_list) #对返回的三张源码数据进行解析
print('总耗时:',time.time()-start)
单线程+多任务异步协程:
特殊函数
async是asyncio模块特有的关键字,如果不导入,没有这个关键字
如果一个函数在定义的时候被async修饰后,则该函数就变成了一个特殊的函数
特殊之处:
该特殊函数被调用后,函数内部实现语句不会立即执行
该特殊函数被调用后会立即返回一个协程对象
协程对象
对象。通过特殊函数的调用返回一个协程对象
协程 == 特殊函数 == 实现内容
协程 == 实现内容
任务对象
任务对象就是通过协程对象的封装
任务 == 实现内容
任务对象的高级之处:
- 可以给任务对象绑定回调,绑定方式task.add_done_callback(task_callback)
- 绑定的回调函数是在任务执行之后才执行回调函数的,并且回调函数的参数是任务对象
- 回调函数的参数只可以有一个
- 使用回电函数的参数调用result返回的就是任务对象表示的特殊函数的返回值
事件循环对象
他也是一个对象
作用:
- 可以将多个任务对象注册/装载到事件循环对象中
- 如果开启了事件循环后,则其内部注册/装载的任务对象便是的制定操作就会被基于异步的被执行
创建方式:
loop = asyncio.ensure_future(c)
将任务对象注册到事件循环中且开启事件循环
loop.run_until_complete(task)
import requests import asyncio async def get_requests(url): print('正在请求url', url) time.sleep(2) print('请求结束', url) return 'bbbb'
def task_callback(t):
print('我是回掉函数,参数t', t)
print('t.result返回的是:', t.result()) #返回的是协程对象的返回值,也就是任务对象的返回值
if name == "main":
#c就是一个协程对象
c = get_request('www.1.com')#任务对象就是对携程对象的进一步封装 task = asyncio.get_event_loop() #任务对象绑定一个回调函数,回掉函数是在任务执行之后才执行 task.add_done_callback(task_callback) #将任务对象注册到事件循环中且开启事件循环 loop.run_until_complete(task)
多任务
import asyncio import requests
async def get_request(url):
print('正在请求url', url)
await asynico.sleep(2) #await保证我们的阻塞不被跳过
print('请求结束', url)
return 'bbbb'
urls = [
'www.1.com',
'www.2.com',
'www.3.com',
]
if name == "main":
tasks = [] #多任务列表
#1.创建协程对象
for url in urls:
c = get_requet(url)
task =asyncio.ensure_future(c)
tasks.append(task)#3创建事件循环对象 loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) #wait作用是可以将任务列表中的任务对象进行挂起操作。(每一个对象都可以被挂起)
wait方法作用:
将任务对象列表中的任务对象赋予可被挂起的权限。只有任务对象赋予了可被挂起权限后任务对象才可以被挂起
挂起:将当前的任务对象交出cpu的使用权
如果异步之中出现不支持异步模块,程序会被终止
request,time模块不支持异步
await关键字作用
在特殊函数内部,凡是阻塞操作执行前都必须使用await进行修饰。await保证我们的阻塞在异步执行过程中不被跳过
import requests import asyncio import aiohttp #支持异步的网络请求模块
async def get_request(url):
async with aiohttp.ClientSession() as sess:
#调用get发起请求,返回一个响应对象
#get/post(url, headers,params/data,proxy="字符串")
async with await sess.get(url) as response:
#获取了字符串形式的响应数据
page_text = await response.text()
return page _text
urls = [
'http://127.0.0.1:5000/bobo',
'http://127.0.0.1:5000/jay',
'http://127.0.0.1:5000/tom'
]
if name == "main":
start = time.time()
tasks = [] #多任务列表
#1.创建协程对象
for url in urls:
c = get_request(url)
#2.创建任务对象
task = asyncio.ensure_future(c)
tasks.append(task)#3.创建事件循环对象 loop = asyncio.get_event_loop() # loop.run_until_complete(tasks) #必须使用wait方法对tasks进行封装才可 loop.run_until_complete(asyncio.wait(tasks)) print('总耗时:', time.time()-start)