Comment puis-je télécharger un fichier via HTTP à l'aide de Python?
Question
J'ai un petit utilitaire que j'utilise pour télécharger un MP3 à partir d'un site web sur un calendrier, puis construit les mises à jour/un podcast fichier XML que je n'ai évidemment ajouté à iTunes.
Le traitement de texte qui crée/met à jour le fichier XML est écrit en Python.J'utilise wget à l'intérieur d'un Windows .bat
fichier à télécharger le réel MP3 cependant.Je préfère avoir l'intégralité de l'utilitaire écrit en Python si.
J'ai eu du mal mais pour trouver un moyen de télécharger le fichier en Python, donc pourquoi j'ai eu recours à wget
.
Alors, comment puis-je télécharger le fichier à l'aide de Python?
La solution
En Python 2, utilisez urllib2 qui vient avec la bibliothèque standard.
import urllib2
response = urllib2.urlopen('http://www.example.com/')
html = response.read()
C'est la façon la plus simple d'utiliser la bibliothèque, moins toute erreur de manipulation.Vous pouvez également faire des trucs plus complexe comme la modification des en-têtes.La documentation peut être trouvée ici.
Autres conseils
Un de plus, à l'aide de urlretrieve
:
import urllib
urllib.urlretrieve ("http://www.example.com/songs/mp3.mp3", "mp3.mp3")
(pour Python 3+ utilisation import urllib.request
et urllib.request.urlretrieve
)
Encore une autre, avec un "progressbar"
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()
En 2012, l'utilisation de la python demandes de la bibliothèque
>>> import requests
>>>
>>> url = "http://download.thinkbroadband.com/10MB.zip"
>>> r = requests.get(url)
>>> print len(r.content)
10485760
Vous pouvez l'exécuter pip install requests
pour l'obtenir.
Demandes a de nombreux avantages sur les solutions de rechange parce que l'API est beaucoup plus simple.Cela est particulièrement vrai si vous avez à faire de l'authentification.urllib et urllib2 sont assez peu intuitive et douloureux dans ce cas.
2015-12-30
Les gens ont exprimé leur admiration pour la barre de progression.C'est cool, c'est sûr.Il y a plusieurs solutions prêtes à l'emploi, y compris 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)
Il s'agit essentiellement de la mise en œuvre @kvance sur 30 mois.
import urllib2
mp3file = urllib2.urlopen("http://www.example.com/songs/mp3.mp3")
with open('test.mp3','wb') as output:
output.write(mp3file.read())
L' wb
dans open('test.mp3','wb')
ouvre un fichier (et efface tous les fichiers existants) en mode binaire, de sorte que vous pouvez enregistrer des données au lieu de juste le texte.
Python 3
-
import urllib.request response = urllib.request.urlopen('http://www.example.com/') html = response.read()
-
import urllib.request urllib.request.urlretrieve('http://www.example.com/songs/mp3.mp3', 'mp3.mp3')
Python 2
urllib2.urlopen
(merci Corey)import urllib2 response = urllib2.urlopen('http://www.example.com/') html = response.read()
urllib.urlretrieve
(merci PabloG)import urllib urllib.urlretrieve('http://www.example.com/songs/mp3.mp3', 'mp3.mp3')
utiliser wget module:
import wget
wget.download('url')
Une version améliorée de la PabloG code 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)
Écrit wget bibliothèque en pur Python juste pour ce but.Il est pompé vers le haut urlretrieve
avec ces caractéristiques à partir de la version 2.0.
Simple mais Python 2 & Python 3
compatible est livré avec six
bibliothèque:
from six.moves import urllib
urllib.request.urlretrieve("http://www.example.com/songs/mp3.mp3", "mp3.mp3")
Je suis d'accord avec Corey, urllib2 est plus complète que urllib et devrait probablement être le module peut être utilisé si vous voulez faire des choses plus complexes, mais pour rendre les réponses plus complètes, urllib est un simple module, si vous voulez juste l'essentiel:
import urllib
response = urllib.urlopen('http://www.example.com/sound.mp3')
mp3 = response.read()
Fonctionnera très bien.Ou, si vous ne voulez pas avoir affaire avec la "réponse" de l'objet, vous pouvez appeler lire() directement:
import urllib
mp3 = urllib.urlopen('http://www.example.com/sound.mp3').read()
Suivants sont les plus couramment utilisées appels pour le téléchargement de fichiers en python:
urllib.urlretrieve ('url_to_file', file_name)
urllib2.urlopen('url_to_file')
requests.get(url)
wget.download('url', file_name)
Note: urlopen
et urlretrieve
sont trouvé à effectuer relativement mal avec le téléchargement de gros fichiers (taille > 500 MO). requests.get
stocke le fichier en mémoire jusqu'à ce que le téléchargement est terminé.
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")
Vous pouvez obtenir de l'avancement de la rétroaction avec urlretrieve ainsi:
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)
Si vous avez wget installé, vous pouvez utiliser parallel_sync.
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)
Doc:https://pythonhosted.org/parallel_sync/pages/examples.html
C'est assez puissant.Il peut télécharger des fichiers en parallèle, une nouvelle tentative en cas d'échec , et il peut même télécharger des fichiers sur une machine distante.
En python3 vous pouvez utiliser urllib3 et shutil libraires.Télécharger en utilisant pip ou pip3 (Selon que python3 est par défaut ou non)
pip3 install urllib3 shutil
Puis exécutez ce code
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)
Notez que vous téléchargez urllib3
mais l'utilisation de urllib
dans le code
Si la vitesse de questions à vous, j'ai fait un petit test de performance pour les modules urllib
et wget
, et en ce qui concerne wget
J'ai essayé une fois avec barre d'état et une fois sans.J'ai pris trois différentes 500 mo de fichiers de test avec (fichiers différents - pour éliminer la possibilité qu'il y a de la mise en cache se cache sous le capot).Testé sur une machine debian, avec python2.
Tout d'abord, ce sont les résultats (ils sont semblables dans les différentes pistes):
$ 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
==============
La façon dont j'ai effectué le test à l'aide de "profil" décorateur.C'est le code complet:
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
semble être le plus rapide
Juste par souci d'exhaustivité, il est également possible d'appeler n'importe quel programme pour récupérer des fichiers à l'aide de la subprocess
package.Des programmes dédiés à la récupération de fichiers sont plus puissants que les fonctions Python comme urlretrieve
.Par exemple, wget
pouvez télécharger des répertoires de manière récursive (-R
), peuvent traiter avec les FTP, les redirections, les serveurs proxy HTTP, peut éviter de re-télécharger les fichiers existants-nc
), et aria2
pouvez faire de multi-connexion téléchargements qui peuvent potentiellement accélérer vos téléchargements.
import subprocess
subprocess.check_output(['wget', '-O', 'example_output_file.html', 'https://example.com'])
Dans Jupyter ordinateur Portable, l'on peut aussi appeler des programmes directement avec les !
syntaxe:
!wget -O example_output_file.html https://example.com
Le code Source peut être:
import urllib
sock = urllib.urlopen("http://diveintopython.org/")
htmlSource = sock.read()
sock.close()
print htmlSource
J'ai écrit ce qui suit, qui travaille à la vanille Python 2 et 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()
Notes:
- Prend en charge une "barre de progression" de rappel.
- Le téléchargement est un 4 MO de test .zip à partir de mon site web.
Vous pouvez utiliser PycURL sur Python 2 et 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()
Cela peut être un peu tard, Mais j'ai vu pabloG du code et ne pouvait pas aider l'ajout d'un os.system('cls') pour en faire un super look!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()
Si en cours d'exécution dans un environnement autre que Windows, vous devrez utiliser autre chose que 'cls'.Dans MAC OS X et Linux, il doit être "claire".
urlretrieve et des demandes.obtenir sont simples, mais la réalité n'.J'ai récupéré les données pour le couple de sites, y compris le texte et les images, les deux probablement résoudre la plupart des tâches.mais pour plus de solution universelle, je suggère l'utilisation de urlopen.Comme il est inclus dans Python 3 de la bibliothèque standard, votre code peut s'exécuter sur n'importe quel ordinateur d'exécuter Python 3, sans pré-installation de site-package
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()
Cette réponse fournit une solution pour HTTP 403 Forbidden lors du téléchargement de fichiers via http à l'aide de Python.J'ai essayé une seule demande et urllib modules, l'autre module peut fournir quelque chose de mieux, mais c'est celui que j'ai utilisé pour résoudre la plupart des problèmes.