基于Python实现类似于IDM多线程下载的效果

Python
技之树 2022-12-3

1332 0

开头

优点:多线程下载

缺点:仅支持单文件,且支持断点续传。

源码

from concurrent.futures import ThreadPoolExecutor, as_completed
import requests
from itertools import tee
from alive_progress import alive_bar

def pairwise(iterable):
    '''转换'''
    # pairwise('ABCDEFG') --> AB BC CD DE EF FG
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)

def calc_divisional_range(res,threads_count):
    '''分区下载'''
    capacity = int(res.headers['Content-Length'])
    remainder = int(capacity%threads_count)
    singular = int((capacity - remainder)/threads_count)
    url_range = list(pairwise((range(0,[/b][b]capacity - remainder[/b][b],singular))))
    url_range[-1] = (url_range[-1][0],[/b][b]capacity -1[/b][b])
    return url_range

def range_download(url,save_name, s_pos, e_pos,proxies=None):
    '''下载函数'''
    headers = {"Range": f"bytes={s_pos}-{e_pos}"}
    res = requests.get(url, headers=headers, stream=True,proxies=proxies)
    with open(save_name, "rb+") as f:
        f.seek(s_pos)
        for chunk in res.iter_content(chunk_size=64*1024):
            if chunk:
                f.write(chunk)

def download(url,thread_count,save_name=None,proxies=None):
    '''多线程调用下载'''
    # url,thread_count = 'http://yue.cmvideo.cn:8080/depository_yqv/asset/zhengshi/5102/598/709/5102598709/media/5102598709_5010999563_56.mp4',16
    if save_name is None:
        save_name = url.split('/')[-1]
    print(save_name,'下载中……')
    res = requests.head(url,proxies=proxies)
    divisional_ranges = calc_divisional_range(res,thread_count)
    with open(save_name, "wb") as f:
        pass
    with ThreadPoolExecutor(max_workers=thread_count) as p,alive_bar(len(divisional_ranges)+1) as bar:
        futures = []
        for s_pos, e_pos in divisional_ranges:
            # print(s_pos, e_pos)
            futures.append(p.submit(range_download,url,save_name, s_pos, e_pos,proxies=proxies))
        # 等待所有任务执行完毕
        for f in as_completed(futures):
            if f.done():
                bar()
    print(save_name,'下载完成!')

if __name__ == '__main__':
    url = input('输入下载链接:')
    thread_count = 16
    download(url,thread_count)

参考资料:1

这家伙太懒了,什么也没留下。
最新回复 (0)
    • YiOVE论坛
      2
         
返回