下面解释了如何在Python中指定网络上的图像、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()可以获得的数据是一个字节字符串(字节类型)。
Open()的第二个参数是mode='wb',将数据写成二进制。
一个更简单的代码例子
嵌套的with语句可以一次写完,用逗号分开。
利用这一点,我们可以写出以下内容。
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文件等。
到目前为止的例子是下载和保存图像文件,但由于我们只是在网上打开一个文件并将其保存为本地文件,所以同样的功能也可以用于其他类型的文件。
你可以通过指定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,如果你想下载和保存文件,你需要指定这个URL。
- https://github.com/from-locals/python-snippets/raw/master/notebook/data/src/pdf/sample1.pdf
还有一些情况是,访问受到用户代理、推荐人等的限制,使其无法下载。我们不保证所有文件都能被下载。
使用Request来改变或添加请求头,如用户代理,是很容易的。
提取网页上的图像的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://cn.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被提取出来。
其结构因网页而异,但基本上是按以下方式获得。
- 通过指定包含你想下载的多张图片的块的类别、ID等,获得一个<img>标签对象的列表。
soup.find(class_='list').find_all('img')
- 从<img>标签的src元素或data-src元素获取图片的URL。
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()为每个图片下载创建一个等待时间。单位是秒,所以在上面的例子中,时间模块被导入并使用。
这个例子是针对图像文件的,但其他类型的文件也可以一起下载,只要它们被列出。