Python kullanarak HTTP üzerinden nasıl dosya indirebilirim?


874

Bir web sitesinden bir MP3 dosyasını bir zamanlamaya indirmek için kullandığım ve iTunes'a eklediğim bir podcast XML dosyasını güncellediğim / güncellediğim küçük bir yardımcı program var.

XML dosyasını oluşturan / güncelleyen metin işleme Python'a yazılır. Ancak, .batgerçek MP3 dosyasını indirmek için wget'i bir Windows dosyası içinde kullanıyorum . Tüm yardımcı programın Python'da yazılmasını tercih ederim.

Python'da dosyayı gerçekten indirmenin bir yolunu bulmaya çalıştım, bu yüzden neden kullanmaya başvurdum wget.

Peki Python kullanarak dosyayı nasıl indirebilirim?



Aşağıdaki cevapların birçoğu tatmin edici bir ikame değildir wget. Diğer şeylerin yanı sıra, wget(1) zaman damgalarını korur (2) dosya .1adını url'den otomatik olarak belirler , dosya zaten varsa (vb.) Ekler (3), içine koyabileceğiniz başka birçok seçenek varsa .wgetrc. Bunlardan herhangi birini istiyorsanız, bunları Python'a kendiniz uygulamanız gerekir, ancak wgetPython'dan çağırmak daha kolaydır .
ShreevatsaR

2
Python 3 için kısa çözüm:import urllib.request; s = urllib.request.urlopen('http://example.com/').read().decode()
Basj

Yanıtlar:


450

Python 2'de, standart kütüphaneyle birlikte gelen urllib2'yi kullanın.

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

Bu, kütüphaneyi kullanmanın en temel yoludur, herhangi bir hata işlemeden kaçınmaktır. Üstbilgileri değiştirme gibi daha karmaşık şeyler de yapabilirsiniz. Belgeleri burada bulabilirsiniz.


11
Sağladığınız URL'de boşluklar varsa, bu çalışmaz. Bu durumda, URL'yi ayrıştırmanız ve yolu urlencode etmeniz gerekir.
Jason Sundram


6
Sadece referans için. Yolu urlencode yoluurllib2.quote
André Puel

11
@ JasonSundram: İçinde boşluklar varsa, bu bir URI değildir.
Zaz

1
Bu, daha büyük dosyalara sahip pencerelerde çalışmaz. Tüm blokları okumalısınız!
Avia

1115

Bir tane daha kullanarak urlretrieve:

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

(Python 3+ kullanımı import urllib.requestve için urllib.request.urlretrieve)

Bir diğeri, "ilerleme çubuğu" ile

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()

1
İşin garibi, urllib2 yöntemi işe yaramadığı zaman bu benim için çalıştı. Urllib2 yöntemi Mac'te çalıştı.
InFreefall

6
Hata: Son okuma genellikle tam bir block_sz olmadığından file_size_dl + = block_sz + = len (buffer) olmalıdır. Ayrıca pencerelerde, metin dosyası değilse çıktı dosyasını "wb" olarak açmanız gerekir.
Patlıcan Jeff

1
Ben de urllib ve urllib2 işe yaramadı ama urlretrieve iyi çalıştı, sinirli oldu - teşekkürler :)
funk-shun

2
if not os.path.isfile(file_name):Podcast'lerin üzerine yazmamak için her şeyi (dosya_adı tanımı hariç) sarın ! bir .html dosyasında bulunan url'ler ile bir cronjob olarak çalıştırırken yararlı
Sriram Murali

2
@PabloG Şimdi 31 oy biraz daha fazla;) Neyse, durum çubuğu eğlenceliydi bu yüzden + 1 olacak
Cinder

340

2012'de python istek kitaplığını kullanın

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

Onu pip install requestsalmak için koşabilirsiniz .

API'nın çok daha basit olması nedeniyle isteklerin alternatiflere göre birçok avantajı vardır. Bu, özellikle kimlik doğrulaması yapmanız gerektiğinde doğrudur. urllib ve urllib2 bu durumda oldukça sezgisel ve acı vericidir.


2015/12/30

İnsanlar ilerleme çubuğuna hayran kaldıklarını ifade ettiler. Güzel, tabi. Şu anda birkaç hazır çözüm var 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)

Bu aslında 30 ay önce açıklanan @kvance uygulamasıdır.


zip dosyası aslında içinde çok sayıda dosya bulunan bir klasörse nasıl kaydedebilir veya çıkarabilirim?
Abdul Muneer

6
Bu, büyük dosyaları nasıl işler, her şey belleğe kaydedilir mi veya büyük bellek gereksinimi olmayan bir dosyaya yazılabilir mi?
bibstha

8
İstekte stream = True ayarlanarak büyük dosyaların akışı mümkündür. Daha sonra tek seferde bir yığın okumak için yanıtta iter_content () yöntemini çağırabilirsiniz.
kvance

7
Neden bir url kütüphanesinde bir dosya unzip özelliği olması gerekir? URL'den dosyayı okuyun, kaydedin ve ardından teknenizde yüzen herhangi bir şekilde sıkıştırmasını açın. Ayrıca bir zip dosyası, pencerelerde gösterildiği gibi bir 'klasör' değildir, bir dosyadır.
Harel

2
@Ali:: r.textMetin veya unicode içerik için. Unicode olarak döndü. r.content: İkili içerik için. Bayt olarak döndürüldü. Buradan okuyun: docs.python-requests.org/en/latest/user/quickstart
hughdbrown

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

wbİçinde open('test.mp3','wb')bir dosyayı açtığında (ve varolan herhangi bir dosyayı siler) sadece metin yerine onunla verileri kaydedebilmek için ikili modda.


30
Bu çözümün dezavantajı, tüm dosyanın diske kaydedilmeden önce ram'a yüklenmesi, yalnızca sınırlı ram'li bir yönlendirici gibi küçük bir sistemdeki büyük dosyalar için kullanıldığında akılda tutulması gereken bir şey olmasıdır.
tripplet

2
@ tripplet peki bunu nasıl düzeltebiliriz?
Lucas Henrique

11
Dosyanın tamamını belleğe okumaktan kaçınmak file.readiçin, okunacak bayt sayısı olan bir argüman iletmeyi deneyin . Bakınız: gist.github.com/hughdbrown/c145b8385a2afa6570e2
hughdbrown

@hughdbrown Komut dosyanızı yararlı buldum, ancak bir sorum var: dosyayı işlem sonrası için kullanabilir miyim? OpenCV ile işlemek istediğim bir jpg dosyasını indirdiğimi varsayalım, çalışmaya devam etmek için 'data' değişkenini kullanabilir miyim? veya indirilen dosyadan tekrar okumam gerekiyor mu?
Rodrigo E. Principe

5
shutil.copyfileobj(mp3file, output)Bunun yerine kullanın .
Aurélien Ooms

129

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')

    Not: Belgelere göre, urllib.request.urlretrieve"eski bir arayüz" ve "gelecekte kullanımdan kaldırılabilir" (teşekkürler gerrit )

Python 2

  • urllib2.urlopen(teşekkürler Corey )

    import urllib2
    response = urllib2.urlopen('http://www.example.com/')
    html = response.read()
  • urllib.urlretrieve(teşekkürler PabloG )

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

2
Elbette biraz zaman aldı, ama sonunda, bir python
stdlib'den

Python3 için çok güzel bir cevap, ayrıca bkz. Docs.python.org/3/library/…
Edouard Thiel

@EdouardThiel Yukarıya tıklarsanız, urllib.request.urlretrieveo bağlantıya götürürsünüz. Şerefe!
bmaupin

2
urllib.request.urlretrieve"eski arayüz" olarak belgelenir ve "gelecekte kullanımdan kaldırılabilir".
gerrit

@ gerrit Bir not ekledim, dikkatleri için teşekkürler!
bmaupin


21

Python 2/3 için PabloG kodunun geliştirilmiş bir sürümü:

#!/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)

Parantezleri ilk satırdan kaldıracağım, çünkü çok eski bir özellik değil.
Arpad Horvath

21

Basit ama Python 2 & Python 3uyumlu bir yol sixkütüphane ile birlikte gelir :

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

1
Bu, 2 + 3 uyumluluğu için bunu yapmanın en iyi yoludur.
Aralık'ta Fush

21
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")

17

Sadece bu amaçla saf Python'da wget kütüphanesi yazdı . Bu kadar pompalanır urlretrieveile bu özelliklerin sürüm 2.0 itibariyle.


3
Özel dosya adıyla kaydetme seçeneğiniz yok mu?
Alex,

2
@Alex 2.1 versiyonuna -o FILENAME seçeneği ekledi
anatoly techtonik

Cygwin altında bu modülü kullandığımda ilerleme çubuğu görünmüyor.
Joe Coder

GNU wget'te olduğu gibi, karışıklığı önlemek -oiçin -Oyerine geçmelisiniz . Veya en azından her iki seçenek de geçerli olmalıdır.
erik

@ eric wget.pyGerçek yerine yerinde değiştirme yapmak istediğimden emin değilim wget. -oZaten farklı davranır - bu uyumlu curlbu şekilde. Belgelerdeki bir not sorunun çözülmesine yardımcı olur mu? Yoksa böyle bir ada sahip bir yardımcı programın komut satırı uyumlu olması temel özelliktir?
anatoly techtonik

16

Python'da dosya indirmek için en sık kullanılan çağrılar şunlardır:

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

  2. urllib2.urlopen('url_to_file')

  3. requests.get(url)

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

Not: urlopenve urlretrievebüyük dosyaları (boyut> 500 MB) indirirken nispeten kötü performans gösterdiği tespit edilmiştir. requests.getindirme işlemi tamamlanana kadar dosyayı bellekte saklar.


14

Corey'ye katılıyorum, urllib2 urllib'den daha eksiksiz ve daha karmaşık şeyler yapmak istiyorsanız kullanılan modül olmalı, ancak cevapları daha eksiksiz hale getirmek için, sadece temelleri istiyorsanız urllib daha basit bir modül:

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

İyi çalışacak. Veya "yanıt" nesnesiyle uğraşmak istemiyorsanız doğrudan read () öğesini çağırabilirsiniz :

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

10

Python3'te urllib3 ve shutil kütüphanelerini kullanabilirsiniz. Pip veya pip3 kullanarak indirin (python3'ün varsayılan olup olmadığına bağlı olarak)

pip3 install urllib3 shutil

Sonra bu kodu çalıştırın

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)

İndirdiğiniz urllib3ancak urllibkodda kullandığınızı unutmayın


7

Urlretrieve ile de ilerleme geri bildirimini alabilirsiniz:

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)

7

Eğer wget yüklüyse parallel_sync kullanabilirsiniz.

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)

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

Bu oldukça güçlü. Dosyaları paralel olarak indirebilir, arıza durumunda yeniden deneyebilir ve hatta uzaktaki bir makinede dosya indirebilir.


Bu sadece Linux içindir
jjj

4

Hız sizin için önemli, ben modülleri için küçük bir performans testi yapılmış urllibve wgetve ilgiliwget ben durum çubuğuna sahip olmadan bir kez bir kez denedik. Test etmek için üç farklı 500MB dosya aldım (farklı dosyalar - başlık altında bazı önbelleğe alma olasılığını ortadan kaldırmak için). Debian makinesinde, python2 ile test edilmiştir.

İlk olarak, bunlar sonuçlar (farklı çalışmalarda benzerler):

$ 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
==============

Testi gerçekleştirme şeklim "profil" dekoratörü kullanmaktır. Bu tam kod:

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 en hızlı gibi görünüyor


Barın zamanı çok arttırması için kaputun altında tamamen korkunç bir şey olmalı.
Alistair Carscadden

4

Sadece tamlık uğruna, subprocesspaketi kullanarak dosyaları almak için herhangi bir programı çağırmak da mümkündür . Dosyaları almaya adanmış programlar Python gibi işlevlerden daha güçlüdür urlretrieve. Örneğin, wgetdizinleri özyinelemeli olarak indirebilir ( -R), FTP ile başa çıkabilir, yönlendirmeler, HTTP proxy'leri, mevcut dosyaları yeniden indirmeyi önleyebilir ( -nc) ve aria2indirmelerinizi hızlandırabilecek çok bağlantılı indirmeler yapabilir.

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

Jupyter Notebook'da programlar !sözdizimi ile doğrudan çağrılabilir :

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

3

Kaynak kodu şunlar olabilir:

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

3

Sen kullanabilirsiniz pycurl Python 2. ve 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()

2

Vanilya Python 2 veya Python 3'te çalışan aşağıdakileri yazdım.


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()

Notlar:

  • "İlerleme çubuğu" geri aramasını destekler.
  • İndirme, web sitemden 4 MB'lık bir test .zip dosyasıdır.

harika çalışıyor, jupyter üzerinden çalıştırmak istediğimi aldım :-)
Samir Ouldsaadi

1

Bu biraz geç olabilir, ama pabloG'nin kodunu gördüm ve oSsystem ('cls') 'in MÜKEMMEL görünmesini sağlamak için ekleyemedim! Bunu kontrol et :

    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()

Windows dışında bir ortamda çalışıyorsanız, 'cl' den başka bir şey kullanmanız gerekecektir. MAC OS X ve Linux'ta 'açık' olmalıdır.


3
clsOS X veya Ubuntu sunucumda hiçbir şey yapmaz. Bazı açıklamalar iyi olabilir.
kqw

clearLinux için kullanmanız veya tüm komut satırı çıktısını temizlemek yerine baskı satırını daha iyi değiştirmeniz gerektiğini düşünüyorum .
Arijoon

4
bu yanıt yalnızca başka bir yanıtı kopyalar ve os.system()platforma özel bir komut ( cls) kullanarak ekranı temizlemek için bir alt işlemi başlatan kullanımdan kaldırılmış bir işleve ( ) çağrı ekler . Bu nasıl var herhangi upvotes ?? Tamamen değersiz "cevap" IMHO.
Corey Goldberg

1

urlretrieve ve requests.get basit, ancak gerçek değil. Metin ve resimler dahil olmak üzere çift siteler için veri getirdim, yukarıdaki ikisi muhtemelen görevlerin çoğunu çözüyor. ancak daha evrensel bir çözüm için urlopen kullanımını öneririm. Python 3 standart kütüphanesine dahil olduğundan, kodunuz site paketini önceden yüklemeden Python 3'ü çalıştıran herhangi bir makinede çalışabilir

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()

Bu yanıt, HTTP 403 için Python kullanarak http üzerinden dosya indirilirken bir çözüm sağlar. Sadece istekleri ve urllib modüllerini denedim, diğer modül daha iyi bir şey sağlayabilir, ancak bu sorunların çoğunu çözmek için kullandığım.


0

Geç cevap, ancak python>=3.6sizin için kullanabilirsiniz:

import dload
dload.save(url)

Yükleme yeri dload:

pip3 install dload

0

Bir web sayfasından tüm dosyaları indirmek istedim. Denedim wgetama başarısız oldu bu yüzden Python yolu için karar verdi ve bu iş parçacığı bulundu.

Bunu okuduktan sonra, biraz komut satırı uygulamasını yaptık soupgetmükemmel yanıtlara genişleyen PabloG ve Stan ve bazı yararlı seçenek ekleyerek.

BeatifulSoup kullanıyorSayfanın tüm URL'lerini toplamak ve daha sonra istenen uzantıya sahip olanları indirmek için . Son olarak paralel olarak birden fazla dosya indirebilirsiniz.

İşte burada:

#!/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)

Kullanımına bir örnek:

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

Ve eylemde görmek istiyorsanız gerçek bir örnek:

python3 soupget.py -p -e .xlsx .pdf .csv -u https://healthdata.gov/dataset/chemicals-cosmetics
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.