Hoe download ik een bestand via HTTP?

Ik heb een klein hulpprogramma dat ik gebruik om volgens een schema een MP3-bestand van een website te downloaden en vervolgens een podcast-XML-bestand samen te stellen/bij te werken dat ik aan iTunes heb toegevoegd.

De tekstverwerking die het XML-bestand maakt/bijwerkt, is geschreven in Python. Ik gebruik echter wget in een Windows .bat-bestand om het eigenlijke MP3-bestand te downloaden. Ik zou liever hebben dat het hele hulpprogramma in Python is geschreven.

Ik worstelde om een ​​manier te vinden om het bestand daadwerkelijk in Python te downloaden, daarom nam ik mijn toevlucht tot het gebruik van wget.

Dus, hoe download ik het bestand met Python?


Antwoord 1, autoriteit 100%

Gebruik urllib.request.urlopen():

import urllib.request
with urllib.request.urlopen('http://www.example.com/') as f:
    html = f.read().decode('utf-8')

Dit is de meest eenvoudige manier om de bibliotheek te gebruiken, minus eventuele foutafhandeling. Je kunt ook meer complexe dingen doen, zoals het wijzigen van kopteksten.

Op Python 2 staat de methode in urllib2:

import urllib2
response = urllib2.urlopen('http://www.example.com/')
html = response.read()

Antwoord 2, autoriteit 97%

Nog een, met behulp van urlretrieve:

import urllib
urllib.urlretrieve("http://www.example.com/songs/mp3.mp3", "mp3.mp3")

(gebruik voor Python 3+ import urllib.request en urllib.request.urlretrieve)

Nog een, met een “voortgangsbalk”

import urllib2
url = "http://download.thinkbroadband.com/10MB.zip"
file_name = url.split('/')[-1]
u = urllib2.urlopen(url)
f = open(file_name, 'wb')
meta = u.info()
file_size = int(meta.getheaders("Content-Length")[0])
print "Downloading: %s Bytes: %s" % (file_name, file_size)
file_size_dl = 0
block_sz = 8192
while True:
    buffer = u.read(block_sz)
    if not buffer:
        break
    file_size_dl += len(buffer)
    f.write(buffer)
    status = r"%10d  [%3.2f%%]" % (file_size_dl, file_size_dl * 100. / file_size)
    status = status + chr(8)*(len(status)+1)
    print status,
f.close()

Antwoord 3, autoriteit 74%

Gebruik in 2012 de python-verzoekenbibliotheek

>>> import requests
>>> 
>>> url = "http://download.thinkbroadband.com/10MB.zip"
>>> r = requests.get(url)
>>> print len(r.content)
10485760

Je kunt pip install requests uitvoeren om het te krijgen.

Requests heeft veel voordelen ten opzichte van de alternatieven omdat de API veel eenvoudiger is. Dit geldt met name als u authenticatie moet doen. urllib en urllib2 zijn in dit geval niet intuïtief en pijnlijk.


30-12-2015

Mensen hebben hun bewondering uitgesproken voor de voortgangsbalk. Het is cool, zeker. Er zijn nu verschillende kant-en-klare oplossingen, waaronder tqdm:

from tqdm import tqdm
import requests
url = "http://download.thinkbroadband.com/10MB.zip"
response = requests.get(url, stream=True)
with open("10MB", "wb") as handle:
    for data in tqdm(response.iter_content()):
        handle.write(data)

Dit is in wezen de implementatie die @kvance 30 maanden geleden heeft beschreven.


Antwoord 4, autoriteit 32%

import urllib2
mp3file = urllib2.urlopen("http://www.example.com/songs/mp3.mp3")
with open('test.mp3','wb') as output:
  output.write(mp3file.read())

De wb in open('test.mp3','wb') opent een bestand (en wist elk bestaand bestand) in binaire modus, zodat u gegevens kunt opslaan mee in plaats van alleen tekst.


Antwoord 5, autoriteit 29%

Python 3

  • urllib.request.urlopen

    import urllib.request
    response = urllib.request.urlopen('http://www.example.com/')
    html = response.read()
    
  • urllib.request.urlretrieve

    import urllib.request
    urllib.request.urlretrieve('http://www.example.com/songs/mp3.mp3', 'mp3.mp3')
    

    Opmerking: Volgens de documentatie is urllib.request.urlretrieve een “verouderde interface” en “kan in de toekomst verouderd worden” (bedankt gerrit)

Python 2

  • urllib2.urlopen (bedankt Corey)

    import urllib2
    response = urllib2.urlopen('http://www.example.com/')
    html = response.read()
    
  • urllib.urlretrieve (bedankt PabloG)

    import urllib
    urllib.urlretrieve('http://www.example.com/songs/mp3.mp3', 'mp3.mp3')
    

Antwoord 6, autoriteit 8%

gebruik wget-module:

import wget
wget.download('url')

Antwoord 7, autoriteit 7%

import os,requests
def download(url):
    get_response = requests.get(url,stream=True)
    file_name  = url.split("/")[-1]
    with open(file_name, 'wb') as f:
        for chunk in get_response.iter_content(chunk_size=1024):
            if chunk: # filter out keep-alive new chunks
                f.write(chunk)
download("https://example.com/example.jpg")

Antwoord 8, autoriteit 4%

Een verbeterde versie van de PabloG-code voor Python 2/3:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import ( division, absolute_import, print_function, unicode_literals )
import sys, os, tempfile, logging
if sys.version_info >= (3,):
    import urllib.request as urllib2
    import urllib.parse as urlparse
else:
    import urllib2
    import urlparse
def download_file(url, dest=None):
    """ 
    Download and save a file specified by url to dest directory,
    """
    u = urllib2.urlopen(url)
    scheme, netloc, path, query, fragment = urlparse.urlsplit(url)
    filename = os.path.basename(path)
    if not filename:
        filename = 'downloaded.file'
    if dest:
        filename = os.path.join(dest, filename)
    with open(filename, 'wb') as f:
        meta = u.info()
        meta_func = meta.getheaders if hasattr(meta, 'getheaders') else meta.get_all
        meta_length = meta_func("Content-Length")
        file_size = None
        if meta_length:
            file_size = int(meta_length[0])
        print("Downloading: {0} Bytes: {1}".format(url, file_size))
        file_size_dl = 0
        block_sz = 8192
        while True:
            buffer = u.read(block_sz)
            if not buffer:
                break
            file_size_dl += len(buffer)
            f.write(buffer)
            status = "{0:16}".format(file_size_dl)
            if file_size:
                status += "   [{0:6.2f}%]".format(file_size_dl * 100 / file_size)
            status += chr(13)
            print(status, end="")
        print()
    return filename
if __name__ == "__main__":  # Only run if this file is called directly
    print("Testing with 10MB download")
    url = "http://download.thinkbroadband.com/10MB.zip"
    filename = download_file(url)
    print(filename)

Antwoord 9, autoriteit 4%

Eenvoudig maar Python 2 & Python 3 compatibele manier wordt geleverd met six bibliotheek:

from six.moves import urllib
urllib.request.urlretrieve("http://www.example.com/songs/mp3.mp3", "mp3.mp3")

Antwoord 10, autoriteit 4%

Schreef speciaal voor dit doel de wget-bibliotheek in pure Python. Het wordt urlretrieve opgepompt met deze functies vanaf versie 2.0.


Antwoord 11, autoriteit 3%

Hier volgen de meest gebruikte oproepen voor het downloaden van bestanden in python:

  1. urllib.urlretrieve ('url_to_file', file_name)

  2. urllib2.urlopen('url_to_file')

  3. requests.get(url)

  4. wget.download('url', file_name)

Opmerking: urlopen en urlretrieve blijken relatief slecht te presteren bij het downloaden van grote bestanden (grootte > 500 MB). requests.get slaat het bestand op in het geheugen totdat het downloaden is voltooid.


Antwoord 12, autoriteit 3%

Ik ben het met Corey eens, urllib2 is completer dan urllib en zou waarschijnlijk de module zijn die wordt gebruikt als je complexere dingen wilt doen, maar om de antwoorden completer te maken, is urllib een eenvoudigere module als je alleen de basis wilt:

import urllib
response = urllib.urlopen('http://www.example.com/sound.mp3')
mp3 = response.read()

Zal goed werken. Of, als u het “response”-object niet wilt behandelen, kunt u read() rechtstreeks aanroepen:

import urllib
mp3 = urllib.urlopen('http://www.example.com/sound.mp3').read()

Antwoord 13, autoriteit 3%

In python3 kun je urllib3 en shutil libraires gebruiken.
Download ze met pip of pip3 (afhankelijk of python3 standaard is of niet)

pip3 install urllib3 shutil

Voer vervolgens deze code uit

import urllib.request
import shutil
url = "http://www.somewebsite.com/something.pdf"
output_file = "save_this_name.pdf"
with urllib.request.urlopen(url) as response, open(output_file, 'wb') as out_file:
    shutil.copyfileobj(response, out_file)

Houd er rekening mee dat u urllib3 downloadt maar urllib in code gebruikt


Antwoord 14, autoriteit 2%

Als je wget hebt geïnstalleerd, kun je parallel_sync gebruiken.

pip install parallel_sync

from parallel_sync import wget
urls = ['http://something.png', 'http://somthing.tar.gz', 'http://somthing.zip']
wget.download('/tmp', urls)
# or a single file:
wget.download('/tmp', urls[0], filenames='x.zip', extract=True)

Document:
https://pythonhosted.org/parallel_sync/pages/examples.html

Dit is behoorlijk krachtig. Het kan bestanden parallel downloaden, het opnieuw proberen bij een fout en het kan zelfs bestanden downloaden op een externe machine.


Antwoord 15

Je kunt de voortgangsfeedback ook krijgen met urlretrieve:

def report(blocknr, blocksize, size):
    current = blocknr*blocksize
    sys.stdout.write("\r{0:.2f}%".format(100.0*current/size))
def downloadFile(url):
    print "\n",url
    fname = url.split('/')[-1]
    print fname
    urllib.urlretrieve(url, fname, report)

Antwoord 16

Als snelheid belangrijk voor je is, heb ik een kleine prestatietest gedaan voor de modules urllib en wget, en met betrekking tot wget heb ik een keer geprobeerd met statusbalk en eenmaal zonder. Ik heb drie verschillende bestanden van 500 MB genomen om mee te testen (verschillende bestanden – om de kans te elimineren dat er wat cache aan de gang is onder de motorkap). Getest op debian machine, met python2.

Ten eerste zijn dit de resultaten (ze zijn vergelijkbaar in verschillende runs):

$ python wget_test.py 
urlretrive_test : starting
urlretrive_test : 6.56
==============
wget_no_bar_test : starting
wget_no_bar_test : 7.20
==============
wget_with_bar_test : starting
100% [......................................................................] 541335552 / 541335552
wget_with_bar_test : 50.49
==============

De manier waarop ik de test heb uitgevoerd, is met behulp van de “profile”-decorateur. Dit is de volledige code:

import wget
import urllib
import time
from functools import wraps
def profile(func):
    @wraps(func)
    def inner(*args):
        print func.__name__, ": starting"
        start = time.time()
        ret = func(*args)
        end = time.time()
        print func.__name__, ": {:.2f}".format(end - start)
        return ret
    return inner
url1 = 'http://host.com/500a.iso'
url2 = 'http://host.com/500b.iso'
url3 = 'http://host.com/500c.iso'
def do_nothing(*args):
    pass
@profile
def urlretrive_test(url):
    return urllib.urlretrieve(url)
@profile
def wget_no_bar_test(url):
    return wget.download(url, out='/tmp/', bar=do_nothing)
@profile
def wget_with_bar_test(url):
    return wget.download(url, out='/tmp/')
urlretrive_test(url1)
print '=============='
time.sleep(1)
wget_no_bar_test(url2)
print '=============='
time.sleep(1)
wget_with_bar_test(url3)
print '=============='
time.sleep(1)

urllib lijkt de snelste te zijn


Antwoord 17

Voor de volledigheid is het ook mogelijk om elk programma voor het ophalen van bestanden aan te roepen met behulp van het subprocess pakket. Programma’s voor het ophalen van bestanden zijn krachtiger dan Python-functies zoals urlretrieve. wget kan bijvoorbeeld mappen recursief downloaden (-R), kan omgaan met FTP, omleidingen, HTTP-proxy’s, kan voorkomen dat bestaande bestanden opnieuw worden gedownload (-nc), en aria2 kan downloads met meerdere verbindingen uitvoeren die uw downloads mogelijk kunnen versnellen.

import subprocess
subprocess.check_output(['wget', '-O', 'example_output_file.html', 'https://example.com'])

In Jupyter Notebook kan men programma’s ook rechtstreeks aanroepen met de syntaxis !:

!wget -O example_output_file.html https://example.com

Antwoord 18

Broncode kan zijn:

import urllib
sock = urllib.urlopen("http://diveintopython.org/")
htmlSource = sock.read()                            
sock.close()                                        
print htmlSource  

Antwoord 19

Ik schreef het volgende, dat werkt in vanille Python 2 of Python 3.


import sys
try:
    import urllib.request
    python3 = True
except ImportError:
    import urllib2
    python3 = False
def progress_callback_simple(downloaded,total):
    sys.stdout.write(
        "\r" +
        (len(str(total))-len(str(downloaded)))*" " + str(downloaded) + "/%d"%total +
        " [%3.2f%%]"%(100.0*float(downloaded)/float(total))
    )
    sys.stdout.flush()
def download(srcurl, dstfilepath, progress_callback=None, block_size=8192):
    def _download_helper(response, out_file, file_size):
        if progress_callback!=None: progress_callback(0,file_size)
        if block_size == None:
            buffer = response.read()
            out_file.write(buffer)
            if progress_callback!=None: progress_callback(file_size,file_size)
        else:
            file_size_dl = 0
            while True:
                buffer = response.read(block_size)
                if not buffer: break
                file_size_dl += len(buffer)
                out_file.write(buffer)
                if progress_callback!=None: progress_callback(file_size_dl,file_size)
    with open(dstfilepath,"wb") as out_file:
        if python3:
            with urllib.request.urlopen(srcurl) as response:
                file_size = int(response.getheader("Content-Length"))
                _download_helper(response,out_file,file_size)
        else:
            response = urllib2.urlopen(srcurl)
            meta = response.info()
            file_size = int(meta.getheaders("Content-Length")[0])
            _download_helper(response,out_file,file_size)
import traceback
try:
    download(
        "https://geometrian.com/data/programming/projects/glLib/glLib%20Reloaded%200.5.9/0.5.9.zip",
        "output.zip",
        progress_callback_simple
    )
except:
    traceback.print_exc()
    input()

Opmerkingen:

  • Ondersteunt een “voortgangsbalk”-callback.
  • Download is een .zip-test van 4 MB van mijn website.

Antwoord 20

Je kunt PycURL gebruiken op Python 2 en 3.

import pycurl
FILE_DEST = 'pycurl.html'
FILE_SRC = 'http://pycurl.io/'
with open(FILE_DEST, 'wb') as f:
    c = pycurl.Curl()
    c.setopt(c.URL, FILE_SRC)
    c.setopt(c.WRITEDATA, f)
    c.perform()
    c.close()

Antwoord 21

Dit is misschien een beetje laat, maar ik zag de code van pabloG en kon het niet laten om een ​​os.system(‘cls’) toe te voegen om het er GEWELDIG uit te laten zien! Check it out:

    import urllib2,os
    url = "http://download.thinkbroadband.com/10MB.zip"
    file_name = url.split('/')[-1]
    u = urllib2.urlopen(url)
    f = open(file_name, 'wb')
    meta = u.info()
    file_size = int(meta.getheaders("Content-Length")[0])
    print "Downloading: %s Bytes: %s" % (file_name, file_size)
    os.system('cls')
    file_size_dl = 0
    block_sz = 8192
    while True:
        buffer = u.read(block_sz)
        if not buffer:
            break
        file_size_dl += len(buffer)
        f.write(buffer)
        status = r"%10d  [%3.2f%%]" % (file_size_dl, file_size_dl * 100. / file_size)
        status = status + chr(8)*(len(status)+1)
        print status,
    f.close()

Als u in een andere omgeving dan Windows draait, moet u iets anders gebruiken dan ‘cls’. In MAC OS X en Linux zou het ‘duidelijk’ moeten zijn.


Antwoord 22

urlretrieve en requests.get zijn eenvoudig, maar de realiteit niet.
Ik heb gegevens opgehaald voor een paar sites, inclusief tekst en afbeeldingen, de bovenstaande twee lossen waarschijnlijk de meeste taken op. maar voor een meer universele oplossing raad ik het gebruik van urlopen aan. Omdat het is opgenomen in de standaardbibliotheek van Python 3, kan uw code worden uitgevoerd op elke machine waarop Python 3 wordt uitgevoerd zonder het sitepakket vooraf te installeren

import urllib.request
url_request = urllib.request.Request(url, headers=headers)
url_connect = urllib.request.urlopen(url_request)
#remember to open file in bytes mode
with open(filename, 'wb') as f:
    while True:
        buffer = url_connect.read(buffer_size)
        if not buffer: break
        #an integer value of size of written data
        data_wrote = f.write(buffer)
#you could probably use with-open-as manner
url_connect.close()

Dit antwoord biedt een oplossing voor HTTP 403 Forbidden bij het downloaden van bestanden via http met Python. Ik heb alleen verzoeken en urllib-modules geprobeerd, de andere module biedt misschien iets beters, maar dit is degene die ik heb gebruikt om de meeste problemen op te lossen.


Antwoord 23

Laat antwoord, maar voor python>=3.6 kun je het volgende gebruiken:

import dload
dload.save(url)

Installeer dload met:

pip3 install dload

Antwoord 24

Ik wilde alle bestanden van een webpagina downloaden. Ik probeerde wget maar het faalde dus ik besloot voor de Python-route en ik vond deze thread.

Na het lezen heb ik een kleine opdrachtregeltoepassing gemaakt, soupget , voortbouwend op de uitstekende antwoorden van PabloG en Stan en het toevoegen van enkele handige opties.

Het gebruikt BeatifulSoup om alle URL’s van de pagina te verzamelen en vervolgens de URL’s te downloaden met de gewenste extensie(s). Eindelijk kan het meerdere bestanden tegelijk downloaden.

Hier is het:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import (division, absolute_import, print_function, unicode_literals)
import sys, os, argparse
from bs4 import BeautifulSoup
# --- insert Stan's script here ---
# if sys.version_info >= (3,): 
#...
#...
# def download_file(url, dest=None): 
#...
#...
# --- new stuff ---
def collect_all_url(page_url, extensions):
    """
    Recovers all links in page_url checking for all the desired extensions
    """
    conn = urllib2.urlopen(page_url)
    html = conn.read()
    soup = BeautifulSoup(html, 'lxml')
    links = soup.find_all('a')
    results = []    
    for tag in links:
        link = tag.get('href', None)
        if link is not None: 
            for e in extensions:
                if e in link:
                    # Fallback for badly defined links
                    # checks for missing scheme or netloc
                    if bool(urlparse.urlparse(link).scheme) and bool(urlparse.urlparse(link).netloc):
                        results.append(link)
                    else:
                        new_url=urlparse.urljoin(page_url,link)                        
                        results.append(new_url)
    return results
if __name__ == "__main__":  # Only run if this file is called directly
    # Command line arguments
    parser = argparse.ArgumentParser(
        description='Download all files from a webpage.')
    parser.add_argument(
        '-u', '--url', 
        help='Page url to request')
    parser.add_argument(
        '-e', '--ext', 
        nargs='+',
        help='Extension(s) to find')    
    parser.add_argument(
        '-d', '--dest', 
        default=None,
        help='Destination where to save the files')
    parser.add_argument(
        '-p', '--par', 
        action='store_true', default=False, 
        help="Turns on parallel download")
    args = parser.parse_args()
    # Recover files to download
    all_links = collect_all_url(args.url, args.ext)
    # Download
    if not args.par:
        for l in all_links:
            try:
                filename = download_file(l, args.dest)
                print(l)
            except Exception as e:
                print("Error while downloading: {}".format(e))
    else:
        from multiprocessing.pool import ThreadPool
        results = ThreadPool(10).imap_unordered(
            lambda x: download_file(x, args.dest), all_links)
        for p in results:
            print(p)

Een voorbeeld van het gebruik ervan is:

python3 soupget.py -p -e <list of extensions> -d <destination_folder> -u <target_webpage>

En een echt voorbeeld als je het in actie wilt zien:

python3 soupget.py -p -e .xlsx .pdf .csv -u https://healthdata.gov/dataset/chemicals-cosmetics

Antwoord 25

Nieuwe op API urllib3 gebaseerde implementatie

>>> import urllib3
>>> http = urllib3.PoolManager()
>>> r = http.request('GET', 'your_url_goes_here')
>>> r.status
   200
>>> r.data
   *****Response Data****

Meer info: https://pypi.org/project/urllib3/


Antwoord 26

Een andere manier is om een ​​extern proces aan te roepen, zoals curl.exe. Curl geeft standaard een voortgangsbalk, gemiddelde downloadsnelheid, resterende tijd en meer weer, allemaal netjes opgemaakt in een tabel.
Zet curl.exe in dezelfde map als uw script

from subprocess import call
url = ""
call(["curl", {url}, '--output', "song.mp3"])

Opmerking: je kunt geen uitvoerpad specificeren met curl, dus doe daarna een os.rename

LEAVE A REPLY

Please enter your comment!
Please enter your name here

nine + five =

Other episodes