吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2340|回复: 17
收起左侧

[Python 转载] 【入门异步编程第一天】图片同步异步批量下载对比

[复制链接]
话痨司机啊 发表于 2022-6-11 20:23
本帖最后由 话痨司机啊 于 2022-6-12 13:40 编辑

兄弟萌,我切菜手切坏了,打个字都费劲,给点赞吧。最近上班忙,抽空看看异步,觉得好强大,当然底层的话这个就是消息循环调用。

同步与异步耗时对比:
只是测了50张的图片,耗时对比竟然就高达近 15 秒,如果是百万张,可想差距有多大,如果是多线程,量小差距不大。
11.jpg

上代码!!


异步代码:
[Python] 纯文本查看 复制代码
import aiohttp
import asyncio
import os
import aiofiles
from loguru import logger as logs
from fake_useragent import UserAgent
from tqdm import tqdm
import time

logs.add('download_pic.log',level='INFO',format="{time:YYYY-MM-DD HH:mm:ss} {level} {message}",enqueue=True,encoding='utf-8',backtrace=True)

async def mkdir(path):
    '''
    创建文件夹
    '''
    if not os.path.exists(path):
        os.makedirs(path)


async def request(url,sem, img=False):
    '''
    请求url,返回响应
    '''
    headers = {'User-Agent':UserAgent().random,'Referer':'https://photo.ihansen.org'}
    async with aiohttp.ClientSession(headers=headers) as session:
        async with sem:
            async with session.get(url,verify_ssl=False) as response:
                assert response.status == 200
                if img == True:
                    return await response.read()
                else:
                    return await response.json(encoding='utf8')
                
async def save_image(res,path,sem):
    '''
    保存图片
    '''
    async with sem:
        async with aiofiles.open(path,'wb') as f:
            await f.write(res)

async def get_json_info(sem,start_page,end_page):
    """
    获取图片下载列表信息并下载
    """

    url = lambda num:'https://api.ihansen.org/img/detail?page={num}&perPage=50&index=&orderBy=today'.format(num=num)
    task = [request(url(i),sem,img=False) for i in range(start_page,end_page+1)]
    return await asyncio.gather(*task)

async def get_img_content_and_downloads(sem,urls):
    """
    获取图片内容
    """
    base_dir = os.path.normpath(os.path.dirname(__file__) + '/img')
    futures = [asyncio.ensure_future(request(url,sem,img=True)) for url in urls]
    contents =  [await i for i in tqdm(asyncio.as_completed(futures),total=len(futures),desc='正在下载图片')]
    await asyncio.create_task(mkdir(base_dir))
    #异步保存图片
    task = [save_image(content,os.path.join(base_dir,str(i) + '.jpg'),sem) for i,content in enumerate(contents)]
    await asyncio.gather(*task)    
        
async def async_main():
    """
    异步函数逻辑    
    """
    now = lambda:time.time()
    start = now()
    start_page = int(input('请输入起始页:'))
    end_page = int(input('请输入结束页:'))
    # 规定异步信号量为10,数值太大可能会被封IP一段时间
    sem = asyncio.Semaphore(10)
    try:
        # 获取图片下载列表信息
        json_list = await get_json_info(sem,start_page,end_page)
        # 生成图片链接urls
        url_list = []
        print('正在获取图片链接...')
        for urls in [json_info for json_info in json_list]:
            for url in urls:
                url_list.append(url.get('raw'))
        await get_img_content_and_downloads(sem,url_list)
        logs.info(f'从第{start_page}页到第{end_page}页下载耗时:{now()-start}')
    except Exception as e:
        logs.exception(e)
    
if __name__ == '__main__':
    asyncio.get_event_loop().run_until_complete(async_main())


同步代码:


[Python] 纯文本查看 复制代码
from asyncio import constants
import requests
import os
from loguru import logger as logs
from fake_useragent import UserAgent
from alive_progress import alive_bar
import time
from urllib3 import disable_warnings

disable_warnings()

logs.add('download_sync_pic.log',level='INFO',format="{time:YYYY-MM-DD HH:mm:ss} {level} {message}",encoding='utf-8')


def mkdir(path):
    '''
    创建文件夹
    '''
    if not os.path.exists(path):
        os.makedirs(path)
        
        
def get_html(url,img=False,bar=None):
    '''
    请求url,获取response
    '''
    headers = {'User-Agent':UserAgent().random,'Referer':'https://photo.ihansen.org'}
    res = requests.get(url,headers=headers,verify=False)
    assert res.status_code == 200
    if img == True:
        bar()
        return res.content
    else:
        return res.json()

def save_img(res,path):
    '''
    保存图片
    '''
    with open(path,'wb') as f:
        f.write(res)
        
        
def get_json_info(start_page,end_page):
    '''
    返回json信息
    '''
    url = lambda num:'https://api.ihansen.org/img/detail?page={num}&perPage=50&index=&orderBy=today'.format(num=num)
    return [get_html(url(i),img=False) for i in range(start_page,end_page+1)]


def get_img_info(urls):
    '''
    保存图片
    '''
    base_dir = os.path.normpath(os.path.dirname(__file__) + '/sync_img')
    mkdir(base_dir)
    with alive_bar(len(urls)) as bar:
        [save_img(content,os.path.join(base_dir,str(i) + '.jpg')) for i,content in enumerate([get_html(url,img=True,bar=bar) for url in urls])]
    
def main():
    '''
    主函数
    '''
    now = lambda:time.time()
    start = now()
    start_page = int(input('请输入起始页:'))
    end_page = int(input('请输入结束页:'))
    json_list = get_json_info(start_page,end_page)
    url_list = []
    for urls in [json_info for json_info in json_list]:
            for url in urls:
                url_list.append(url.get('raw'))
    get_img_info(url_list)  
    logs.info(f'从第{start_page}页到第{end_page}页下载耗时:{now()-start}')
    
if __name__ == "__main__":
    main()


免费评分

参与人数 5吾爱币 +5 热心值 +5 收起 理由
riverskywrorld + 1 + 1 我很赞同!
ghell + 1 + 1 我也准备把爬虫改成异步,初步试了一下,跑到3-5个并发就到极限了,不过每.
yjn866y + 1 + 1 我很赞同!
woyucheng + 1 + 1 谢谢@Thanks!
Zeaf + 1 + 1 用心讨论,共获提升!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 话痨司机啊 发表于 2022-6-11 20:29
本帖最后由 话痨司机啊 于 2022-6-12 12:33 编辑

从原理上解决了gather问题,更新代码,50张图片只用了6秒多一点!
 楼主| 话痨司机啊 发表于 2022-6-12 12:27
逝去的初夏 发表于 2022-6-12 09:57
这第一天我就有好多看不懂的语法了,楼主看的哪里的教程啊,感觉挺好的

B站上,还有python源码,又更新了源码,比之前效率又提高了~
helloword121 发表于 2022-6-11 22:44
oclassic 发表于 2022-6-11 23:17
照着写一遍,自己搞一个
大大泡泡糖121 发表于 2022-6-11 23:26
python是个好东西,谢谢分享!
狂侠先森 发表于 2022-6-12 03:51
谢谢分享 支持了
你是我的人 发表于 2022-6-12 08:16
感谢楼主分享
sssguo 发表于 2022-6-12 08:19
感谢分享!!
hnwang 发表于 2022-6-12 08:31
感谢分享。
逝去的初夏 发表于 2022-6-12 09:57
这第一天我就有好多看不懂的语法了,楼主看的哪里的教程啊,感觉挺好的
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-22 07:20

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表