Python-Äquivalent eines bestimmten wget-Befehls


76

Ich versuche, eine Python-Funktion zu erstellen, die dasselbe tut wie dieser wget-Befehl:

wget -c --read-timeout=5 --tries=0 "$URL"

-c - Fahren Sie dort fort, wo Sie aufgehört haben, wenn der Download unterbrochen wird.

--read-timeout=5- Wenn länger als 5 Sekunden keine neuen Daten eingehen, geben Sie auf und versuchen Sie es erneut. In -cdiesem Sinne wird es erneut versuchen, wo es aufgehört hat.

--tries=0 - Versuchen Sie es für immer.

Diese drei im Tandem verwendeten Argumente führen zu einem Download, der nicht fehlschlagen kann.

Ich möchte diese Funktionen in meinem Python-Skript duplizieren, weiß aber nicht, wo ich anfangen soll ...


3
Nein, der Download kann aus vielen Gründen fehlschlagen, aber ja. Haben Sie sich das Anforderungsmodul angesehen ?
Iguananaut

@Iguananaut Es sollte beachtet werden, dass Downloads absichtlich mit Strg + c unterbrochen werden können, jedenfalls mit dem Befehlszeilen-Wget-Tool (ich glaube, dies ist die Standardmethode, um sie in Wget anzuhalten und wgetb -c the_URLzum Fortsetzen zu verwenden). Siehe ubuntuforums.org/showthread.php?t=991864
Brōtsyorfuzthrāx

Antworten:


34

urllib.request sollte funktionieren. Richten Sie es einfach in einer while-Schleife (nicht erledigt) ein und prüfen Sie, ob bereits eine lokale Datei vorhanden ist. Wenn ein GET mit einem RANGE-Header gesendet wird, geben Sie an, wie weit Sie beim Herunterladen der lokalen Datei gekommen sind. Stellen Sie sicher, dass Sie read () verwenden, um an die lokale Datei anzuhängen, bis ein Fehler auftritt.

Dies ist möglicherweise auch ein Duplikat des Downloads von Python urllib2-Lebensläufen, das nicht funktioniert, wenn das Netzwerk erneut verbunden wird


Wenn ich es versuche urllib.request.urlopenoder urllib.request.Requestmit einer Zeichenfolge, die die URL als URL-Argument enthält, erhalte ichValueError: unknown url type
Ecko

2
@XamuelDvorak Geben Sie tatsächlich eine URL ein? Eine URL erfordert die Art, zum Beispiel http://, ftp://.
Eugene K

Ich habe 'stackoverflow.com' verwendet, das in meinem Browser nichts dergleichen vor sich hat.
Ecko

Es zeigt dies jedoch für andere Websites. Ich werde Ihre Lösung versuchen
Ecko

98

Es gibt auch ein schönes Python-Modul namens wget, das ziemlich einfach zu bedienen ist. Gefunden hier .

Dies zeigt die Einfachheit des Designs:

>>> import wget
>>> url = 'http://www.futurecrew.com/skaven/song_files/mp3/razorback.mp3'
>>> filename = wget.download(url)
100% [................................................] 3841532 / 3841532>
>> filename
'razorback.mp3'

Genießen.

Wenn dies wgetjedoch nicht funktioniert (ich hatte Probleme mit bestimmten PDF-Dateien), versuchen Sie diese Lösung .

Bearbeiten: Sie können den outParameter auch verwenden , um ein benutzerdefiniertes Ausgabeverzeichnis anstelle des aktuellen Arbeitsverzeichnisses zu verwenden.

>>> output_directory = <directory_name>
>>> filename = wget.download(url, out=output_directory)
>>> filename
'razorback.mp3'

3
Entschuldigung für die verspätete Antwort, diese Benachrichtigung wurde aus irgendeinem Grund nicht angezeigt. Sie müssen pip install wgethöchstwahrscheinlich.
Blairg23

1
@AshishKarpe Wenn Sie unter Ubuntu sind, versuchen Sie es mit sudo apt-get install python3-wget.
Brōtsyorfuzthrāx

1
@Shule Das ist ein wirklich guter Punkt, den ich erst bemerkt habe, als du ihn angesprochen hast. Ich habe mit diesem wgetPython-Modul überhaupt nicht mit dem continue-Parameter gespielt , aber hier ist die Quelle, wenn Sie es überprüfen möchten: bitbucket.org/techtonik/python-wget
Blairg23

1
wgetkommt mit sehr wenigen Optionen und scheint nicht beibehalten zu werden. requestsist in jeder Hinsicht überlegen.
Imrek

1
@ Blairg23 Währenddessen sagt das Python-Wget-Paket ausdrücklich, dass es keine Optionen sind, die mit dem ursprünglichen wgetDienstprogramm kompatibel sind . Zu Ihrer Information, Sie können nicht einmal den User-Agent-Header setzen, oder?
Imrek

21
import urllib2
import time

max_attempts = 80
attempts = 0
sleeptime = 10 #in seconds, no reason to continuously try if network is down

#while true: #Possibly Dangerous
while attempts < max_attempts:
    time.sleep(sleeptime)
    try:
        response = urllib2.urlopen("http://example.com", timeout = 5)
        content = response.read()
        f = open( "local/index.html", 'w' )
        f.write( content )
        f.close()
        break
    except urllib2.URLError as e:
        attempts += 1
        print type(e)

Kein -cÄquivalent hier. Lädt die Datei einfach dreimal herunter.
Phani Rithvij

18

Ich musste so etwas unter einer Linux-Version machen, bei der nicht die richtigen Optionen in wget kompiliert waren. In diesem Beispiel wird das Speicheranalysetool 'guppy' heruntergeladen. Ich bin nicht sicher, ob es wichtig ist oder nicht, aber ich habe den Namen der Zieldatei mit dem Namen des URL-Ziels identisch gehalten ...

Folgendes habe ich mir ausgedacht:

python -c "import requests; r = requests.get('https://pypi.python.org/packages/source/g/guppy/guppy-0.1.10.tar.gz') ; open('guppy-0.1.10.tar.gz' , 'wb').write(r.content)"

Das ist der Einzeiler, hier ist es etwas lesbarer:

import requests
fname = 'guppy-0.1.10.tar.gz'
url = 'https://pypi.python.org/packages/source/g/guppy/' + fname
r = requests.get(url)
open(fname , 'wb').write(r.content)

Dies funktionierte zum Herunterladen eines Tarballs. Ich konnte das Paket extrahieren und nach dem Herunterladen herunterladen.

BEARBEITEN:

Um eine Frage zu beantworten, finden Sie hier eine Implementierung mit einem Fortschrittsbalken, der in STDOUT gedruckt wird. Es gibt wahrscheinlich eine tragbarere Möglichkeit, dies ohne das clintPaket zu tun , aber dies wurde auf meinem Computer getestet und funktioniert einwandfrei:

#!/usr/bin/env python

from clint.textui import progress
import requests

fname = 'guppy-0.1.10.tar.gz'
url = 'https://pypi.python.org/packages/source/g/guppy/' + fname

r = requests.get(url, stream=True)
with open(fname, 'wb') as f:
    total_length = int(r.headers.get('content-length'))
    for chunk in progress.bar(r.iter_content(chunk_size=1024), expected_size=(total_length/1024) + 1): 
        if chunk:
            f.write(chunk)
            f.flush()

14

Eine Lösung, die ich oft einfacher und robuster finde, besteht darin, einfach einen Terminalbefehl in Python auszuführen. In deinem Fall:

import os
url = 'https://www.someurl.com'
os.system(f"""wget -c --read-timeout=5 --tries=0 "{url}"""")

5
Wenn ich eine Ablehnung bekomme, insbesondere für einen völlig anderen Ansatz, möchte ich wissen, warum. Möchtest du das erklären?
Yohan Obadia

1
Es sieht so aus, als ob die Argumente für os.system nicht ordnungsgemäß maskiert wurden. Eins "zu viele am Ende. Außerdem funktioniert es unter Windows nicht, weil es kein Wget hat. Dazu müssen Sie hier hingehen: eternallybored.org/misc/wget Laden Sie es herunter und fügen Sie es der Umgebung hinzu (PATH). Gute Lösung, Upvoting;)
Abel Dantas

Vielen Dank für Ihre Rückmeldungen :)
Yohan Obadia

Verwenden Sie subprocess. IMMER verwenden subprocess. Es ist trivial einfach, eine Maschine zu pumpen, die os.systemdiese für die Benutzereingabe per Fernzugriff verwendet.
Antti Haapala

9

Für Windows und Python 3.x mein Beitrag von zwei Cent zum Umbenennen der Datei beim Download :

  1. Installieren Sie das wget- Modul:pip install wget
  2. Verwenden Sie wget:
import wget
wget.download('Url', 'C:\\PathToMyDownloadFolder\\NewFileName.extension')

Wirklich funktionierendes Kommandozeilenbeispiel:

python -c "import wget; wget.download(""https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.17.2.tar.xz"", ""C:\\Users\\TestName.TestExtension"")"

Hinweis : 'C: \\ PathToMyDownloadFolder \\ NewFileName.extension' ist nicht obligatorisch. Standardmäßig wird die Datei nicht umbenannt und der Download-Ordner ist Ihr lokaler Pfad.


2

Hier ist der Code aus der Torchvision-Bibliothek :

import urllib

def download_url(url, root, filename=None):
    """Download a file from a url and place it in root.
    Args:
        url (str): URL to download file from
        root (str): Directory to place downloaded file in
        filename (str, optional): Name to save the file under. If None, use the basename of the URL
    """

    root = os.path.expanduser(root)
    if not filename:
        filename = os.path.basename(url)
    fpath = os.path.join(root, filename)

    os.makedirs(root, exist_ok=True)

    try:
        print('Downloading ' + url + ' to ' + fpath)
        urllib.request.urlretrieve(url, fpath)
    except (urllib.error.URLError, IOError) as e:
        if url[:5] == 'https':
            url = url.replace('https:', 'http:')
            print('Failed download. Trying https -> http instead.'
                    ' Downloading ' + url + ' to ' + fpath)
            urllib.request.urlretrieve(url, fpath)

Wenn Sie in der Lage sind, sich auf die Torchvision-Bibliothek zu verlassen, tun Sie dies auch einfach:

from torchvision.datasets.utils import download_url
download_url('http://something.com/file.zip', '~/my_folder`)

1

Lassen Sie mich ein Beispiel mit Threads verbessern, falls Sie viele Dateien herunterladen möchten.

import math
import random
import threading

import requests
from clint.textui import progress

# You must define a proxy list
# I suggests https://free-proxy-list.net/
proxies = {
    0: {'http': 'http://34.208.47.183:80'},
    1: {'http': 'http://40.69.191.149:3128'},
    2: {'http': 'http://104.154.205.214:1080'},
    3: {'http': 'http://52.11.190.64:3128'}
}


# you must define the list for files do you want download
videos = [
    "https://i.stack.imgur.com/g2BHi.jpg",
    "https://i.stack.imgur.com/NURaP.jpg"
]

downloaderses = list()


def downloaders(video, selected_proxy):
    print("Downloading file named {} by proxy {}...".format(video, selected_proxy))
    r = requests.get(video, stream=True, proxies=selected_proxy)
    nombre_video = video.split("/")[3]
    with open(nombre_video, 'wb') as f:
        total_length = int(r.headers.get('content-length'))
        for chunk in progress.bar(r.iter_content(chunk_size=1024), expected_size=(total_length / 1024) + 1):
            if chunk:
                f.write(chunk)
                f.flush()


for video in videos:
    selected_proxy = proxies[math.floor(random.random() * len(proxies))]
    t = threading.Thread(target=downloaders, args=(video, selected_proxy))
    downloaderses.append(t)

for _downloaders in downloaderses:
    _downloaders.start()

Dies macht keines der Dinge, nach denen OP gefragt hat (und einige Dinge, nach denen sie nicht gefragt haben).
Melpomene

1
Das Beispiel versuchen, wget Multi-Download-Funktion zu zeigen
Egalicia

Niemand hat danach gefragt. OP bat um das Äquivalent -c, --read-timeout=5und --tries=0(mit einer einzigen URL).
Melpomene

Ich verstehe, sorry :(
Egalicia

1
Ich bin wirklich froh, das hier zu sehen. Serendipity ist der Eckpfeiler des Internets. Ich könnte hier hinzufügen, dass ich während meiner Recherche auf Multithreading und die Anforderungsbibliothek gestoßen
Miller the Gorilla

1

einfach wie py:

class Downloder():
    def download_manager(self, url, destination='Files/DownloderApp/', try_number="10", time_out="60"):
        #threading.Thread(target=self._wget_dl, args=(url, destination, try_number, time_out, log_file)).start()
        if self._wget_dl(url, destination, try_number, time_out, log_file) == 0:
            return True
        else:
            return False


    def _wget_dl(self,url, destination, try_number, time_out):
        import subprocess
        command=["wget", "-c", "-P", destination, "-t", try_number, "-T", time_out , url]
        try:
            download_state=subprocess.call(command)
        except Exception as e:
            print(e)
        #if download_state==0 => successfull download
        return download_state

2
Zu Ihrer Information: Dies funktioniert unter Windows nicht, da der wgetBefehl dort nicht implementiert ist.
Gabriel Fair

-1

TensorFlow erleichtert das Leben. Der Dateipfad gibt uns den Speicherort der heruntergeladenen Datei an.

import tensorflow as tf
tf.keras.utils.get_file(origin='https://storage.googleapis.com/tf-datasets/titanic/train.csv',
                                    fname='train.csv',
                                    untar=False, extract=False)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.