下面介紹如何在Python中指定Web上的圖像、ZIP、PDF或其他文件的URL,下載並保存為本地文件。
- 通過指定 URL 下載圖像。
- 代碼示例
urllib.request.urlopen()
:打開網址open()
:以二進制模式寫入文件- 一個更簡單的代碼示例
- 下載 ZIP 文件、PDF 文件等。
- 提取網頁上圖像的 URL。
- 如果數字是連續的
- 用美麗的湯提取
- 從 URL 列表中批量下載多個圖像
通過指定 URL 下載圖像。
您只能使用標準庫通過指定 URL 來下載單個文件;無需額外安裝。
代碼示例
以下是通過指定 URL 和目標路徑下載和保存文件的函數及其用法的示例。為了便於解釋,這段代碼有點冗長。下面給出一個簡單的例子。
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)
要指定目標目錄並使用 URL 文件名保存文件,請執行以下操作
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)
它使用 os.path.basename() 從 URL 中提取文件名,並將其與 os.path.join() 指定的目錄連接以生成目標路徑。
下面分別介紹數據採集的部分和數據保存為文件的部分。
urllib.request.urlopen():打開網址
使用 urllib.request.urlopen() 打開 URL 並檢索數據。請注意, urllib.urlopen() 在 Python 2.6 及更早版本中已被棄用。 urllib.request.urlretrieve() 尚未棄用,但將來可能會棄用。
為避免在發生異常時停止,請使用 try 和 except 捕獲錯誤。
在示例中,導入了 urllib.error,並且僅顯式捕獲了 urllib.error.URLError。當文件的 URL 不存在時,將顯示錯誤消息。
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
如果您還想在本地保存時捕獲異常(FileNotFoundError 等),請執行以下操作。(urllib.error.URLError, FileNotFoundError)
也可以使用第三方庫Requests代替標準庫urllib來打開url獲取數據。
在 open() 中以二進制模式寫入文件
使用 urllib.request.urlopen() 可以獲得的數據是一個字節串(bytes 類型)。
以 mode=’wb’ 作為第二個參數的 Open() 將數據寫入二進制。 w 表示寫入,b 表示二進制。
一個更簡單的代碼示例
嵌套語句可以一次寫入,用逗號分隔。
使用它,我們可以編寫以下內容。
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)
下載 ZIP 文件、PDF 文件等。
到目前為止的示例是下載和保存圖像文件,但由於我們只是在 Web 上打開一個文件並將其保存為本地文件,因此相同的功能可以用於其他類型的文件。
您可以通過指定 URL 下載和保存文件。
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)
請注意,此函數中指定的 URL 必須是指向文件本身的鏈接。
例如,在 GitHub 存儲庫文件的情況下,以下 URL 具有 pdf 擴展名但實際上是一個 html 頁面。如果在上面的函數中指定了這個 URL,將下載 html 源代碼。
- https://github.com/from-locals/python-snippets/blob/master/notebook/data/src/pdf/sample1.pdf
文件實體的鏈接是以下 URL,如果要下載和保存文件,則需要指定該鏈接。
- https://github.com/from-locals/python-snippets/raw/master/notebook/data/src/pdf/sample1.pdf
也有被user agent、referrer等限制訪問,導致無法下載的情況。我們不保證會下載所有文件。
很容易使用 Requests 來更改或添加請求標頭,例如用戶代理。
提取網頁上圖像的 URL。
要一次下載頁面中的所有圖像,首先提取圖像的 URL 並創建一個列表。
如果數字是連續的
如果您要下載的圖像的 URL 是一個簡單的序列號,則很容易。如果 URL 不僅是序列號,而且還具有一定的規律性,那麼按照規則製作 URL 列表比用 Beautiful Soup 抓取更容易(見下文)。
使用列表理解符號。
- 相關文章:使用 Python 列表推導式表示法
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']
在上面的例子中,{:03} 用於 3 位零填充的序列號; {} 用於不需要填零時,{:05} 用於 5 位數字而不是 3 位數字。關於字符串str的格式化方法的更多信息,請參見下面的文章。
此外,這裡我們使用 pprint 使輸出更易於閱讀。
用美麗的湯提取
要從網頁中批量提取圖像 URL,請使用 Beautiful Soup。
import os import time import urllib.error import urllib.request from bs4 import BeautifulSoup url = 'https://tw.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')]
在示例中,提取了該網站的縮略圖的 URL。
結構因網頁而異,但基本上按如下方式獲得。
- 獲取 <img> 的列表通過指定包含要下載的多個圖像的塊的類、ID 等來標記對象。
soup.find(class_='list').find_all('img')
- 從
img.get('data-src')
上面的示例代碼只是一個例子,不能保證工作。
從 URL 列表中批量下載多個圖像
如果您有一個 URL 列表,您可以將它放入一個 for 循環並調用該函數來下載並保存顯示第一個 URL 的文件。由於臨時的 URL 列表,函數調用 download_image_dir() 在這裡被註釋掉。
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
為了不讓服務器過載,我使用 time.sleep() 為每個圖像下載創建一個等待時間。單位為秒,因此在上面的示例中,導入並使用了時間模塊。
這個例子是針對圖像文件的,但其他類型的文件也可以一起下載,只要它們被列出。