Python异步爬虫之协程抓取妹子图片(aiohttp、aiofiles)
目录
前言
一、什么是协程?
二、协程的优势
三、代码分析
1.引入库
2.获取所有时间线的链接
3.获取一个时间线中所有相册的链接
4.获取一个相册中所有的图片链接以及相册的名字
5.下载并保存图片
6.main函数
7.主方法
四、完整代码
前言
在爬虫的过程中,效率是一个很关键的问题,最常用的是多线程、多进程、线程池、进程池等等。这篇文章主要介绍使用协程来完成抓取妹子图片。
一、什么是协程?
协程,英文Coroutines,是一种比线程更加轻量级的存在。正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程 。最重要的是,协程不是被操作系统内核所管理,而完全是由程序所控制(也就是用户执行)。
二、协程的优势
优势就是性能得到了很大的提升,不会像线程切换那样消耗资源。协程的开销远远小于线程的开销。协程本质是单线程,在不占用更多系统资源的情况下,将IO操作进行了挂起,然后继续执行其他任务,等待IO操作完成之后,再返回原来的任务继续执行。
三、代码分析
1.引入库
import requests #同步的网络请求模块
import re #正则模块,用于提取数据
import asyncio #创建并管理事件循环的模块
import aiofiles #可异步的文件操作模块
import aiohttp #可异步的网络请求模块
import os #可调用操作系统的模块
2.获取所有时间线的链接
#定义一个同步函数,使用requests库进行请求
def get_date_list():#目标链接url='https://zhaocibaidicaiyunjian.ml/'#伪装请求头header={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36'}#发送请求r=requests.get(url=url,headers=header)#获取网页页面源代码htm=r.text#使用正则模块re解析获得时间线的链接results=re.findall('''<aside id="archives-2" class="widget widget_archive">(.*?)</aside>''',htm,re.S)date_list_str=str(re.findall('''<a href=(.*?)>.*?</a>''',str(results)))date_list=re.findall('''\\'(.*?)\\\\\\\\\'''',date_list_str)#返回一个所有时间线链接的列表return date_list
3.获取一个时间线中所有相册的链接
#判断一个时间线页面是否含有第二页(在下面的协程函数get_album_urls中调用)
def hasnext(Responsetext):if re.findall('''<a class="next page-numbers" href="(.*?)">下一页</a>''', Responsetext):nextpage = re.findall('''<a class="next page-numbers" href="(.*?)">下一页</a>''',Responsetext)[0]return nextpageelse:return None#async 定义一个协程函数,参数为一个时间线的链接
async def get_album_urls(date_url):header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36'}#创建一个上下文管理器,并创建一个可异步的session对象async with aiohttp.ClientSession() as session:#session的get()的方法与requests库中的用法一样(注:requests库中get()方法的代理参数为字典形式proxies=dict,支持http和https。而session中get()方法的代理参数为字符串,proxy=str。且仅支持http,不支持https)async with session.get(url=date_url,headers=header) as Response:#获取网页页面源代码,使用await将网络IO请求挂起,程序继续执行其他任务,等待内容返回后再跳转到此处继续执行htm=await Response.text()#使用正则提取所有相册的链接album_urls=re.findall('''<a href="(.*?)" class="more-link">继续阅读<span class="screen-reader-text">.*?</span></a>''',htm)#判断此时间线页面是否含有第二页nextpage=hasnext(htm)#如果有第二页则提取第二页所有的相册链接if nextpage:async with session.get(url=nextpage,headers=header) as Response1:htm1=await Response1.text()#列表生成器,将第二页中的所有相册链接加入到列表album_urls中[album_urls.append(album_url) for album_url in re.findall('''<a href="(.*?)" class="more-link">继续阅读<span class="screen-reader-text">.*?</span></a>''',htm1)]#返回一个时间线中所有的相册链接return album_urls
4.获取一个相册中所有的图片链接以及相册的名字
#async 定义一个协程函数,参数为一个相册链接
async def get_pic_urls_and_title(album_url):header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36'}#创建一个上下文管理器,并创建一个可异步的session对象async with aiohttp.ClientSession() as session:#session的get()的方法与requests库中的用法一样(注:requests库中get()方法的代理参数为字典形式proxies=dict,支持http和https。而session中get()方法的代理参数为字符串,proxy=str。且仅支持http,不支持https)async with session.get(url=album_url,headers=header) as Response:#获取网页页面源代码,使用await将网络IO请求挂起,程序继续执行其他任务,等待内容返回后再跳转到此处继续执行htm=await Response.text()#使用正则提取出所有的图片地址以及相册的名字pic_urls=re.findall('''<img src="(.*?)" alt=".*?" border="0" />.*?''',htm,re.S)title=re.findall('''<h1 class="entry-title">(.*?)</h1>''',htm,re.S)[0]#返回所有的图片地址以及相册的名字return pic_urls,title
5.下载并保存图片
#定义一个协程函数,参数为一个相册的所有图片地址以及相册的名字
async def download(pic_urls,title):header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36'}#为一个相册创建一个文件夹dir_name = title#判断是否有这个文件夹,有则结束,否则创建一个文件夹并将图片放入if os.path.exists(dir_name):print(dir_name + '这个图片夹已存在')return Falseelif not os.path.exists(dir_name):os.mkdir(dir_name)print(f'--------正在下载: {dir_name}--------')#对每张照片进行异步请求for pic_url in pic_urls:#图片的名字取图片的链接地址pic_name = pic_url.split('/')[-1]async with aiohttp.ClientSession() as session:async with session.get(url=pic_url, headers=header) as Response:#创建一个上下文管理器,并创建一个可异步的文件对象async with aiofiles.open(file=dir_name + '/' + pic_name, mode='wb') as f:#因为Response对象的read()和text()方法会将响应一次性全部读入内存,这会导致内存爆满,导致卡顿,影响效率。#因此采取字节流的形式,每次读取4096个字节并写入文件while True:#遇到IO阻塞的情况则挂起,等待内容返回再跳转到此处继续执行pic_stream = await Response.content.read(4096)#如果读取完毕之后,则跳出此次循环if not pic_stream:break#文件写入为IO操作,挂起后执行其他任务,写入完成后跳转到此处继续执行await f.write(pic_stream)
6.main函数
#定义一个协程函数,参数为一个时间线链接
async def main(date_url):#获取一个时间线中所有的相册链接,使用await进行挂起操作(因为此处get_album_urls为一个协程对象,并且内部有IO等待)album_urls=await get_album_urls(date_url)#获取每个相册中的相册名字以及所有图片地址for album_url in album_urls:#获取一个相册中的所有图片地址以及相册名字,使用await进行挂起操作(因为此处get_pic_urls_and_title为一个协程对象,并且内部有IO等待)pic_urls,title=await get_pic_urls_and_title(album_url)#下载一个相册,使用await进行挂起操作(因为此处download为一个协程对象,并且内部有IO等待)await download(pic_urls,title)
7.主方法
if __name__=="__main__":#创建一个任务列表tasks=[]#使用同步获取所有时间线的地址(因为后面的所有的操作都基于获取到的时间线链接,所以使用同步操作将所有链接获取完毕后再进行接下来的操作)date_list=get_date_list()#为每个时间线链接都创建为一个任务对象for date_url in date_list:#此处不是立即执行main函数,而是创建了一个协程对象task=main(date_url)#将任务添加到任务列表中tasks.append(task)#创建一个事件循环,用户接收信息(接收某个任务的状态,未执行?,执行中?,执行完毕?)loop=asyncio.get_event_loop()#此处是真正执行任务,等待所有任务执行结束(可以认为是一种固定的写法)loop.run_until_complete(asyncio.wait(tasks))#所有任务执行完毕后关闭事件循环,释放资源loop.close()
四、完整代码
import requests #同步的网络请求模块
import re #正则模块,用于提取数据
import asyncio #创建并管理事件循环的模块
import aiofiles #可异步的文件操作模块
import aiohttp #可异步的网络请求模块
import os #可调用操作系统的模块#定义一个同步函数,使用requests库进行请求
def get_date_list():#目标链接url='https://zhaocibaidicaiyunjian.ml/'#伪装请求头header={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36'}#发送请求r=requests.get(url=url,headers=header)#获取网页页面源代码htm=r.text#使用正则模块re解析获得时间线的链接results=re.findall('''<aside id="archives-2" class="widget widget_archive">(.*?)</aside>''',htm,re.S)date_list_str=str(re.findall('''<a href=(.*?)>.*?</a>''',str(results)))date_list=re.findall('''\\'(.*?)\\\\\\\\\'''',date_list_str)#返回一个所有时间线链接的列表return date_list#判断一个时间线页面是否含有第二页(在下面的协程函数get_album_urls中调用)
def hasnext(Responsetext):if re.findall('''<a class="next page-numbers" href="(.*?)">下一页</a>''', Responsetext):nextpage = re.findall('''<a class="next page-numbers" href="(.*?)">下一页</a>''',Responsetext)[0]return nextpageelse:return None#async 定义一个协程函数,参数为一个时间线的链接
async def get_album_urls(date_url):header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36'}#创建一个上下文管理器,并创建一个可异步的session对象async with aiohttp.ClientSession() as session:#session的get()的方法与requests库中的用法一样(注:requests库中get()方法的代理参数为字典形式proxies=dict,支持http和https。而session中get()方法的代理参数为字符串,proxy=str。且仅支持http,不支持https)async with session.get(url=date_url,headers=header) as Response:#获取网页页面源代码,使用await将网络IO请求挂起,程序继续执行其他任务,等待内容返回后再跳转到此处继续执行htm=await Response.text()#使用正则提取所有相册的链接album_urls=re.findall('''<a href="(.*?)" class="more-link">继续阅读<span class="screen-reader-text">.*?</span></a>''',htm)#判断此时间线页面是否含有第二页nextpage=hasnext(htm)#如果有第二页则提取第二页所有的相册链接if nextpage:async with session.get(url=nextpage,headers=header) as Response1:htm1=await Response1.text()#列表生成器,将第二页中的所有相册链接加入到列表album_urls中[album_urls.append(album_url) for album_url in re.findall('''<a href="(.*?)" class="more-link">继续阅读<span class="screen-reader-text">.*?</span></a>''',htm1)]#返回一个时间线中所有的相册链接return album_urls#async 定义一个协程函数,参数为一个相册链接
async def get_pic_urls_and_title(album_url):header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36'}#创建一个上下文管理器,并创建一个可异步的session对象async with aiohttp.ClientSession() as session:#session的get()的方法与requests库中的用法一样(注:requests库中get()方法的代理参数为字典形式proxies=dict,支持http和https。而session中get()方法的代理参数为字符串,proxy=str。且仅支持http,不支持https)async with session.get(url=album_url,headers=header) as Response:#获取网页页面源代码,使用await将网络IO请求挂起,程序继续执行其他任务,等待内容返回后再跳转到此处继续执行htm=await Response.text()#使用正则提取出所有的图片地址以及相册的名字pic_urls=re.findall('''<img src="(.*?)" alt=".*?" border="0" />.*?''',htm,re.S)title=re.findall('''<h1 class="entry-title">(.*?)</h1>''',htm,re.S)[0]#返回所有的图片地址以及相册的名字return pic_urls,title#定义一个协程函数,参数为一个相册的所有图片地址以及相册的名字
async def download(pic_urls,title):header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36'}#为一个相册创建一个文件夹dir_name = title#判断是否有这个文件夹,有则结束,否则创建一个文件夹并将图片放入if os.path.exists(dir_name):print(dir_name + '这个图片夹已存在')return Falseelif not os.path.exists(dir_name):os.mkdir(dir_name)print(f'--------正在下载: {dir_name}--------')#对每张照片进行异步请求for pic_url in pic_urls:#图片的名字取图片的链接地址pic_name = pic_url.split('/')[-1]async with aiohttp.ClientSession() as session:async with session.get(url=pic_url, headers=header) as Response:#创建一个上下文管理器,并创建一个可异步的文件对象async with aiofiles.open(file=dir_name + '/' + pic_name, mode='wb') as f:#因为Response对象的read()和text()方法会将响应一次性全部读入内存,这会导致内存爆满,导致卡顿,影响效率。#因此采取字节流的形式,每次读取4096个字节并写入文件while True:#遇到IO阻塞的情况则挂起,等待内容返回再跳转到此处继续执行pic_stream = await Response.content.read(4096)#如果读取完毕之后,则跳出此次循环if not pic_stream:break#文件写入为IO操作,挂起后执行其他任务,写入完成后跳转到此处继续执行await f.write(pic_stream)#定义一个协程函数,参数为一个时间线链接
async def main(date_url):#获取一个时间线中所有的相册链接,使用await进行挂起操作(因为此处get_album_urls为一个协程对象,并且内部有IO等待)album_urls=await get_album_urls(date_url)#获取每个相册中的相册名字以及所有图片地址for album_url in album_urls:#获取一个相册中的所有图片地址以及相册名字,使用await进行挂起操作(因为此处get_pic_urls_and_title为一个协程对象,并且内部有IO等待)pic_urls,title=await get_pic_urls_and_title(album_url)#下载一个相册,使用await进行挂起操作(因为此处download为一个协程对象,并且内部有IO等待)await download(pic_urls,title)if __name__=="__main__":#创建一个任务列表tasks=[]#使用同步获取所有时间线的地址(因为后面的所有的操作都基于获取到的时间线链接,所以使用同步操作将所有链接获取完毕后再进行接下来的操作)date_list=get_date_list()#为每个时间线链接都创建为一个任务对象for date_url in date_list:#此处不是立即执行main函数,而是创建了一个协程对象task=main(date_url)#将任务添加到任务列表中tasks.append(task)#创建一个事件循环,用户接收信息(接收某个任务的状态,未执行?,执行中?,执行完毕?)loop=asyncio.get_event_loop()#此处是真正执行任务,等待所有任务执行结束(可以认为是一种固定的写法)loop.run_until_complete(asyncio.wait(tasks))#所有任务执行完毕后关闭事件循环,释放资源loop.close()
Python异步爬虫之协程抓取妹子图片(aiohttp、aiofiles)相关推荐
- python从网址爬图片协程_Python爬虫多任务协程爬取虎牙MM图片
查看: 4420|回复: 241 [作品展示] Python爬虫多任务协程爬取虎牙MM图片 电梯直达 发表于 2019-4-17 21:35:47 | 只看该作者 |倒序浏览 |阅读模式 马上注册,结 ...
- python从网址爬图片协程_python 用 gevent 协程抓取海量网页
python作为爬虫利器,抓网页的方式简洁明了.爬成百上千的网页,都可以很快爬完,但是如果网页数量上万呢?速度就不能忍受了. 这是一段爬取页面的函数,用了requests库:1 2 3 4 5impo ...
- Python 异步 IO 、协程、asyncio、async/await、aiohttp
From :廖雪峰 异步IO :https://www.liaoxuefeng.com/wiki/1016959663602400/1017959540289152 Python Async/Awai ...
- Python小爬虫之协程爬虫快速上手
文章目录 前言 协程 协程快速上手 协程异步运行 工作流程 任务管理 aiohttp 异步保存 异步回调 前言 爬虫是个好东西,最近要用用这玩意,所以顺便把以前的小东西给发出来,水几篇博客~ 协程 首 ...
- python 异步编程:协程与 asyncio
文章目录 一.协程(coroutine) 1.1 协程的概念 1.2 实现协程的方式 二.asyncio 异步编程 2.1 事件循环 2.2 快速上手 2.3 运行协程 2.4 await 关键字 2 ...
- Python开源爬虫项目代码:抓取淘宝、京东、QQ、知网数据--转
数据来源:数据挖掘入门与实战 公众号: datadw scrapy_jingdong[9]- 京东爬虫.基于scrapy的京东网站爬虫,保存格式为csv.[9]: https://github.co ...
- Python开发爬虫之动态网页抓取篇:爬取博客评论数据——通过浏览器审查元素解析真实网页地址...
由于主流网站都使用JavaScript展示网页内容,和前面简单抓取静态网页不同的是,在使用JavaScript时,很多内容并不会出现在HTML源代码中,而是在HTML源码位置放上一段JavaScrip ...
- Python 异步编程之——协程
1.总则 多进程可以实现真正的并行,但进程间无法进行直接通信且占用资源较多.多线程的使用代价相对多进程较小,但为了解决数据安全问题引入了锁的机制.这又使得多线程并发度降低,同时,使用锁还可能造成死锁. ...
- Python新手爬虫,简单制作抓取廖雪峰教程的小爬虫
先看几张对比图,分别是官网截图和抓取下来的 txt文档的截图,不算那难看的排版的话,内容是一致的,图片用 url替换了! 在整个抓取过程中,除了普通的文本以外,还需要处理 3个地方,分别是:代码.图片 ...
最新文章
- MySQL 8.0 Invisible Indexes 和 RDS 5.6 Invisible Indexes介绍
- unity3d发布linux版本_微软发布 Linux 版本 Microsoft Defender ATP,并计划将其引入 Android 等移动端...
- php 表单处理,用PHP提交from表单的处理方法
- 设计模式复习-备忘录模式
- 计算机应用基础操作题教学考试,电大教学全国计算机应用基础考试网考内容全部操作题.doc...
- cocos2dx build_native.sh clean 命令报错的解决
- python abc
- 阿里面试官居然问我如何设计一个本地缓存
- python处理xps文件_自学WPF--第二十四课XPS文件处理
- PS_BaseUse_红眼擦拭
- 曹晋睿 受邀担任第七届少儿模特明星盛典亲善大使
- Rsync-同步备份服务器脚本
- 苹果首批ARKit应用展示 或随iOS 11一起亮相
- pear php库,PEARX-不依赖 PEAR 的 PEAR 的 PHP 库
- chrome和Chromium有什么区别
- 无心剑英汉双语诗005.《浮生若云》
- 在纯粹虚拟空间萌发的种子,刚刚萌芽 就要面临夭折
- 2022年华东师范大学计科考研复试机试题-详细题解
- SAP SMARTFORMS 打印机配置 SPAD
- 2018-03-29-阿里菜鸟面试(电面一)
热门文章
- error: cannot pull with rebase: Your index contains uncommitted changes.
- Python-Excel 零基础学习xlwings,看这篇文章就够了
- Sahi 使用技巧4-iframe、下载文件、模态框、访问不了网页的处理
- 荣耀VNXP 5G天团全员正式出道,Play4系列空降“走花路”
- atop用法_atop学习
- error: failed to push some refs to ... 就这篇,一定帮你解决
- Boring counting
- svg地球昼夜交替动画js特效
- BUG监测平台,Sentry 集成全过程。
- VIjos 晴天小猪历险记之Number (搜索+链表hash)