Pobierz zwrócony plik ZIP z adresu URL

88

Jeśli mam adres URL, który po przesłaniu w przeglądarce internetowej wyskakuje okno dialogowe do zapisania pliku zip, jak powinienem przechwycić i pobrać ten plik zip w Pythonie?

user1229108
źródło
1
Próbowałem punkt pobierania pliku binarnego i pisanie go na dysku z tej strony , która pracowała jako chram.
Zeinab Abbasimazar

Odpowiedzi:

36

Większość ludzi zaleca używanie, requestsjeśli jest dostępne, a requests dokumentacja zaleca to do pobierania i zapisywania surowych danych z adresu URL:

import requests 

def download_url(url, save_path, chunk_size=128):
    r = requests.get(url, stream=True)
    with open(save_path, 'wb') as fd:
        for chunk in r.iter_content(chunk_size=chunk_size):
            fd.write(chunk)

Ponieważ odpowiedź zawiera pytanie o pobranie i zapisanie pliku zip, nie wdałem się w szczegóły dotyczące odczytu pliku zip. Zobacz jedną z wielu odpowiedzi poniżej, aby poznać możliwości.

Jeśli z jakiegoś powodu nie masz dostępu requests, możesz użyć urllib.requestzamiast tego. Może nie być tak solidne, jak powyższe.

import urllib.request

def download_url(url, save_path):
    with urllib.request.urlopen(url) as dl_file:
        with open(save_path, 'wb') as out_file:
            out_file.write(dl_file.read())

Wreszcie, jeśli nadal używasz Pythona 2, możesz użyć urllib2.urlopen.

from contextlib import closing

def download_url(url, save_path):
    with closing(urllib2.urlopen(url)) as dl_file:
        with open(save_path, 'wb') as out_file:
            out_file.write(dl_file.read())
nadawca
źródło
Czy możesz również dodać przykładowy fragment kodu. Byłoby tak
miło z twojej strony
207

O ile wiem, właściwym sposobem na to jest:

import requests, zipfile, StringIO
r = requests.get(zip_file_url, stream=True)
z = zipfile.ZipFile(StringIO.StringIO(r.content))
z.extractall()

oczywiście chciałbyś sprawdzić, czy GET się powiódł r.ok.

W przypadku Pythona 3+, podrzędny moduł StringIO z modułem io i użyj BytesIO zamiast StringIO: Oto uwagi do wydania, które wspominają o tej zmianie.

import requests, zipfile, io
r = requests.get(zip_file_url)
z = zipfile.ZipFile(io.BytesIO(r.content))
z.extractall("/path/to/destination_directory")
yoavram
źródło
Dzięki za tę odpowiedź. Użyłem go, aby rozwiązać mój problem, otrzymując plik zip z żądaniami .
gr1zzly be4r
yoavram, w swoim kodzie - gdzie wpisuję adres URL strony internetowej?
nowyGIS
25
Jeśli chcesz zapisać pobrany plik w innym miejscu, należy wymienić z.extractall()zz.extractall("/path/to/destination_directory")
user799188
1
Jeśli tylko chcesz zapisać plik z adresu URL można zrobić: urllib.request.urlretrieve(url, filename).
yoavram,
3
Aby pomóc innym połączyć kropki, zajęło mi to 60 minut za długo, możesz użyć pd.read_table(z.open('filename'))powyższego. Przydatne, jeśli masz link zip url zawierający wiele plików i chcesz tylko załadować jeden.
Frikster
13

Z pomocą tego posta na blogu udało mi się to po prostu requests. Rzecz w tym, że dziwne streamjest to, że nie musimy wywoływać contentdużych żądań, które wymagałyby przetworzenia wszystkich na raz, zatykając pamięć. streamUnika tego przez iteracja Dane jednym kawałku na raz.

url = 'https://www2.census.gov/geo/tiger/GENZ2017/shp/cb_2017_02_tract_500k.zip'
target_path = 'alaska.zip'

response = requests.get(url, stream=True)
handle = open(target_path, "wb")
for chunk in response.iter_content(chunk_size=512):
    if chunk:  # filter out keep-alive new chunks
        handle.write(chunk)
handle.close()
Jeremiah England
źródło
2
W większości treści odpowiedzi nie powinny opierać się na linkach. Linki mogą zgasnąć lub zawartość po drugiej stronie może zostać zmieniona, aby nie odpowiadać na pytanie. Zmień swoją odpowiedź, aby zawierała podsumowanie lub wyjaśnienie informacji, do których prowadzi łącze.
mypetlion
8

Oto, co mam do pracy w Pythonie 3:

import zipfile, urllib.request, shutil

url = 'http://www....myzipfile.zip'
file_name = 'myzip.zip'

with urllib.request.urlopen(url) as response, open(file_name, 'wb') as out_file:
    shutil.copyfileobj(response, out_file)
    with zipfile.ZipFile(file_name) as zf:
        zf.extractall()
Webucator
źródło
Dzień dobry. Jak można uniknąć tego błędu urllib.error.HTTPError: HTTP Error 302: The HTTP server returned a redirect error that would lead to an infinite loop.:?
Victor M Herasme Perez
@VictorHerasmePerez, kod stanu odpowiedzi HTTP 302 oznacza, że ​​strona została przeniesiona. Myślę, że problem, przed którym
stoisz,
5

Użyj urllib2.urlopen lub możesz spróbować użyć doskonałego Requestsmodułu i uniknąć bólów głowy urllib2:

import requests
results = requests.get('url')
#pass results.content onto secondary processing...
aravenel
źródło
1
Ale jak analizować wyniki. Zawartość w zipie?
0atman
Użyj zipfilemodułu: zip = zipfile.ZipFile(results.content). Następnie wystarczy analizować poprzez pliki użyciu ZipFile.namelist(), ZipFile.open()alboZipFile.extractall()
aravenel
5

Przyszedłem tutaj, szukając, jak zapisać plik .bzip2. Wkleję kod dla innych, którzy mogą tego szukać.

url = "http://api.mywebsite.com"
filename = "swateek.tar.gz"

response = requests.get(url, headers=headers, auth=('myusername', 'mypassword'), timeout=50)
if response.status_code == 200:
with open(filename, 'wb') as f:
   f.write(response.content)

Chciałem tylko zapisać plik tak, jak jest.

swateek
źródło
3

Dzięki @yoavram za powyższe rozwiązanie, moja ścieżka URL jest połączona ze spakowanym folderem i napotykam błąd BADZipfile (plik nie jest plikiem zip) i było dziwne, gdy próbowałem kilka razy, aby pobrać adres URL i rozpakować wszystko nagle więc poprawiam nieco rozwiązanie. używając metody is_zipfile , jak tutaj

r = requests.get(url, stream =True)
check = zipfile.is_zipfile(io.BytesIO(r.content))
while not check:
    r = requests.get(url, stream =True)
    check = zipfile.is_zipfile(io.BytesIO(r.content))
else:
    z = zipfile.ZipFile(io.BytesIO(r.content))
    z.extractall()
hindamosh
źródło