< a href="https://github.com/%E5%B0%8F%E7%9A%AE%E6%B5%A9"> Fork me on GitHub

异步爬虫

<!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(&#39;总耗时:&#39;, time.time()-start)

 

posted @ 2020-03-25 19:40  赌徒!  阅读(607)  评论(0编辑  收藏  举报