pycURLの単体版は結構情報あったのですが、並行リクエストするCurlMultiの情報が少なかったのでサンプル。ストリームのまま直接アーカイブに保存しています。
import pycurl
import time
import io
import tarfile
import datetime
urls = [{"url":r"https://www.yahoo.co.jp/", "key":"yahoo"},
{"url":r"https://qiita.com/", "key":"qiita"}]
TIMEOUT = 10# 10秒
mh = pycurl.CurlMulti()
reqs = []
for url in urls:
c = pycurl.Curl()
r = io.BytesIO()
c.setopt(pycurl.URL, url["url"])
c.setopt(pycurl.TRANSFERTEXT, True)
c.setopt(pycurl.WRITEDATA, r)
c.setopt(pycurl.SSL_VERIFYPEER, False)
c.setopt(pycurl.SSL_VERIFYHOST, False)
#c.setopt(c.VERBOSE, True) #デバッグ用
if TIMEOUT > 0:
c.setopt(pycurl.TIMEOUT, TIMEOUT)
c.setopt(pycurl.CONNECTTIMEOUT, TIMEOUT)
mh.add_handle(c)
reqs.append((c, r, url))
performed = False
while True:
if performed:
ret = mh.select(TIMEOUT)
if ret == -1: continue
while True:
ret, num_handles = mh.perform()
time.sleep(1)
performed = True
if ret != pycurl.E_CALL_MULTI_PERFORM: break
if num_handles == 0: break
with tarfile.open("archive.tar.xz", "w:xz") as tar:
for req in reqs:
req[1].seek(0) #これをしないとエラー
info = tarfile.TarInfo(f"{req[2]['key']}.html")
info.size = len(req[1].getbuffer())
info.mtime = datetime.datetime.now().timestamp()
tar.addfile(info, req[1])
pycURL自体がlibcurlをPythonに持ってきただけなので、同じような実装をしているPHPの情報が参考になりました。curlのオプションはPHPのページを見るといいでしょう。pycURLとほぼ一緒です。
cURL 転送用オプションを設定する - PHP.net
http://php.net/manual/ja/function.curl-setopt.php
とりあえず動くレベルのものなので、サーバーがエラー返してきたときの対応はしていません。PHPですが、以下の記事を参考にするともっと良くなると思います。
curl_multiでHTTP並行リクエストを行うサンプル
https://qiita.com/Hiraku/items/1c67b51040246efb4254
追記:環境によっては「pycurl: libcurl link-time ssl backend (nss) is different from compile-time ssl backend (openssl)」と怒られることがあります。解決法は以下の通りです。
https://qiita.com/kirishimaru/items/722776766da890fd853f
追記:結構メモリ使うので、メモリ溢れそうなら一度中間ファイルを作りましょう。