<!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 Pool urls = [ '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)
来源:https://www.cnblogs.com/g15009428458/p/12568902.html