from
concurrent.futures
import
ThreadPoolExecutor, as_completed
import
requests
from
itertools
import
tee
from
alive_progress
import
alive_bar
def
pairwise(iterable):
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
):
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:
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)