单线程实现了多任务异步协程

单线程+多任务异步协程:



意义:提升爬取数据的效率,我们也可以使用线程池,

异步爬虫方式:

  • 多线程/多进程(电脑吃不消,没办法无节制开启)不建议
  • 池:池中的线程或进程也是无法任意开启.
  • 单线程+多任务异步协程(推荐)(500个协程,最优)

概念:

协程:本质就是一个对象,协程对象,怎么去获取?可以使用asynic该关键字去修饰一个函数定义,此时的函数就叫它特殊函数,当该特殊函数被调用之后,就可以返回一个协程对象,特殊之处不仅仅是返回一个协程对象,当函数内部实现的语句不会被立即执行(时间循环开启后执行),导入模块import asycio

import asyncio
#特殊函数:
async  def test(num):
        print(num)
c = test(10)
print(c)
#内部函数语句没有被执行,返回的是一个协程对象,一个地址,仅仅一个协程对象没有意义

任务对象:

  • 本质上就是对协程对象的进一步封装,封装之后也是一个协程对象,任务对象变相等于一个特殊函数.
  • 给任务对象绑定一个回调:add_done_callback(callback)时间循环执行完成后再执行回调函数.
import asyncio
#特殊函数:
async  def test(num):
        print(num)
c = test(10)
#内部函数语句没有被执行,返回的是一个协程对象,一个地址,仅仅一个协程对象没有意义

#进行封装,根据一个协程对象封装一个任务对象
task = asyncio.ensure_future(c)

绑定回调:

import asyncio
import time

async def request(url):
          print('正在请求:',url)
          time.sleep(2)
          print('请求完成':url)
          return url

#定义一个任务对象的回调函数:
#task参数就是该函数被绑定的任务对象,必须要有.
def task_callback(task):
    print('a callback')
    print(task)
    print(task.result())
#task.result()返回的是特殊函数内部的返回值.

c1 = request('www.qq.com')#协程对象
c2 = request('www.qq.com')
c3 = request('www.qq.com')
task_A = asyncio.ensure_future(c1)
task_B = asyncio.ensure_future(c2)
task_C = asyncio.ensure_future(c3)#任务对象

#绑定回调:函数请求完毕后调用
#只传回调函数的名字,没有传递参数,task就是参数,
task.add_done_callback(task_callback)

#创建时间循环对象
loop = asyncio.get_event_loop()
#将任务对象注册到事件循环对象中并且开启事件循环
loop.run_until_complete(task_A)#放协程对象会是可以的,肯定不会把协程对象直接注册到事件循环

事件循环:(eventloop)我们必须将任务对象注册到事件循环对象中,开启事件循环对象.无限的循环对象(无法确定执行次数是多少次,遇到多少次阻塞).

事件循环开启之后,a,b,c都开始循环执行,都会有阻塞,如果单线程的话,会耗时,事件循环是异步核心,事件循环对象执行任务对象是基于异步的,执行a对象的发现阻塞时,挂起阻塞对象,开始同时执行b,b遇到阻塞时也会执行c,但是此时当a阻塞完毕时,他会直接去执行a,等a处理完成后再去执行c.(a被执行了两次,所以跟任务对象个数无关)

import asyncio
import time

async def request(url):
          print('正在请求:',url)
          time.sleep(2)
          print('请求完成':url)

c1 = request('www.qq.com')#协程对象
c2 = request('www.qq.com')
c3 = request('www.qq.com')
task_A = asyncio.ensure_future(c1)
task_B = asyncio.ensure_future(c2)
task_C = asyncio.ensure_future(c3)#任务对象

#创建事件循环对象
loop = asyncio.get_event_loop()
#将任务对象注册到时间循环对象中并且开启事件循环
loop.run_until_complete(task_A)#放协程对象会是可以的,肯定不会把协程对象直接注册到事件循环

关键字:

await:

当前阻塞时,交出cpu的控制权,就挂起.

注意事项:

  • 特殊函数内部不可以出现不支持异步的模块代码
  • 特殊函数内部遇到阻塞操作时,必须使用await对其进行手动挂起.
  • 如果想要将多个任务注册到事件循环中,必须将多个任务对象装进一个列表中,必须使用wait方法将列表中的任务进行挂起.

多任务异步协程对象:

import asyncio
import time

#在特殊函数内部不可以出现不支持异步模块相关的代码.time模块不支持异步,
async def request(url):
          print('正在请求:',url)
          #time.sleep(2)
          #阻塞之后挂起,手动的设置
          await asyncio.sleep(2)
          print('请求完成':url)
          return url
urls = [
    'www.goo.com',
    'www.sss.com',
    'www.sss.com',
    'www.sss.com',
]

def task_callback(task):
    print(task.result())

tasks = []
for url in urls:
    c = request(url)
    task = asyncio.ensure_future(cc)
    task.add_done_callback(task_callback)
    task.append(task)#装进一个列表内

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))#将任务列表中的任务对象进行挂起操作
    

requests模块不支持异步,从而我们引入支持异步的模块aiohttp

aiohttp模块:支持异步网络请求模块,pip install aiohttp

import asyncio
import time
import aiohttp
start = time.time()

#在特殊函数内部不可以出现不支持异步模块相关的代码
#简单的框架:在此基础上补充细节
async def request(url):
        with aiohttp.ClientSession() as s:
            #s.get/post和requests中的get/post用法几乎一样:url,headers,data/params
            #在s.get中如果使用代理操作:proxy = 'http://ip:port'
            with s.get(url) as response:
                #获取字符串类型的响应数据:response.text()
                #获取byte类型:response.read()
                page_text = response.text()
                return page_text
#细节1:在每一个with前加上async关键字
#细节2:在get方法前和response.text()前加上await关键字进行手动挂起操作

#真实代码:
async def request(url):
    async with aiohttp.ClientSession() as s:
       async with await s.get(url) as response:
        page_text = await response.text()
        return page_text
urls = []
for i in range(500):
    urls.append('https://127.0.0.1:5000/bobo')

def parse(task):
    page_text = task.result()
    print(page_text+',请求数据')

tasks =[]
for url in urls:
    c = 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案例:

import aiohttp
import asyncio
from lxml import etree

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}

async def request(url):
    async with aiohttp.ClientSession() as s:
        async with await s.get(url,headers=headers) as response:
            page_text = await response.text()
            return page_text

urls = []
all_titles = []
url = 'http://wz.sun0769.com/index.php/question/reply?page=%d'
for page in range(10):
    u_page = page*30
    new_url = format(url%u_page)
    urls.append(new_url)

def parse(task):
    page_text = task.result()#page_text
    tree = etree.HTML(page_text)
    tr_list = tree.xpath('/html/body/div[4]/table[2]//tr')
    for tr in tr_list:
        title = tr.xpath('./td[2]/a[1]/text()')[0]
        print(title)
        all_titles.append(title)

tasks = []
for url in urls:
    c = 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))

    

async:

selenium基本使用:

概念:基于浏览器自动化的模块.

selenium和爬虫之间的关联:很便捷的捕获动态加载的数据,实现模拟登陆,登陆成功之后可以将页面的爬取.

使用环境:

pip install selenium

下载一个浏览器的驱动程序

创建一个浏览器对象

from  selenium import webdriver

bro = webdriver.Chrome(executable_path = 'chromedriver.exe')#驱动程序路径

#发起指定url请求
bro.get('http:www.baidu.com')

#再搜索框中搜索

#可以使用find系列方法标签定位
bro.find_element_by_xpath('//*[@id="key"]')

#向搜索框中写入商品名称
search_input.send_keys('iphone')
sleep(2)
btn = bro.find_element_by_xpath('//*[@id="search"]/div/div[2]/button')

btn.click()
sleep(2)

bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
sleep(2)
bro.execute_script('window.scrollTo(0,-document.body.scrollHeight)')
page_text = bro.page_source
with open('./jd.html','w',encoding='utf-8')as p:
    p.write(page_text)
#关闭浏览器
bro.quit()

动作链:

如果想要触发一系列的连续的行为动作.actionchains

from selenium import webdriver
from selenium.webdriver import ActionChains #动作连
from time import sleep

bro = webdriver.Chrome(executable_path='chromedriver.exe')
bro.get('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')

#定位要拖动的标签
#定位的标签是存在于iframe的子页面中,如果直接使用find做定位,是定位不到的
# target_ele = bro.find_element_by_id('draggable')

#像定位iframe中子页面中的标签必须进行如下操作
bro.switch_to.frame('iframeResult')
target_ele = bro.find_element_by_id('draggable')

#基于动作连实现滑动操作
action = ActionChains(bro)
#点击且长按
action.click_and_hold(target_ele)

for i in range(5):
    #perform()表示立即执行动作连指定好的动作
    action.move_by_offset(17,0).perform()
    sleep(0.5)

action.release()

sleep(4)

bro.quit()

原文地址:https://www.cnblogs.com/Zhao159461/p/11310834.html

时间: 2024-10-09 15:43:22

单线程实现了多任务异步协程的相关文章

爬虫第四章 单线程+多任务异步协程

单线程+多任务异步协程: asyncio 事件循环 loop: 无限循环的对象,事件循环中最终需要将一些特殊的函数注册到该事件循环中 特殊的函数: 被ansyc关键字修饰的函数 协程: 本质上是一个对象,可以把协程对象注册到事件循环中, 任务对象:就是对协程对象进一步的封装. 绑定回调函数(即在执行完特殊函数之后执行这个回调函数):task.add_done_callback(func) - func(task) :task 参数表示的就是绑定的任务对象 - task.result() 返回的就

单线程多任务异步协程

目录  1. 概念讲解 2. 多任务异步协程理解 3.基于aiohttp模块异步网络请求实现数据爬取及数据解析 一.需要了解的概念 特殊函数:如果async修饰了一个函数的定义,那么该函数就变成了一个特殊函数, 特殊之处:特殊函数被调用后函数内部实现语句不会被立即执行 该函数调用之后会返回一个协程对象 协程对象:特殊函数调用后可以返回一个协程对象 协程 == 特殊函数 任务对象:对协程对象的进一步封装,就是一个高级协程对象 任务对象 == 协程对象 == 特殊的函数 绑定回调:task.add_

python爬虫--多任务异步协程, 快点,在快点......

多任务异步协程asyncio 特殊函数: - 就是async关键字修饰的一个函数的定义 - 特殊之处: - 特殊函数被调用后会返回一个协程对象 - 特殊函数调用后内部的程序语句没有被立即执行 - 协程 - 对象.协程==特殊的函数.协程表示的就是一组特定的操作. - 任务对象 - 高级的协程(对协程的进一步的封装) - 任务对象==协程==特殊的函数 - 任务对象==特殊的函数 - 绑定回调: - task.add_done_callback(task) - 参数task:当前回调函数对应的任务

多任务异步协程,asyncio及aiohttp

要实现异步协程,需要满足几个条件: 1,创建协程对象,且协程内部操作需要支持异步. 2,创建任务对象,如需为协程执行结果进行进一步处理,则需要为任务对象绑定回调函数. 3,创建事件循环,并将任务启动. 1 import asyncio 2 import requests 3 from lxml import etree 4 import aiohttp 5 import os 6 7 headers = { 8 9 'User-Agent': 'Mozilla/5.0 (Windows NT 1

单线程+异步协程

event_loop:事件循环,相当于一个无限循环(不清楚循环多少次),我们可以把一些特殊函数注册(放置)到这个事件循环上,当满足某些条件的时候,函数就会被循环执行.程序是按照设定的顺序从头执行到尾,运行的次数也是完全按照设定.当在编写异步程序时,必然其中有部分程序的运行耗时是比较久的,需要先让出当前程序的控制权,让其在背后(挂起)运行,让另一部分的程序先运行起来.当背后运行的程序完成后,也需要及时通知主程序已经完成任务可以进行下一步操作,但这个过程所需的时间是不确定的,需要主程序不断的监听状态

爬虫 + 数据分析 - 4 异步协程, selenium使用, 自动登录

一.单线程+异步协程 1.基本概念: event_loop:事件循环,相当于一个无限循环,我们可以把一些特殊函数注册(放置)到这个事件循环上, 当满足某些条件的时候,函数就会被循环执行.程序是按照设定的顺序从头执行到尾,运行的次数也是完全按照设定. 当在编写异步程序时,必然其中有部分程序的运行耗时是比较久的,需要先让出当前程序的控制权,让其在背后运行, 让另一部分的程序先运行起来.当背后运行的程序完成后,也需要及时通知主程序已经完成任务可以进行下一步操作, 但这个过程所需的时间是不确定的,需要主

06爬虫-异步协程

1. 前言(目的就是大大提升爬虫效率) 在执行IO密集型任务的时候,代码常常遇到IO操作而等待.例如我们在爬虫的时候,用到requests请求的时候,网页响应慢,一直等待着,那么爬虫的效率会大大的降低. 为了解决这类问题,本文就来探讨一下 Python 中异步协程来加速的方法,此种方法对于 IO 密集型任务非常有效.如将其应用到网络爬虫中,爬取效率甚至可以成百倍地提升. 注:本文协程使用 async/await 来实现,需要 Python 3.5 及以上版本. 2. 基本了解 在了解异步协程之前

爬虫速度太慢?来试试用异步协程提速吧!

1. 前言 在执行一些 IO 密集型任务的时候,程序常常会因为等待 IO 而阻塞.比如在网络爬虫中,如果我们使用 requests 库来进行请求的话,如果网站响应速度过慢,程序一直在等待网站响应,最后导致其爬取效率是非常非常低的. 为了解决这类问题,本文就来探讨一下 Python 中异步协程来加速的方法,此种方法对于 IO 密集型任务非常有效.如将其应用到网络爬虫中,爬取效率甚至可以成百倍地提升. 注:本文协程使用 async/await 来实现,需要 Python 3.5 及以上版本. 2.

(zt)Lua的多任务机制——协程(coroutine)

原帖:http://blog.csdn.net/soloist/article/details/329381 并发是现实世界的本质特征,而聪明的计算机科学家用来模拟并发的技术手段便是多任务机制.大致上有这么两种多任务技术,一种是抢占式多任务(preemptive multitasking),它让操作系统来决定何时执行哪个任务.另外一种就是协作式多任务(cooperative multitasking),它把决定权交给任务,让它们在自己认为合适的时候自愿放弃执行.这两种多任务方式各有优缺点,前者固