asyncio+aiohttp异步爬虫
概念
进程:进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。进程是操作系统动态执行的基本单元。
线程:一个进程中包含若干线程,当然至少有一个线程,线程可以利用进程所拥有的资源。线程是独立运行和独立调度的基本单元。
协程:协程是一种用户态的轻量级线程。协程无需线程上下文切换的开销,也无需原子操作锁定及同步的开销。
同步:不同程序单元为了完成某个任务,在执行过程中需靠某种通信方式以协调一致,称这些程序单元是同步执行的。
异步:为完成某个任务,不同程序单元之间过程中无需通信协调,也能完成任务的方式,不相关的程序单元之间可以是异步的。
多进程:多进程就是利用 CPU 的多核优势,在同一时间并行地执行多个任务。多进程模式优点就是稳定性高,因为一个子进程崩溃了,不会影响主进程和其他子进程,但是操作系统能同时运行的进程数是有限的。
多线程:多线程模式通常比多进程快一点,但是也快不到哪去,而且,多线程模式致命的缺点就是任何一个线程挂掉都可能直接造成整个进程崩溃,因为所有线程共享进程的内存。
Python 中使用协程最常用的库莫过于asyncio
,然后我们还需要了解一些概念:
event_loop 事件循环
程序开启一个无限循环,把一些函数注册到事件循环上,当满足事件发生的时候,调用相应的协程函数
coroutine 协程
协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环,由事件循环调用。
task 任务
一个协程对象就是一个原生可以挂起的函数,任务则是对协程进一步封装,其中包含了任务的各种状态
future
代表将来执行或没有执行的任务的结果。它和task上没有本质上的区别
async/await 关键字
python3.5用于定义协程的关键字,async定义一个协程,await用于挂起阻塞的异步调用接口。
不知道为什么我一看概念这些东西,讲的简单点的还好,一长就容易走神…所以这里只是简单复制粘贴了下
Python手册中关于asyncio的部分
aiohttp手册
很多网上教的例子都在手册上有了,所以直接看手册就行,下面就来根据实例理解理解吧
实例
这个是我爬取站酷网上“潇湘过客莫念”的雪中悍刀行的插图,如下所示,通过最基本的requests
抓取图片链接,没有遇到反爬
get_content
是返回访问图片地址的content数据;downloader
是将图片保存到本地的方法;run
是提取目标图片链接并循环访问,并且记录整个过程的耗时
import time
import requestsdef get_content(link):r = requests.get(link)content = r.contentreturn contentdef downloader(img):content = get_content(img[1])with open('D:\\MY\\雪中\\lists2\\' + str(img[0]) + '.jpg', 'wb') as f:f.write(content)print('下载成功!' + str(img[0]))def run():start = time.time() # 记录起始时间戳base_url = 'https://www.zcool.com.cn/work/content/show?p=2&objectId=6455837'r = requests.get(base_url)image_list = r.json()['data']['allImageList']for i, image in enumerate(image_list):downloader((i, image['url']))end = time.time() # 获取结束时间戳print('共运行了{}秒'.format(end - start)) # 程序耗时if __name__ == '__main__':run()
运行结果:共运行了99.09104537963867
秒
接着我们来看看通过asyncio+aiohttp的方法的异步爬取,同样的,代码分成三个部分(代码在Python3.6环境运行)
import asyncio
import time
import aiohttp
import requestsasync def get_content(link):async with aiohttp.ClientSession() as session:response = await session.get(link)content = await response.read()return contentasync def downloader(img):content = await get_content(img[1])with open('D:\\MY\\雪中\\lists1\\' + str(img[0]) + '.jpg', 'wb') as f:f.write(content)print('下载成功!' + str(img[0]))def run():start = time.time() # 记录起始时间戳base_url = 'https://www.zcool.com.cn/work/content/show?p=2&objectId=6455837'r = requests.get(base_url)image_list = r.json()['data']['allImageList']loop = asyncio.get_event_loop()tasks = [asyncio.ensure_future(downloader((i, image['url']))) for i, image in enumerate(image_list)]loop.run_until_complete(asyncio.wait(tasks))end = time.time() # 获取结束时间戳print('共运行了{}秒'.format(end - start)) # 程序耗时if __name__ == '__main__':run()
运行结果:共运行了56.29711127281189
秒,跟上面的同步代码比较,节省了一半左右的时间,这里的每张图片大小在几M
那么我们来看看代码是如何执行的
这里需要注意的是run
方法中增加了loop = asyncio.get_event_loop()
,就是创建一个event_loop
事件循环,这个事件循环叫loop
,然后我们要做的就是把协程
放到loop事件循环
中,协程对象不能直接运行,在注册事件循环的时候,其实是run_until_complete(coroutine)
方法将协程包装成为了一个任务task
对象,task
对象是Future
类的子类,保存了协程运行后的状态,用于未来获取协程的结果
那么哪来的协程
呢?这里以async
关键字定义的方法就是一个协程
,这个方法在调用时不会立即被执行,而是返回一个协程对象,协程对象需要注册到事件循环,由事件循环调用
tasks = [asyncio.ensure_future(downloader((i, image['url']))) for i, image in enumerate(image_list)]
这行代码的作用实际上就是通过循环生成多个downloader
协程,传入一个元组类型的参数,这个元祖中包含两个参数,然后通过asyncio.ensure_future()
方法返回task
任务(一个协程对象就是一个原生可以挂起的函数,任务则是对协程进一步封装,其中包含了任务的各种状态,通过asyncio.ensure_future(coroutine)
创建task
,同样的可以通过loop.create_task(coroutine)
创建task
),最终得到一个tasks
任务列表
loop.run_until_complete(asyncio.wait(tasks))
而这行代码说实话我没有深入的理解,就大概理解为事件循环执行run_until_complete
方法,等到其中的每一个可等待对象都执行完毕,对于其中的每一个对象,去执行downloader协程
,运行到await get_content(img[1])
时挂起当前的协程,去执行get_content()
这个协程,引用了aiohttp
里的ClientSession
类,建立 了一个session
对象,通过session.get()
得到response
以及最后的content
并最终返回content
然后继续执行downloader
中的保存图片部分
以上就是用asyncio+aiohttp的简单的异步爬虫实例,很明显相较于一般的爬虫能节省很多时间啦
参考
* asyncio.wait如何理解
asyncio.wait实现的异步
* python中重要的模块–asyncio
* 【Python3爬虫】使用异步协程编写爬虫
asyncio+aiohttp异步爬虫相关推荐
- 第17讲:aiohttp 异步爬虫实战
在上一课时我们介绍了异步爬虫的基本原理和 asyncio 的基本用法,另外在最后简单提及了 aiohttp 实现网页爬取的过程,这一可是我们来介绍一下 aiohttp 的常见用法,以及通过一个实战案例 ...
- asyncio+aiohttp异步免费代理池(已失效)
asyncio+aiohttp异步代理池 程序已失效,因为免费代理可用率实在太低,就不维护了. 异步代理池 github地址 初级版本代理池 博客地址 经历了好几天时间,终于将asyncio初步了解, ...
- Python使用asyncio+aiohttp异步爬取猫眼电影专业版
asyncio是从pytohn3.4开始添加到标准库中的一个强大的异步并发库,可以很好地解决python中高并发的问题,入门学习可以参考官方文档 并发访问能极大的提高爬虫的性能,但是requests访 ...
- 【Python aiohttp异步爬虫】批量爬取电脑壁纸
寒假在家,实在无事可做,就找到了崔庆才爬虫52讲的课程,巩固一下爬虫知识,最近也是学到了异步爬虫,本来想按照视频教的案例实践一下就可以了,没想到案例网站证书过期了,没办法进行实践,只能去找别的网站实践 ...
- Python异步爬虫技术:10秒抓取3000条房源信息!
本文先熟悉并发与并行.阻塞与非阻塞.同步与异步.多线程.多线程.协程的基本概念.再实现asyncio + aiohttp爬取链家成都二手房源信息的异步爬虫,爬取效率与多线程版进行简单测试和比较. 1. ...
- Python爬取链家成都二手房源信息,异步爬虫实战项目!
本文先熟悉并发与并行.阻塞与非阻塞.同步与异步.多线程.多线程.协程的基本概念.再实现asyncio + aiohttp爬取链家成都二手房源信息的异步爬虫,爬取效率与多线程版进行简单测试和比较. 1. ...
- python爬虫 asyncio aiohttp aiofiles 单线程多任务异步协程爬取图片
python爬虫 asyncio aiohttp aiofiles 多任务异步协程爬取图片 main.py """=== coding: UTF8 ==="&q ...
- 异步爬虫-aiohttp库、Twisted库简介
为什么要用异步爬虫? 爬虫本质上就是模拟客户端与服务端的通讯过程.以浏览器端的爬虫为例,我们在爬取不同网页过程中,需要根据url构建很多HTTP请求去爬取,而如果以单个线程为参考对象,平常我们所采取 ...
- 异步爬虫模块aiohttp实战之infoq
点击上方蓝字关注 异步爬虫模块aiohttp实战之infoq 之前写过很多的关于异步的文章,介绍了asyncio的使用,大多的只是通过简单的例子说明了asyncio的使用,但是没有拿出具体的使用例子, ...
最新文章
- ATS 5.3.0中parent.config配置文件解读
- Python学习笔记——常量和变量
- 【mysql】二级索引----聚簇索引和非聚簇索引-----
- 行转列:SQL SERVER PIVOT与用法解释
- MongoDB副本集、分片集的伪分布式部署(保姆级教程)
- 简述python定义中的五个要点_Python基础知识复习
- qt判断读入的字符串是否含有英文_重复的子字符串
- Android菜鸟成长记1--环境的搭配和第一个项目的构建
- php7 捕获语法错误,PHP7 method_exists未捕获错误:函数名称必须是字符串
- c语言 sd卡编程,嵌入式系统基础 嵌入式系统中的C语言编程基础 烧写Superboot到SD卡.docx...
- python爬贴吧回复内容_Python爬虫_获取贴吧内容
- 攻防世界mobile新手区之app3 write up
- 程序员写代码也存在本手、妙手、俗手
- OSPF-1.ospf基础及工作流程
- 2018中南大学 计算机考研分数,中南大学2018年硕士研究生招生复试基本分数线
- QT开发代码格式化设置
- python 离散数学 判断单射 双射 满射
- 中企海外周报 | 哈弗F7x性能版在俄罗斯上市;徐工首家海外银行落户巴西
- 重磅!上海出落户新政:双一流应届硕士可直接落户!
- KSQL DB 学习笔记2