指定された URL をファイルに保存し、複数のスレッドを使用してダウンロードする Python スクリプトを次に示します。
#!/usr/bin/env python
import sys
from functools import partial
from itertools import count, izip
from multiprocessing.dummy import Pool # use threads
from urllib2 import HTTPError, Request, urlopen
def download_chunk(url, byterange):
req = Request(url, headers=dict(Range='bytes=%d-%d' % byterange))
try:
return urlopen(req).read()
except HTTPError as e:
return b'' if e.code == 416 else None # treat range error as EOF
except EnvironmentError:
return None
def main():
url, filename = sys.argv[1:]
pool = Pool(4) # define number of concurrent connections
chunksize = 1 << 16
ranges = izip(count(0, chunksize), count(chunksize - 1, chunksize))
with open(filename, 'wb') as file:
for s in pool.imap(partial(download_part, url), ranges):
if not s:
break # error or EOF
file.write(s)
if len(s) != chunksize:
break # EOF (servers with no Range support end up here)
if __name__ == "__main__":
main()
サーバーが空の本文または 416 http コードを返す場合、または応答サイズがchunksize
正確でない場合、ファイルの終わりが検出されます。
ヘッダーを理解しないサーバーをサポートしますRange
(この場合、すべてが単一の要求でダウンロードされます。大きなファイルをサポートするdownload_chunk()
には、一時ファイルに保存するように変更し、ファイルの内容自体ではなく、メイン スレッドで読み取られるようにファイル名を返します。 )。
同時接続数 (プール サイズ) と単一の http 要求で要求されるバイト数を個別に変更できます。
スレッドの代わりに複数のプロセスを使用するには、インポートを変更します。
from multiprocessing.pool import Pool # use processes (other code unchanged)