python asyncio aiohttp 异步下载 完整例子

asyncio 基础:python asyncio 协程

之前完整的说明了并发下载例子: 并发下载

使用了aiohttp,

注意, 下面写文件没有使用异步写入.一般情况下可以配合ThreadPoolExecutor来结合写入文件 : 关于aiohttp下载大文件的方式

import os,sys,time,asyncio,aiohttp
import tqdm
FLAGS = ('CN IN US ID BR PK NG BD RU JP ' 
         'MX PH VN ET EG DE IR TR CD FR').split()
BASE_URL = 'http://flupy.org/data/flags'        #下载url
DEST_DIR = 'downloads/'                           #保存目录
#获取链接,下载文件
async def fetch(session:aiohttp.ClientSession,url:str,path:str,flag:str):
    print(flag, ' 开始下载')
    async with session.get(url) as resp:
        with open(path,'wb') as fd:
            while 1:
                chunk = await resp.content.read(1024)    #每次获取1024字节
                if not chunk:
                    break
                fd.write(chunk)
    return flag

async def begin_download(sem,session:aiohttp.ClientSession,url:str,path:str,flag:str):
    #控制协程并发数量
    with (await sem):
        return await fetch(session,url,path,flag)

async def download(sem:asyncio.Semaphore):
    tasks = []
    async with aiohttp.ClientSession() as session:
        for flag in FLAGS:
            #创建路径以及url
            path = os.path.join(DEST_DIR, flag.lower() + '.gif')
            url = '{}/{cc}/{cc}.gif'.format(BASE_URL, cc=flag.lower())
            #构造一个协程列表
            tasks.append(asyncio.ensure_future(begin_download(sem,session, url, path, flag)))
        #等待返回结果
        tasks_iter = asyncio.as_completed(tasks)
        #创建一个进度条
        fk_task_iter = tqdm.tqdm(tasks_iter,total=len(FLAGS))
        for coroutine in fk_task_iter:
            #获取结果
            res = await coroutine
            print(res, '下载完成')

#创建目录
os.makedirs(DEST_DIR,exist_ok=True)
#获取事件循环
lp = asyncio.get_event_loop()
start = time.time()
#创建一个信号量以防止DDos
sem = asyncio.Semaphore(4)
lp.run_until_complete(download(sem))
end = time.time()
lp.close()
print('耗时:',end-start)

 

在写文件那块代码可以使用 run_in_executor 这个函数执行,事件循环中包含一个默认的线程池(ThreadPoolExecutor).

run_in_executor(executorfunc*args) 原型 . executor == None, 使用默认的. 可以自己创建一个;

具体代码:

#线程运行的函数
def save_file(fd:io.BufferedWriter,chunk):
    fd.write(chunk)
#获取链接,下载文件
async def fetch(session:aiohttp.ClientSession,url:str,path:str,flag:str):
    print(flag, ' 开始下载')
    async with session.get(url) as resp:
        with open(path,'wb') as fd:
            while 1:
                chunk = await resp.content.read(8192)
                if not chunk:
                    break
                lp = asyncio.get_event_loop()
                lp.run_in_executor(None,save_file,fd,chunk)
                # fd.write(chunk)
    return flag

 

你可能感兴趣的:(py)