Laden Sie die Datei in Python 3 aus dem Internet herunter

331

Ich erstelle ein Programm, das eine JAR-Datei (Java) von einem Webserver herunterlädt, indem ich die URL lese, die in der JAD-Datei desselben Spiels / derselben Anwendung angegeben ist. Ich benutze Python 3.2.1

Ich habe es geschafft, die URL der JAR-Datei aus der JAD-Datei zu extrahieren (jede JAD-Datei enthält die URL zur JAR-Datei), aber wie Sie sich vorstellen können, ist der extrahierte Wert type () string.

Hier ist die relevante Funktion:

def downloadFile(URL=None):
    import httplib2
    h = httplib2.Http(".cache")
    resp, content = h.request(URL, "GET")
    return content

downloadFile(URL_from_file)

Ich erhalte jedoch immer die Fehlermeldung, dass der Typ in der obigen Funktion Bytes und keine Zeichenfolge sein muss. Ich habe versucht, den URL.encode ('utf-8') und auch Bytes (URL, encoding = 'utf-8') zu verwenden, aber ich habe immer den gleichen oder einen ähnlichen Fehler erhalten.

Meine Frage ist also im Grunde, wie man eine Datei von einem Server herunterlädt, wenn die URL in einem Zeichenfolgentyp gespeichert ist.

Bo Milanovich
quelle
4
@alvas, Ein Kopfgeld dafür? Der Antwortende ist auf SO immer noch (und ziemlich) aktiv. Warum nicht einfach einen Kommentar hinzufügen und fragen?
Bhargav Rao
8
Denn eine gute Antwort, die den Test der Zeit dauert, ist es wert, vergeben zu werden. Wir sollten dies auch für viele andere Fragen tun, um zu prüfen, ob Antworten heute relevant sind. Besonders wenn die Sortierung von SO-Antworten ziemlich verrückt ist, geht manchmal die veraltete oder sogar schlechteste Antwort nach oben.
Alvas

Antworten:

645

Wenn Sie den Inhalt einer Webseite in eine Variable umwandeln möchten, geben Sie einfach readdie Antwort von urllib.request.urlopen:

import urllib.request
...
url = 'http://example.com/'
response = urllib.request.urlopen(url)
data = response.read()      # a `bytes` object
text = data.decode('utf-8') # a `str`; this step can't be used if data is binary

Der einfachste Weg, eine Datei herunterzuladen und zu speichern, ist die Verwendung der folgenden urllib.request.urlretrieveFunktion:

import urllib.request
...
# Download the file from `url` and save it locally under `file_name`:
urllib.request.urlretrieve(url, file_name)
import urllib.request
...
# Download the file from `url`, save it in a temporary directory and get the
# path to it (e.g. '/tmp/tmpb48zma.txt') in the `file_name` variable:
file_name, headers = urllib.request.urlretrieve(url)

Beachten Sie jedoch, dass dies urlretrieveals Vermächtnis betrachtet wird und möglicherweise veraltet ist (ich weiß jedoch nicht warum).

Der korrekteste Weg, dies zu tun, wäre die Verwendung der urllib.request.urlopenFunktion, um ein dateiähnliches Objekt zurückzugeben, das eine HTTP-Antwort darstellt, und es mit in eine echte Datei zu kopieren shutil.copyfileobj.

import urllib.request
import shutil
...
# Download the file from `url` and save it locally under `file_name`:
with urllib.request.urlopen(url) as response, open(file_name, 'wb') as out_file:
    shutil.copyfileobj(response, out_file)

Wenn dies zu kompliziert erscheint, möchten Sie möglicherweise einfacher vorgehen und den gesamten Download in einem bytesObjekt speichern und dann in eine Datei schreiben. Dies funktioniert jedoch nur für kleine Dateien.

import urllib.request
...
# Download the file from `url` and save it locally under `file_name`:
with urllib.request.urlopen(url) as response, open(file_name, 'wb') as out_file:
    data = response.read() # a `bytes` object
    out_file.write(data)

Es ist möglich, .gzkomprimierte Daten im laufenden Betrieb zu extrahieren (und möglicherweise auch in anderen Formaten), aber für einen solchen Vorgang muss der HTTP-Server wahrscheinlich den wahlfreien Zugriff auf die Datei unterstützen.

import urllib.request
import gzip
...
# Read the first 64 bytes of the file inside the .gz archive located at `url`
url = 'http://example.com/something.gz'
with urllib.request.urlopen(url) as response:
    with gzip.GzipFile(fileobj=response) as uncompressed:
        file_header = uncompressed.read(64) # a `bytes` object
        # Or do anything shown above using `uncompressed` instead of `response`.
Oleh Prypin
quelle
7
Sie könnten response.info().get_param('charset', 'utf-8')anstelle der Hardcodierung verwenden utf-8, um die Zeichencodierung aus dem Content-TypeHeader zu erhalten
jfs
2
@OlehPrypin Warum funktioniert das outfile.write(data)nur für kleine Dateien?
Startec
"urlretrieve gilt als Vermächtnis und wird möglicherweise veraltet" Woher haben Sie diese Idee?
Corey Goldberg
13
@Corey: Direkt aus den Dokumenten : "21.6.24. Legacy-Oberfläche Die folgenden Funktionen und Klassen werden vom Python 2-Modul urllib (im Gegensatz zu urllib2) portiert. Sie werden möglicherweise irgendwann in der Zukunft veraltet sein." ... und ich stimme
Olehs
@Oleh Prypin Wenn ich urllib.request.urlopen (url) als Antwort verwende, open (Dateiname, 'wb') als out_file: shutil.copyfileobj (response, out_file), wie finde ich dann den HTTP-Statuscode in der catch-Anweisung zu wissen, dass die Datei nicht gefunden wurde?
Robert Achmann
145

ich benutze requests Paket immer dann, wenn ich etwas mit HTTP-Anfragen zu tun haben möchte, da die API sehr einfach zu starten ist:

Installieren Sie zuerst requests

$ pip install requests

dann der Code:

from requests import get  # to make GET request


def download(url, file_name):
    # open in binary mode
    with open(file_name, "wb") as file:
        # get request
        response = get(url)
        # write to file
        file.write(response.content)
Ali Faki
quelle
16

Ich hoffe, ich habe die Frage richtig verstanden: Wie lade ich eine Datei von einem Server herunter, wenn die URL in einem Zeichenfolgentyp gespeichert ist?

Ich lade Dateien herunter und speichere sie lokal mit dem folgenden Code:

import requests

url = 'https://www.python.org/static/img/python-logo.png'
fileName = 'D:\Python\dwnldPythonLogo.png'
req = requests.get(url)
file = open(fileName, 'wb')
for chunk in req.iter_content(100000):
    file.write(chunk)
file.close()
Ranvijay Kumar
quelle
Hallo, ich verwende auch die gleiche Art von Code zum Herunterladen von Dateien, aber einige Zeit habe ich eine Ausnahme wie - 'Charmap'-Codec kann das Zeichen' \ u010c 'nicht codieren ..... können Sie mir dabei helfen
Joyson
10

Hier können wir die Legacy-Oberfläche von urllib in Python3 verwenden:

Die folgenden Funktionen und Klassen werden vom Python 2-Modul urllib (im Gegensatz zu urllib2) portiert. Sie könnten irgendwann in der Zukunft veraltet sein.

Beispiel (2 Zeilen Code) :

import urllib.request

url = 'https://www.python.org/static/img/python-logo.png'
urllib.request.urlretrieve(url, "logo.png")
Yang Yu
quelle
9

Sie können dafür wget verwenden, das beliebte Download-Shell-Tool. https://pypi.python.org/pypi/wget Dies ist die einfachste Methode, da die Zieldatei nicht geöffnet werden muss. Hier ist ein Beispiel.

import wget
url = 'https://i1.wp.com/python3.codes/wp-content/uploads/2015/06/Python3-powered.png?fit=650%2C350'  
wget.download(url, '/Users/scott/Downloads/cat4.jpg') 
Lasith Niroshan
quelle
0

Ja, Anfragen sind definitiv ein großartiges Paket, um sie in Bezug auf HTTP-Anfragen zu verwenden. Aber wir müssen vorsichtig mit dem Codierungstyp der eingehenden Daten sein. Ein Beispiel, das den Unterschied erklärt


from requests import get

# case when the response is byte array
url = 'some_image_url'

response = get(url)
with open('output', 'wb') as file:
    file.write(response.content)


# case when the response is text
# Here unlikely if the reponse content is of type **iso-8859-1** we will have to override the response encoding
url = 'some_page_url'

response = get(url)
# override encoding by real educated guess as provided by chardet
r.encoding = r.apparent_encoding

with open('output', 'w', encoding='utf-8') as file:
    file.write(response.content)
Kaushal
quelle
0

Motivation

Manchmal möchten wir das Bild erhalten, müssen es aber nicht in echte Dateien herunterladen.

dh laden Sie die Daten und halten Sie sie auf Speicher.

Wenn ich beispielsweise die Methode des maschinellen Lernens verwende, trainiere ein Modell, das ein Bild mit der Nummer (Strichcode) erkennen kann.

Wenn ich einige Websites spinne und diese Bilder habe, damit ich das Modell verwenden kann, um es zu erkennen,

und ich möchte diese Bilder nicht auf meinem Laufwerk speichern,

Anschließend können Sie die folgende Methode ausprobieren, um die Download-Daten im Speicher zu halten.

Punkte

import requests
from io import BytesIO
response = requests.get(url)
with BytesIO as io_obj:
    for chunk in response.iter_content(chunk_size=4096):
        io_obj.write(chunk)

Im Grunde ist wie @Ranvijay Kumar

Ein Beispiel

import requests
from typing import NewType, TypeVar
from io import StringIO, BytesIO
import matplotlib.pyplot as plt
import imageio

URL = NewType('URL', str)
T_IO = TypeVar('T_IO', StringIO, BytesIO)


def download_and_keep_on_memory(url: URL, headers=None, timeout=None, **option) -> T_IO:
    chunk_size = option.get('chunk_size', 4096)  # default 4KB
    max_size = 1024 ** 2 * option.get('max_size', -1)  # MB, default will ignore.
    response = requests.get(url, headers=headers, timeout=timeout)
    if response.status_code != 200:
        raise requests.ConnectionError(f'{response.status_code}')

    instance_io = StringIO if isinstance(next(response.iter_content(chunk_size=1)), str) else BytesIO
    io_obj = instance_io()
    cur_size = 0
    for chunk in response.iter_content(chunk_size=chunk_size):
        cur_size += chunk_size
        if 0 < max_size < cur_size:
            break
        io_obj.write(chunk)
    io_obj.seek(0)
    """ save it to real file.
    with open('temp.png', mode='wb') as out_f:
        out_f.write(io_obj.read())
    """
    return io_obj


def main():
    headers = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7',
        'Cache-Control': 'max-age=0',
        'Connection': 'keep-alive',
        'Host': 'statics.591.com.tw',
        'Upgrade-Insecure-Requests': '1',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36'
    }
    io_img = download_and_keep_on_memory(URL('http://statics.591.com.tw/tools/showPhone.php?info_data=rLsGZe4U%2FbphHOimi2PT%2FhxTPqI&type=rLEFMu4XrrpgEw'),
                                         headers,  # You may need this. Otherwise, some websites will send the 404 error to you.
                                         max_size=4)  # max loading < 4MB
    with io_img:
        plt.rc('axes.spines', top=False, bottom=False, left=False, right=False)
        plt.rc(('xtick', 'ytick'), color=(1, 1, 1, 0))  # same of plt.axis('off')
        plt.imshow(imageio.imread(io_img, as_gray=False, pilmode="RGB"))
        plt.show()


if __name__ == '__main__':
    main()
Carson
quelle
-3
from urllib import request

def get(url):
    with request.urlopen(url) as r:
        return r.read()


def download(url, file=None):
    if not file:
        file = url.split('/')[-1]
    with open(file, 'wb') as f:
        f.write(get(url))
user7726287
quelle