Jak pobrać duży plik w Pythonie z requests.py?
Requests to naprawdę fajna biblioteka. Chciałbym go użyć do pobierania dużych plików (>1GB). Problem w tym, że nie da się utrzymać całego pliku w pamięci, muszę go odczytać w kawałkach. I jest to problem z następującym kodem
import requests
def DownloadFile(url)
local_filename = url.split('/')[-1]
r = requests.get(url)
f = open(local_filename, 'wb')
for chunk in r.iter_content(chunk_size=512 * 1024):
if chunk: # filter out keep-alive new chunks
f.write(chunk)
f.close()
return
Z jakiegoś powodu to nie działa w ten sposób. Nadal ładuje odpowiedź do pamięci przed zapisaniem jej do pliku.
UPDATE
Jeśli potrzebujesz małego klienta (Python 2.x / 3.x) które mogą pobierać duże pliki z FTP, można znaleźć to tutaj . Obsługuje wielowątkowość i ponowne połączenia (monitoruje połączenia), a także dostraja paramy gniazd do zadania pobierania.
4 answers
Wymyśliłem, co należy zmienić. Sztuczka polegała na ustawieniu stream = True
w metodzie get()
.
Po tym, jak proces Pythona przestał ssać pamięć (pozostaje około 30kb niezależnie od rozmiaru pobranego pliku).
Dziękuję @danodonovan za składnię używam go tutaj:
def download_file(url):
local_filename = url.split('/')[-1]
# NOTE the stream=True parameter
r = requests.get(url, stream=True)
with open(local_filename, 'wb') as f:
for chunk in r.iter_content(chunk_size=1024):
if chunk: # filter out keep-alive new chunks
f.write(chunk)
#f.flush() commented by recommendation from J.F.Sebastian
return local_filename
Zobacz http://docs.python-requests.org/en/latest/user/advanced/#body-content-workflow w celach informacyjnych.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-30 13:32:43
Jest znacznie łatwiejsze, jeśli używasz Response.raw
oraz shutil.copyfileobj()
:
import requests
import shutil
def download_file(url):
local_filename = url.split('/')[-1]
r = requests.get(url, stream=True)
with open(local_filename, 'wb') as f:
shutil.copyfileobj(r.raw, f)
return local_filename
Spowoduje to Przesyłanie pliku na dysk bez użycia nadmiernej pamięci, a kod jest prosty.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-30 02:13:18
Twój rozmiar kawałka może być zbyt duży, próbowałeś to upuścić-może 1024 bajty na raz? (możesz też użyć with
do uporządkowania składni)
def DownloadFile(url):
local_filename = url.split('/')[-1]
r = requests.get(url)
with open(local_filename, 'wb') as f:
for chunk in r.iter_content(chunk_size=1024):
if chunk: # filter out keep-alive new chunks
f.write(chunk)
return
Nawiasem mówiąc, jak wnioskujesz, że odpowiedź została załadowana do pamięci?
Brzmi to tak, jakby python nie spłukiwał danych do pliku, z innych więc pytania można spróbować f.flush()
i os.fsync()
wymusić zapis pliku i wolną pamięć;
with open(local_filename, 'wb') as f:
for chunk in r.iter_content(chunk_size=1024):
if chunk: # filter out keep-alive new chunks
f.write(chunk)
f.flush()
os.fsync(f.fileno())
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:30
Nie do końca o co prosiła OP, ale... śmiesznie łatwo to zrobić z urllib
:
from urllib.request import urlretrieve
url = 'http://mirror.pnl.gov/releases/16.04.2/ubuntu-16.04.2-desktop-amd64.iso'
dst = 'ubuntu-16.04.2-desktop-amd64.iso'
urlretrieve(url, dst)
Lub w ten sposób, jeśli chcesz zapisać go do pliku tymczasowego:
from urllib.request import urlopen
from shutil import copyfileobj
from tempfile import NamedTemporaryFile
url = 'http://mirror.pnl.gov/releases/16.04.2/ubuntu-16.04.2-desktop-amd64.iso'
with urlopen(url) as fsrc, NamedTemporaryFile(delete=False) as fdst:
copyfileobj(fsrc, fdst)
Obejrzałem proces:
watch 'ps -p 18647 -o pid,ppid,pmem,rsz,vsz,comm,args; ls -al *.iso'
I widziałem, że plik rośnie, ale zużycie pamięci pozostało na 17 MB. Coś przeoczyłem?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-15 09:14:18