基于 httpx/requests 的 异步 / 多线程 切片下载

2022-06-08 15:00:34 浏览数 (1)

作者: 懒

妥妥的论文标题hhh

最近也没搞啥新的逆向

but 由于最近工作需求 要写一个切片下载的功能

之前一直写js逆向的文章 今天来个python爬虫相关的吧hhh

应用场景:几百m的文件 网站限流 100k/s

该文章主要提供交流学习使用,请勿利用其进行不当行为!

如本篇文章应该不会侵犯贵公司了吧,我不删!

如因滥用(不是解密技术了吧)技术而产生的风险与本人无关!


1、切片下载的原理

首先 不是所有的下载都可以使用切片下载的,那怎么判断

主要是通过 headers 里面一个 特别的请求头 Range 实现的

简单来说 当使用 Range 参数后 服务器返回206 则代表支持切片下载

所以接下来切片下载需要实现的基本功能就如下:

1、判断是否支持切片功能,如果支持则顺带获取文件总大小

2、按指定的切片大小创建切片任务

3、并发下载

4、合并下载

(是不是和上面截图差不多 当然 正常流程就是这样子 但是实际设计过程中还有很多坑)

所以有一些附件功能

1、失败切片任务重试

2、缓存功能

3、异步模式和多线程模式

4、...

先解释下为啥又用了 httpx 又用了 requests

其实首先开发的时候是用的 aiohttp 后来发现他不支持 https 代理

然后就想着用 httpx 的异步。。结果使用代理请求部分https网站照样报错。。搜了下说是也不支持(找不到链接了) 所以就又写了多线程 requests的方式

开始开始(以下样例就以异步模式来讲吧,比较相对来说 多线程简单点):

首先是在基类的一些公共字段(用途看注释应该就行了)

download 方法流程如下

流程分析

1、判断是否有缓存 若有的话 则加载到内存中

2、判断是否支持切片功能并获取文件大小

看到文章说 使用 head 方法判断 实际上遇到过 光head 就以及很慢了的情况

所以我是直接构造 Range 下载 100b 的内容 来判断

如果状态码为 206 就是支持的 如果为200 则是不支持切片且直接下载完成了

其余均为异常情况

3、创建切片任务

根据文件总大小 和 切片大小 来计算 同时记录切片的序号 index

4、并发下载

先生成信号量控制并发 并创建异步任务

(多线程则用 ThreadPoolExecutor 控制并发就行)

每个切片下载前 先判断下缓存文件是否已下载(启用缓存功能的情况下)不存在则下载,对每个切片请求下来的大小做校验

成功的切片加入 success_list

重试后失败的切片加入 err_list

5、处理失败的情况

根据指定的失败列表重试次数去重试下载切片 如果重试还失败 就把成功下载的切片缓存下来 下次下载时只需要下载失败的部分就行了

6、都下载成功的情况下合并切片 可以对总大小再做一次校验

8、完整调用

异步模式:20s

多线程模式:20s

普通requests.get:等了8分钟了 不想等了。。

以上测试仅是当前参数下的结果 且可能存在网络波动hhhh

到此整个流程就完成了~

一些注意事项:

1、请使用python3.7 因为 asyncio.run 貌似是3.7 的语法 或者自行修改异步的语法就好了

2、有啥bug可以联系我撒,写完也没大量测试 可能还有坑没改hhh

0 人点赞