Download afbeeldingen en andere bestanden van het web in Python (individueel of in batches)

Bedrijf

Hieronder wordt uitgelegd hoe je in Python de URL van een afbeelding, ZIP, PDF, of ander bestand op het Web kunt opgeven, het kunt downloaden en het als een lokaal bestand kunt opslaan.

  • Download afbeeldingen door de URL op te geven.
    • Code voorbeeld
    • urllib.request.urlopen():Open URL
    • open():Schrijven naar een bestand in binaire modus
    • Een eenvoudiger code voorbeeld
  • Download ZIP-bestanden, PDF-bestanden, enz.
  • Extraheer de URL van de afbeelding op de webpagina.
    • Als het nummer opeenvolgend is
    • Extract met Beautiful Soup
  • Batch download meerdere afbeeldingen van een lijst van URL's

Download afbeeldingen door de URL op te geven.

U kunt de standaardbibliotheek alleen gebruiken om afzonderlijke bestanden te downloaden door hun URL's op te geven; er is geen extra installatie vereist.

Code voorbeeld

Het volgende is een voorbeeld van een functie die een bestand download en opslaat door de URL en het bestemmingspad op te geven, en het gebruik ervan. Deze code is een beetje langdradig omwille van de uitleg. Een eenvoudig voorbeeld wordt hieronder gegeven.

import os
import pprint
import time
import urllib.error
import urllib.request

def download_file(url, dst_path):
    try:
        with urllib.request.urlopen(url) as web_file:
            data = web_file.read()
            with open(dst_path, mode='wb') as local_file:
                local_file.write(data)
    except urllib.error.URLError as e:
        print(e)
url = 'https://www.python.org/static/img/python-logo.png'
dst_path = 'data/temp/py-logo.png'
download_file(url, dst_path)

Om de bestemmingsdirectory te specificeren en het bestand op te slaan met de URL-bestandsnaam, doet u het volgende

def download_file_to_dir(url, dst_dir):
    download_file(url, os.path.join(dst_dir, os.path.basename(url)))

dst_dir = 'data/temp'
download_file_to_dir(url, dst_dir)

Het haalt de bestandsnaam uit de URL met os.path.basename() en voegt deze samen met de directory opgegeven met os.path.join() om het bestemmingspad te genereren.

De volgende secties beschrijven het deel van de gegevensverwerving en het deel van de gegevensopslag als een bestand.

urllib.request.urlopen(): Open URL

Gebruik urllib.request.urlopen() om de URL te openen en de data op te halen. Merk op dat urllib.urlopen() is afgeschreven in Python 2.6 en eerder. urllib.request.urlretrieve() is nog niet afgeschreven, maar kan dat in de toekomst wel worden.

Om te voorkomen dat je stopt als er een exception optreedt, vang je de fout op met try en except.

In het voorbeeld wordt urllib.error geïmporteerd en alleen urllib.error.URLError wordt expliciet opgevangen. De foutmelding wordt getoond als de URL van het bestand niet bestaat.

url_error = 'https://www.python.org/static/img/python-logo_xxx.png'
download_file_to_dir(url_error, dst_dir)
# HTTP Error 404: Not Found

Als u ook uitzonderingen wilt opvangen (FileNotFoundError, enz.) bij het lokaal opslaan, doe dan het volgende.
(urllib.error.URLError, FileNotFoundError)

Het is ook mogelijk om de derde partij bibliotheek Requests te gebruiken in plaats van de standaard bibliotheek urllib om de url te openen en de gegevens op te halen.

Schrijf naar een bestand in binaire modus in open()

De gegevens die kunnen worden verkregen met urllib.request.urlopen() is een byte string (type bytes).

Open() met mode='wb' als tweede argument schrijft de gegevens als binair. w betekent schrijven en b betekent binair.

Een eenvoudiger code voorbeeld

Geneste met statements kunnen in één keer worden geschreven, gescheiden door komma's.

Hiermee kunnen we het volgende schrijven.

def download_file(url, dst_path):
    try:
        with urllib.request.urlopen(url) as web_file, open(dst_path, 'wb') as local_file:
            local_file.write(web_file.read())
    except urllib.error.URLError as e:
        print(e)

Download ZIP-bestanden, PDF-bestanden, enz.

De voorbeelden tot nu toe zijn voor het downloaden en opslaan van afbeeldingsbestanden, maar aangezien we gewoon een bestand op het web openen en het opslaan als een lokaal bestand, kunnen dezelfde functies ook voor andere soorten bestanden worden gebruikt.

U kunt bestanden downloaden en opslaan door de URL op te geven.

url_zip = 'https://from-locas.com/sample_header.csv.zip'
download_file_to_dir(url_zip, dst_dir)

url_xlsx = 'https://from-locas/sample.xlsx'
download_file_to_dir(url_xlsx, dst_dir)

url_pdf = 'https://from-locas/sample1.pdf'
download_file_to_dir(url_pdf, dst_dir)

Merk op dat de URL die in deze functie gespecificeerd wordt, een link naar het bestand zelf moet zijn.

Bijvoorbeeld, in het geval van een GitHub repository bestand, de volgende URL heeft een pdf extensie maar is eigenlijk een html pagina. Als deze URL wordt gespecificeerd in de functie hierboven, zal de html bron worden gedownload.

  • https://github.com/from-locals/python-snippets/blob/master/notebook/data/src/pdf/sample1.pdf

De link naar de bestandsentiteit is de volgende URL, die u moet opgeven als u het bestand wilt downloaden en opslaan.

  • https://github.com/from-locals/python-snippets/raw/master/notebook/data/src/pdf/sample1.pdf

Er zijn ook gevallen waarin de toegang wordt beperkt door user agent, referrer, enz., waardoor het onmogelijk is om te downloaden. Wij garanderen niet dat alle bestanden zullen worden gedownload.

Het is eenvoudig om Requests te gebruiken om request headers, zoals user agent, te wijzigen of toe te voegen.

Extraheer de URL van de afbeelding op de webpagina.

Om alle afbeeldingen op een pagina in één keer te downloaden, haalt u eerst de URL's van de afbeeldingen eruit en maakt u een lijst.

Als het nummer opeenvolgend is

Als de URL van de afbeelding die je wilt downloaden een eenvoudig opeenvolgend nummer is, is het gemakkelijk. Als de URL's niet alleen opeenvolgende nummers zijn, maar ook enige regelmaat vertonen, is het eenvoudiger om een lijst van URL's te maken volgens de regels in plaats van te schrapen met Beautiful Soup (zie hieronder).

Gebruik lijst begrip notatie.

url_list = ['https://example.com/basedir/base_{:03}.jpg'.format(i) for i in range(5)]
pprint.pprint(url_list)
# ['https://example.com/basedir/base_000.jpg',
#  'https://example.com/basedir/base_001.jpg',
#  'https://example.com/basedir/base_002.jpg',
#  'https://example.com/basedir/base_003.jpg',
#  'https://example.com/basedir/base_004.jpg']

In het bovenstaande voorbeeld wordt {:03} gebruikt voor een oplopend getal van 3 cijfers dat met nullen is gevuld; {} wordt gebruikt als het vullen met nullen niet nodig is, en {:05} wordt gebruikt voor een getal van 5 cijfers in plaats van 3 cijfers. Voor meer informatie over de format methode van string str, zie het volgende artikel.

Ook gebruiken we hier pprint om de uitvoer leesbaarder te maken.

Extract met Beautiful Soup

Om afbeeldings-URL's van webpagina's in bulk te extraheren, gebruik je Beautiful Soup.

import os
import time
import urllib.error
import urllib.request

from bs4 import BeautifulSoup

url = 'https://nl.from-locals.com/'
ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) '\
     'AppleWebKit/537.36 (KHTML, like Gecko) '\
     'Chrome/55.0.2883.95 Safari/537.36 '

req = urllib.request.Request(url, headers={'User-Agent': ua})
html = urllib.request.urlopen(req)

soup = BeautifulSoup(html, "html.parser")

url_list = [img.get('data-src') for img in soup.find(class_='list').find_all('img')]

In het voorbeeld wordt de URL van de miniatuurafbeelding van deze website geëxtraheerd.

De structuur varieert naar gelang van de webpagina, maar in principe wordt hij als volgt verkregen.

  • Verkrijg een lijst van <img> tag objecten door de klasse, id, enz. op te geven van het blok dat de meervoudige afbeeldingen bevat die je wilt downloaden.
    • soup.find(class_='list').find_all('img')
  • Verkrijg de URL van de afbeelding uit het src element of data-src element van de <img> tag.
    • img.get('data-src')

De bovenstaande voorbeeldcode is slechts een voorbeeld en werkt niet gegarandeerd.

Batch download meerdere afbeeldingen van een lijst van URL's

Als je een lijst met URL's hebt, kun je die gewoon in een for-lus draaien en de functie aanroepen om het bestand met de eerst getoonde URL te downloaden en op te slaan. Vanwege de tijdelijke URL lijst, is de functie aanroep download_image_dir() hier becommentarieerd.

download_dir = 'data/temp'
sleep_time_sec = 1

for url in url_list:
    print(url)
#     download_file_dir(url, download_dir)
    time.sleep(sleep_time_sec)
# https://example.com/basedir/base_000.jpg
# https://example.com/basedir/base_001.jpg
# https://example.com/basedir/base_002.jpg
# https://example.com/basedir/base_003.jpg
# https://example.com/basedir/base_004.jpg

Om de server niet te overbelasten, gebruik ik time.sleep() om een wachttijd te creëren voor elke download van een afbeelding. De eenheid is in seconden, dus in het bovenstaande voorbeeld is de tijdmodule geïmporteerd en gebruikt.

Het voorbeeld is voor afbeeldingsbestanden, maar andere soorten bestanden kunnen ook samen worden gedownload, zolang ze maar in de lijst staan.