高性能异步爬虫

如何提升requests模块爬取数据的效率

  • 多进程或者多线程(不建议)
  • 线程池或者进程池(适当使用)
  • 单线程+异步协程(推荐)

示例爬取梨视频

import requests
import re
from lxml import etree
from multiprocessing.dummy import Pool
import random
headers = {
    ‘User-Agent‘:‘Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36‘
}

def request_video(url):
    return requests.get(url=url,headers=headers).content

def saveVideo(data):
    name = str(random.randint(0,9999))+‘.mp4‘
    with open(name,‘wb‘) as fp:
        fp.write(data)
        print(name,‘下载存储成功!!!‘)

url = ‘https://www.pearvideo.com/category_1‘
page_text = requests.get(url=url,headers=headers).text

tree = etree.HTML(page_text)
li_list = tree.xpath(‘//ul[@id="listvideoListUl"]/li‘)
#实例化一个线程池对象
pool = Pool(4)
video_url_list = [] #所有的视频连接
for li in li_list:
    detail_url = ‘https://www.pearvideo.com/‘+li.xpath(‘./div/a/@href‘)[0]
    detail_page_text = requests.get(url=detail_url,headers=headers).text
    ex = ‘srcUrl="(.*?)",vdoUrl=‘
    video_url = re.findall(ex,detail_page_text,re.S)[0]
    video_url_list.append(video_url)
#异步的获取4个视频的二进制数据
video_data_list = pool.map(request_video,video_url_list)

#进行视频的持久化存储
pool.map(saveVideo,video_data_list)

梨视频

单线程和异步协程

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

coroutine:中文翻译叫协程,在 Python 中常指代为协程对象类型,我们可以将协程对象注册到事件循环中,它会被事件循环调用。我们可以使用 async 关键字来定义一个方法,这个方法在调用时不会立即被执行,而是返回一个协程对象。

task:任务,它是对协程对象的进一步封装,包含了任务的各个状态。

future:代表将来执行或还没有执行的任务,实际上和 task 没有本质区别。

另外我们还需要了解 async/await 关键字,它是从 Python 3.5 才出现的,专门用于定义协程。其中,async 定义一个协程,await 用来挂起异步阻塞方法的执行。

asyncio模块基本使用

import asyncio
async def hello(name):
    print(‘hello to :‘,name)
#获取了一个协程对象
c = hello(‘bobo‘)

#创建一个事件循环对象
loop = asyncio.get_event_loop()

#将协程对象注册到事件循环中,然后启动事件循环对象
loop.run_until_complete(c)

#async 添加到函数前面,函数调用不会立即执行,而是获取一个协程对象,需要通过asyncio模块创建一个事件循环对象,再将协程对象注册到时间循环中,再启动事件循环对象

task的应用

#task的使用
import asyncio
async def hello(name):
    print(‘hello to :‘,name)

c = hello(‘bobo‘)
loop = asyncio.get_event_loop()
#就协程进行进一步的封装,封装到了task对象中
task = loop.create_task(c)
print(task)
loop.run_until_complete(task)
print(task)

#将协程封装到task对象中,再启动事件循环的时候携带task参数

future的应用

#future的使用
import asyncio
async def hello(name):
    print(‘hello to :‘,name)

c = hello(‘bobo‘)

task = asyncio.ensure_future(c)

loop.run_until_complete(task)

#future本质和task区别不大

绑定回调(task)

#绑定回调(task)
def callback(task):
    print(‘i am callback:‘,task.result())

import asyncio
async def hello(name):
    print(‘hello to :‘,name)
    return name

c = hello(‘bobo‘)

task = asyncio.ensure_future(c)
#给任务对象绑定一个回调函数
task.add_done_callback(callback)
loop.run_until_complete(task)

多任务异步协程

import asyncio
async def request(url):
    print(‘正在下载:‘,url)
#     sleep(2) #非异步模块的代码:在此处如果存在非异步操作代码,则会彻底让asyncio失去异步的效果
    await asyncio.sleep(2)
    print(‘下载成功:‘,url)
urls = [
    ‘www.baidu.com‘,
    ‘www.taobao.com‘,
    ‘www.sogou.com‘
]
start = time.time()
loop = asyncio.get_event_loop()
tasks = [] #任务列表,放置多个任务对象
for url in urls:
    c = request(url)
    task = asyncio.ensure_future(c)
    tasks.append(task)

#将多个任务对象对应的列表注册到事件循环中
loop.run_until_complete(asyncio.wait(tasks))
print(‘总耗时:‘,time.time()-start)

"""
正在下载: www.baidu.com
正在下载: www.taobao.com
正在下载: www.sogou.com
下载成功: www.baidu.com
下载成功: www.taobao.com
下载成功: www.sogou.com
总耗时: 2.0011146068573
"""

多任务异步操作应用到爬虫中

示例1 使用requests模块

import requests
async def get_page(url):
    print(‘正在下载:‘,url)
    #之所以没有实现异步操作,原因是因为requests模块是一个非异步的模块
    response = requests.get(url=url)
    print(‘响应数据:‘,response.text)
    print(‘下载成功:‘,url)
start = time.time()
urls = [
    ‘http://127.0.0.1:5000/bobo‘,
    ‘http://127.0.0.1:5000/jay‘,
    ‘http://127.0.0.1:5000/tom‘
]
tasks = []
loop = asyncio.get_event_loop()
for url in urls:
    c = get_page(url)
    task = asyncio.ensure_future(c)
    tasks.append(task)
loop.run_until_complete(asyncio.wait(tasks))
print(‘总耗时:‘,time.time()-start)

"""
正在下载: http://127.0.0.1:5000/bobo
响应数据: Hello bobo
下载成功: http://127.0.0.1:5000/bobo
正在下载: http://127.0.0.1:5000/jay
响应数据: Hello jay
下载成功: http://127.0.0.1:5000/jay
正在下载: http://127.0.0.1:5000/tom
响应数据: Hello tom
下载成功: http://127.0.0.1:5000/tom
总耗时: 6.0263447761535645
"""

支持异步的网络请求的模块 aiohttp

import aiohttp
import asyncio

async def get_page(url):
    async with aiohttp.ClientSession() as session:
        async with await session.get(url=url) as response:
            page_text = await response.text() #read()  json()
            print(page_text)
start = time.time()
urls = [
    ‘http://127.0.0.1:5000/bobo‘,
    ‘http://127.0.0.1:5000/jay‘,
    ‘http://127.0.0.1:5000/tom‘,
    ‘http://127.0.0.1:5000/bobo‘,
    ‘http://127.0.0.1:5000/jay‘,
    ‘http://127.0.0.1:5000/tom‘,
    ‘http://127.0.0.1:5000/bobo‘,
    ‘http://127.0.0.1:5000/jay‘,
    ‘http://127.0.0.1:5000/tom‘
]
tasks = []
loop = asyncio.get_event_loop()
for url in urls:
    c = get_page(url)
    task = asyncio.ensure_future(c)
    tasks.append(task)
loop.run_until_complete(asyncio.wait(tasks))
print(‘总耗时:‘,time.time()-start)

"""
Hello bobo
Hello jay
Hello tom
Hello jay
Hello bobo
Hello tom
Hello bobo
Hello tom
Hello jay
总耗时: 2.031116008758545
"""

高性能异步爬虫

如何实现数据解析---任务的绑定回调机制

#高性能异步爬虫
import aiohttp
import asyncio
#生成回调函数:解析响应数据
def callback(task):
    print("this is callback")
    #获取响应数据
    page_text = task.result()
    print(‘在回调函数中进行数据解析‘)   #在这块做数据解析操作

async def get_page(url):
    async with aiohttp.ClientSession() as session:  #返回一个session对象,with前必须加async
        async with await session.get(url=url) as response:
            page_text = await response.text()  #read()二进制形式的响应数据,json()
            #print(‘响应数据‘,page_text)
            return page_text

urls = [
    ‘http://www.baidu.com‘,
    ‘http://www.xueqiu.com‘,
    ‘http://www.taobao.com‘,
]
start = time.time()
loop = asyncio.get_event_loop()
tasks = []  #任务列表,放置多个任务对象
for url in urls:
    c = get_page(url)
    task = asyncio.ensure_future(c)
    #给任务对象绑定好回调函数用于解析响应数据
    task.add_done_callback(callback)
    tasks.append(task)
#将多个任务对象对应的列表注册到事件循环中
loop.run_until_complete(asyncio.wait(tasks))
print(‘总耗时: ‘,time.time()-start)

"""
this is callback
在回调函数中进行数据解析
this is callback
在回调函数中进行数据解析
this is callback
在回调函数中进行数据解析
总耗时:  2.252128839492798
"""

...

原文地址:https://www.cnblogs.com/CrazySheldon1/p/10818579.html

时间: 2024-11-09 09:46:43

高性能异步爬虫的相关文章

爬虫-高性能异步爬虫

异步爬虫方式 目的:在爬虫中使用异步实现高性能的数据爬取操作 异步爬虫方式: 多进程,多线程(不建议) 好处:可以为先关阻塞操作单独开启进程或者线程,阻塞操作就可以异步执行 坏处:无法无限制开启 线程池,进程池(适当使用) 好处:可以降低系统对进程或者线程创建和销毁的评率,进而降低系统开销 坏处:池中线程或进程的数量有上线 单线程+异步协程(推荐) event_loop:事件循环,相当于一个无限循环,我们可以把一些函数注册到这个事件循环上, 当满足某些条件的时候,函数就会被循环执行. corou

高性能异步爬虫02

单线程+异步协程(推荐): -asyncio的一些关键字的说明: event_loop 事件循环:程序开启一个无限循环,把一些函数注册到事件循环上,当满足事件发生的时候,调用相应的协程函数 coroutine 协程:协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象.协程对象需要注册到事件循环,由事件循环调用. task 任务:一个协程对象就是一个原生可以挂起的函数,任务则是对协程进一步封装,其中包含了任务的各种状态 async:async定义一个协

Python实现基于协程的异步爬虫

一.课程介绍 1. 课程来源 本课程核心部分来自<500 lines or less>项目,作者是来自 MongoDB 的工程师 A. Jesse Jiryu Davis 与 Python 之父 Guido van Rossum.项目代码使用 MIT 协议,项目文档使用 http://creativecommons.org/licenses/by/3.0/legalcode 协议. 课程内容在原文档基础上做了稍许修改,增加了部分原理介绍,步骤的拆解分析及源代码注释. 2. 内容简介 传统计算机

Voovan 是一个高性能异步网络框架和 HTTP(Java)

Voovan 是一个高性能异步网络框架和 HTTP 服务器框架,同时支持 HTTP 客户端抓取.动态编译支持.数据库访问封装以及 DateTime.String.Log.反射.对象工具.流操作.文件操作.异步双向通道等功能.旨在提供可靠.方便.可单元测试的代码.它是一个无任何依赖的独立工具包,希望能够方便广大开发者快速的实现应用. 作者:@愚民日记 地址:http://git.oschina.net/helyho/Voovan http://www.oschina.net/news/80909/

(转)新手写爬虫v2.5(使用代理的异步爬虫)

开始 开篇:爬代理ip v2.0(未完待续),实现了获取代理ips,并把这些代理持久化(存在本地).同时使用的是tornado的HTTPClient的库爬取内容. 中篇:开篇主要是获取代理ip:中篇打算使用代理ip,同时优化代码,并且异步爬取内容.所以接下来,就是写一个:异步,使用代理的爬虫.定义为:爬虫 v2.5 为什么使用代理 在开篇中我们爬来的代理ip怎么用? 在需要发送请求的时候,需要把请求,先发送到代理服务器(通过代理ip和端口),再由代理服务器请求目标网站.目标网站返回响应的时候也是

利用aiohttp制作异步爬虫

简介asyncio可以实现单线程并发IO操作,是Python中常用的异步处理模块.关于asyncio模块的介绍,笔者会在后续的文章中加以介绍,本文将会讲述一个基于asyncio实现的HTTP框架--aiohttp,它可以帮助我们异步地实现HTTP请求,从而使得我们的程序效率大大提高.本文将会介绍aiohttp在爬虫中的一个简单应用.在原来的项目中,我们是利用Python的爬虫框架scrapy来爬取当当网图书畅销榜的图书信息的.在本文中,笔者将会以两种方式来制作爬虫,比较同步爬虫与异步爬虫(利用a

深入理解协程(四):async/await异步爬虫实战

本文目录: 同步方式爬取博客标题 async/await异步爬取博客标题 本片为深入理解协程系列文章的补充. 你将会在从本文中了解到:async/await如何运用的实际的爬虫中. 案例 从CSDN上批量爬取指定文章的标题.文章列表如下: urls = [ 'https://blog.csdn.net/Jmilk/article/details/103218919', 'https://blog.csdn.net/stven_king/article/details/103256724', 'h

.Net中的并行编程-4.实现高性能异步队列

上文<.Net中的并行编程-3.ConcurrentQueue实现与分析>分析了ConcurrentQueue的实现,本章就基于ConcurrentQueue实现一个高性能的异步队列,该队列主要用于实时数据流的处理并简化多线程编程模型.设计该队列时考虑以下几点需求(需求来自公司的一个实际项目): 1. 支持多线程入队出队,尽量简化多线程编程的复杂度. 2. 支持事件触发机制,数据入队时才进行处理而不是使用定时处理机制, 而且内部能阻塞消费者线程. 3. 出队时数据处理的顺序要保证和入队时是一致

基于scrapy源码实现的自定义微型异步爬虫框架

一.scrapy原理 Scrapy 使用了 Twisted异步网络库来处理网络通讯.整体架构大致如下 Scrapy主要包括了以下组件: 引擎(Scrapy)用来处理整个系统的数据流处理, 触发事务(框架核心) 调度器(Scheduler)用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址 下载器(Downloader)用于下载网页内容, 并将网页内容返回给