Bagaimana cara mengunduh file melalui HTTP menggunakan Python?


875

Saya memiliki utilitas kecil yang saya gunakan untuk mengunduh file MP3 dari sebuah situs web sesuai jadwal dan kemudian membangun / memperbarui file XML podcast yang telah saya tambahkan ke iTunes.

Pemrosesan teks yang membuat / memperbarui file XML ditulis dengan Python. Namun, saya menggunakan wget di dalam .batfile Windows untuk mengunduh file MP3 yang sebenarnya. Saya lebih suka memiliki seluruh utilitas ditulis dengan Python.

Saya kesulitan menemukan cara untuk benar-benar mengunduh file dengan Python, jadi mengapa saya terpaksa menggunakan wget.

Jadi, bagaimana cara mengunduh file menggunakan Python?



Banyak jawaban di bawah ini bukan pengganti yang memuaskan wget. Antara lain, wget(1) menjaga stempel waktu (2) secara otomatis menentukan nama file dari url, menambahkan .1(dll) jika file sudah ada (3) memiliki banyak opsi lain, beberapa di antaranya mungkin Anda masukkan ke dalam .wgetrc. Jika Anda menginginkan salah satu dari itu, Anda harus mengimplementasikannya sendiri dengan Python, tetapi lebih mudah untuk hanya memanggil wgetdari Python.
ShreevatsaR

2
Solusi singkat untuk Python 3:import urllib.request; s = urllib.request.urlopen('http://example.com/').read().decode()
Basj

Jawaban:


450

Dalam Python 2, gunakan urllib2 yang datang dengan pustaka standar.

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

Ini adalah cara paling dasar untuk menggunakan perpustakaan, minus penanganan kesalahan. Anda juga dapat melakukan hal-hal yang lebih kompleks seperti mengganti tajuk. Dokumentasi dapat ditemukan di sini.


11
Ini tidak akan berfungsi jika ada ruang di url yang Anda berikan. Dalam hal ini, Anda harus mengurai url dan urlencode path.
Jason Sundram

91
Berikut adalah solusi Python 3: stackoverflow.com/questions/7243750/...
tommy.carstensen

6
Hanya untuk referensi. Cara untuk urlencode jalan adalahurllib2.quote
André Puel

11
@JasonSundram: Jika ada spasi di dalamnya, itu bukan URI.
Zaz

1
Ini tidak berfungsi di windows dengan file yang lebih besar. Anda harus membaca semua blok!
Avia

1115

Satu lagi, menggunakan urlretrieve:

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

(untuk penggunaan Python 3+ import urllib.requestdan urllib.request.urlretrieve)

Satu lagi, dengan "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()

1
Anehnya, ini bekerja untuk saya di Windows ketika metode urllib2 tidak. Metode urllib2 bekerja pada Mac.
InFreefall

6
Bug: file_size_dl + = block_sz harus + = len (buffer) karena pembacaan terakhir sering kali bukan block_sz penuh. Juga di windows Anda perlu membuka file output sebagai "wb" jika itu bukan file teks.
Terong Jeff

1
Saya juga urllib dan urllib2 tidak bekerja tetapi urlretrieve bekerja dengan baik, semakin frustrasi - terima kasih :)
funk-shun

2
Bungkus semuanya (kecuali definisi file_name) dengan if not os.path.isfile(file_name):untuk menghindari menimpa podcast! berguna saat menjalankannya sebagai cronjob dengan url yang ditemukan dalam file .html
Sriram Murali

2
@PabloG sedikit lebih dari 31 suara sekarang;) Bagaimanapun, status bar sangat menyenangkan jadi saya akan memberi +1
Cinder

340

Pada 2012, gunakan pustaka permintaan python

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

Anda bisa lari pip install requestsuntuk mendapatkannya.

Permintaan memiliki banyak keunggulan dibandingkan alternatif karena API jauh lebih sederhana. Ini terutama benar jika Anda harus melakukan otentikasi. urllib dan urllib2 sangat tidak intuitif dan menyakitkan dalam kasus ini.


2015-12-30

Orang-orang telah menyatakan kekagumannya terhadap progress bar. Itu keren, tentu saja. Ada beberapa solusi siap pakai sekarang, termasuk 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)

Ini pada dasarnya adalah implementasi @kvance yang diuraikan 30 bulan lalu.


bagaimana cara menyimpan atau mengekstrak jika file zip sebenarnya adalah folder dengan banyak file di dalamnya?
Abdul Muneer

6
Bagaimana ini menangani file besar, apakah semuanya disimpan ke dalam memori atau dapatkah ini ditulis ke file tanpa persyaratan memori besar?
bibstha

8
Dimungkinkan untuk melakukan streaming file besar dengan mengatur stream = True dalam permintaan. Anda kemudian dapat memanggil iter_content () pada respons untuk membaca bongkahan sekaligus.
kvance

7
Mengapa perpustakaan url perlu memiliki fasilitas unzip file? Baca file dari url, simpan dan unzip dengan cara apa pun mengapung perahu Anda. File zip juga bukan 'folder' seperti yang ditampilkan di windows, ini file.
Harel

2
@ Ali:: r.textUntuk konten teks atau unicode. Dikembalikan sebagai unicode. r.content: Untuk konten biner. Dikembalikan sebagai byte. Baca tentang ini di sini: 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())

The wbdalam open('test.mp3','wb')membuka file (dan menghapus file yang ada) dalam mode biner sehingga Anda dapat menyimpan data dengan itu bukan hanya teks.


30
Kerugian dari solusi ini adalah, bahwa seluruh file dimuat ke ram sebelum disimpan ke disk, hanya sesuatu yang perlu diingat jika menggunakan ini untuk file besar pada sistem kecil seperti router dengan ram terbatas.
tripplet

2
@ Tripplet jadi bagaimana kita memperbaikinya?
Lucas Henrique

11
Untuk menghindari membaca seluruh file ke dalam memori, coba sampaikan argumen ke file.readjumlah byte yang dibaca. Lihat: gist.github.com/hughdbrown/c145b8385a2afa6570e2
hughdbrown

@ hughdbrown Saya menemukan skrip Anda berguna, tetapi ada satu pertanyaan: dapatkah saya menggunakan file untuk post-processing? misalkan saya mengunduh file jpg yang ingin saya proses dengan OpenCV, dapatkah saya menggunakan variabel 'data' untuk tetap berfungsi? atau apakah saya harus membacanya lagi dari file yang diunduh?
Rodrigo E. Principe

5
Gunakan shutil.copyfileobj(mp3file, output)sebagai gantinya.
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')

    Catatan: Menurut dokumentasi, urllib.request.urlretrieveadalah "antarmuka lama" dan "mungkin menjadi usang di masa depan" (terima kasih gerrit )

Python 2

  • urllib2.urlopen(terima kasih Corey )

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

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

2
Memang butuh beberapa saat, tetapi di sana, akhirnya adalah api mudah dan mudah yang saya harapkan dari stdlib python :)
ThorSummoner

Jawaban yang sangat bagus untuk python3, lihat juga docs.python.org/3/library/…
Edouard Thiel

@ EdouardThiel Jika Anda mengklik di urllib.request.urlretrieveatas itu akan membawa Anda ke tautan yang tepat. Bersulang!
bmaupin

2
urllib.request.urlretrievedidokumentasikan sebagai "antarmuka warisan" dan "mungkin menjadi usang di masa depan".
gerrit

@gerit Saya menambahkan catatan, terima kasih untuk semua yang sudah ada
bmaupin


21

Versi perbaikan dari kode PabloG untuk 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)

Saya akan menghapus tanda kurung dari baris pertama, karena ini bukan fitur yang terlalu lama.
Arpad Horvath

21

Cara sederhana namun Python 2 & Python 3kompatibel dilengkapi dengan sixperpustakaan:

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

1
Ini adalah cara terbaik untuk melakukannya untuk kompatibilitas 2 + 3.
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

Menulis pustaka wget dengan Python murni hanya untuk tujuan ini. Dipompa urlretrievedengan fitur-fitur ini pada versi 2.0.


3
Tidak ada opsi untuk menyimpan dengan nama file khusus?
Alex

2
@Alex menambahkan opsi -o FILENAME ke versi 2.1
anatoly techtonik

Bilah progres tidak muncul ketika saya menggunakan modul ini di bawah Cygwin.
Joe Coder

Anda harus mengubah dari -omenjadi -Ountuk menghindari kebingungan, seperti di GNU wget. Atau setidaknya kedua opsi harus valid.
erik

@ eric Saya tidak yakin ingin membuat wget.pypengganti di tempat untuk yang sebenarnya wget. Yang -osudah berperilaku berbeda - itu kompatibel dengan curlcara ini. Apakah catatan dalam dokumentasi membantu menyelesaikan masalah? Atau itu adalah fitur penting untuk utilitas dengan nama yang sesuai baris perintah?
anatoly techtonik

16

Berikut ini adalah panggilan yang paling sering digunakan untuk mengunduh file dengan 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)

Catatan: urlopendan urlretrieveternyata kinerjanya relatif buruk dengan mengunduh file besar (ukuran> 500 MB). requests.getmenyimpan file dalam memori hingga unduhan selesai.


14

Saya setuju dengan Corey, urllib2 lebih lengkap daripada urllib dan seharusnya menjadi modul yang digunakan jika Anda ingin melakukan hal-hal yang lebih kompleks, tetapi untuk membuat jawabannya lebih lengkap, urllib adalah modul yang lebih sederhana jika Anda hanya menginginkan dasar-dasarnya:

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

Akan bekerja dengan baik. Atau, jika Anda tidak ingin berurusan dengan objek "respons", Anda dapat memanggil read () secara langsung:

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

10

Dalam python3 Anda dapat menggunakan urllib3 dan libraires shutil. Unduh mereka dengan menggunakan pip atau pip3 (Tergantung apakah python3 default atau tidak)

pip3 install urllib3 shutil

Kemudian jalankan kode ini

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)

Perhatikan bahwa Anda mengunduh urllib3tetapi menggunakan urllibkode


7

Anda bisa mendapatkan umpan balik kemajuan dengan urlretrieve juga:

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

Jika Anda telah menginstal wget, Anda dapat menggunakan parallel_sync.

pip instal 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

Ini sangat kuat. Ia dapat mengunduh file secara paralel, mencoba lagi setelah kegagalan, dan bahkan dapat mengunduh file pada mesin jarak jauh.


Catatan ini hanya untuk Linux
jjj

4

Jika kecepatan penting bagi Anda, saya membuat tes kinerja kecil untuk modul urllibdan wget, dan wgetsaya mencoba sekali dengan status bar dan sekali tanpa. Saya mengambil tiga file 500MB berbeda untuk diuji dengan (file yang berbeda-untuk menghilangkan kemungkinan ada beberapa caching terjadi di bawah tenda). Diuji pada mesin debian, dengan python2.

Pertama, ini adalah hasilnya (mereka serupa dalam menjalankan berbeda):

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

Cara saya melakukan tes menggunakan dekorator "profil". Ini adalah kode lengkap:

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 tampaknya menjadi yang tercepat


Pasti ada sesuatu yang benar-benar mengerikan terjadi di bawah tenda untuk membuat bar menambah waktu begitu banyak.
Alistair Carscadden

4

Hanya demi kelengkapan, dimungkinkan juga untuk memanggil program apa pun untuk mengambil file menggunakan subprocesspaket. Program yang didedikasikan untuk mengambil file lebih kuat daripada fungsi Python urlretrieve. Misalnya, wgetdapat mengunduh direktori secara rekursif ( -R), dapat menangani FTP, arahan ulang, proxy HTTP, dapat menghindari mengunduh ulang file yang ada ( -nc), dan aria2dapat melakukan unduhan multi-koneksi yang berpotensi mempercepat unduhan Anda.

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

Di Jupyter Notebook, Anda juga dapat memanggil program secara langsung dengan !sintaks:

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

3

Kode sumber dapat:

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

3

Anda dapat menggunakan PycURL di Python 2 dan 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

Saya menulis yang berikut, yang bekerja di vanilla Python 2 atau 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()

Catatan:

  • Mendukung panggilan balik "progress bar".
  • Unduh adalah tes 4 MB .zip dari situs web saya.

bekerja hebat, jalankan melalui jupyter mendapatkan apa yang saya inginkan :-)
Samir Ouldsaadi

1

Ini mungkin agak terlambat, Tapi saya melihat kode pabloG dan tidak dapat membantu menambahkan sistem os.s ('cls') agar terlihat MENGAGUMKAN! Coba lihat :

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

Jika berjalan di lingkungan selain Windows, Anda harus menggunakan sesuatu selain 'cls'. Di MAC OS X dan Linux itu harus 'jelas'.


3
clstidak melakukan apa pun pada OS X saya atau pada server Ubuntu saya. Beberapa klarifikasi bisa bagus.
kqw

Saya pikir Anda harus menggunakan clearuntuk linux, atau bahkan lebih baik mengganti jalur cetak daripada menghapus seluruh output baris perintah.
Arijoon

4
jawaban ini hanya menyalin jawaban lain dan menambahkan panggilan ke fungsi yang tidak digunakan lagi ( os.system()) yang meluncurkan subproses untuk menghapus layar menggunakan perintah spesifik platform ( cls). Bagaimana ini setiap upvotes ?? IMHO "jawaban" sama sekali tidak berharga.
Corey Goldberg

1

urlretrieve dan requests.get sederhana, namun kenyataannya tidak. Saya telah mengambil data untuk beberapa situs, termasuk teks dan gambar, dua di atas mungkin menyelesaikan sebagian besar tugas. tetapi untuk solusi yang lebih universal saya sarankan penggunaan urlopen. Karena ini termasuk dalam pustaka standar Python 3, kode Anda bisa berjalan di mesin apa pun yang menjalankan Python 3 tanpa pra-instal paket-situs

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

Jawaban ini memberikan solusi untuk HTTP 403 Forbidden saat mengunduh file melalui http menggunakan Python. Saya telah mencoba hanya modul permintaan dan urllib, modul lain mungkin menyediakan sesuatu yang lebih baik, tetapi ini adalah yang saya gunakan untuk menyelesaikan sebagian besar masalah.


0

Jawaban terlambat, tetapi untuk python>=3.6Anda dapat menggunakan:

import dload
dload.save(url)

Instal dloaddengan:

pip3 install dload

0

Saya ingin mengunduh semua file dari halaman web. Saya mencoba wgettetapi gagal jadi saya memutuskan untuk rute Python dan saya menemukan utas ini.

Setelah membacanya, saya telah membuat aplikasi baris perintah kecil soupget, memperluas jawaban yang sangat baik dari PabloG dan Stan dan menambahkan beberapa opsi yang bermanfaat.

Ini menggunakan BeatifulSoup untuk mengumpulkan semua URL halaman dan kemudian unduh yang dengan ekstensi yang diinginkan. Akhirnya dapat mengunduh banyak file secara paralel.

Ini dia:

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

Contoh penggunaannya adalah:

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

Dan contoh aktual jika Anda ingin melihatnya beraksi:

python3 soupget.py -p -e .xlsx .pdf .csv -u https://healthdata.gov/dataset/chemicals-cosmetics
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.