大家好,我是何三,80后老猿,独立开发者。
继续我们的"5分钟Python自动化"系列。今天我们来解决一个网络资源收集的刚需——批量下载网页图片。
有这样的场景:你在做一个设计项目,需要大量参考图片;你在收集某个主题的资料,网页上有上百张相关图片;你想备份某个网站的所有产品图片;或者你看到了一个很棒的图片合集,想要全部保存到本地...
传统做法:右键另存为,一张一张保存,遇到几十上百张图片时,手指都要点抽筋,还容易出错漏掉。
Python做法:15行代码,3秒钟,自动识别网页所有图片,一键批量下载到本地!
今天,我就带你用5分钟,掌握这个让你成为"资源收割机"的神奇技能!
环境准备:两个命令搞定
在开始之前,你只需要:
- 安装Python(这个已经装好了)
- 安装必要的库:打开命令行,依次输入:
pip install requests
pip install beautifulsoup4
这两个库分别是:
- requests:HTTP请求库,用来获取网页内容
- beautifulsoup4:HTML解析库,用来提取图片链接
核心代码:15行图片批量下载器
让我们先看看这个最简单的"图片收割机":
import requests
from bs4 import BeautifulSoup
import os
def download_images(url, save_folder='images'):
"""下载网页上的所有图片"""
# 创建保存文件夹
os.makedirs(save_folder, exist_ok=True)
# 获取网页内容
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
# 查找所有图片标签
img_tags = soup.find_all('img')
# 下载每张图片
for i, img in enumerate(img_tags):
img_url = img.get('src')
if img_url: # 确保有图片链接
# 补全相对链接
if not img_url.startswith('http'):
img_url = url + img_url if img_url.startswith('/') else url + '/' + img_url
try:
# 下载图片
img_data = requests.get(img_url).content
# 保存图片
img_name = f'image_{i+1}.jpg'
img_path = os.path.join(save_folder, img_name)
with open(img_path, 'wb') as f:
f.write(img_data)
print(f'已下载: {img_name}')
except Exception as e:
print(f'下载失败: {img_url} - {e}')
# 使用示例
download_images('https://www.h3blog.com')
逐行详解:理解图片下载的原理
第1-3行:导入核心工具箱
import requests
from bs4 import BeautifulSoup
import os
requests:负责网络请求,像浏览器一样获取网页数据BeautifulSoup:负责解析HTML,像剪刀一样提取图片链接os:负责文件操作,创建文件夹和保存文件
第5-9行:定义下载函数
def download_images(url, save_folder='images'):
"""下载网页上的所有图片"""
# 创建保存文件夹
os.makedirs(save_folder, exist_ok=True)
url:要下载图片的网页地址save_folder:保存图片的文件夹名os.makedirs():创建文件夹,exist_ok=True表示如果文件夹已存在也不报错
第11-15行:获取并解析网页
# 获取网页内容
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
# 查找所有图片标签
img_tags = soup.find_all('img')
requests.get(url):发送HTTP请求,获取网页源代码BeautifulSoup(response.text, 'html.parser'):将网页源代码转换成可解析的对象soup.find_all('img'):找到网页中所有的<img>标签
第17-35行:下载每张图片
for i, img in enumerate(img_tags):
img_url = img.get('src')
if img_url: # 确保有图片链接
# 补全相对链接
if not img_url.startswith('http'):
img_url = url + img_url if img_url.startswith('/') else url + '/' + img_url
try:
# 下载图片
img_data = requests.get(img_url).content
# 保存图片
img_name = f'image_{i+1}.jpg'
img_path = os.path.join(save_folder, img_name)
with open(img_path, 'wb') as f:
f.write(img_data)
print(f'已下载: {img_name}')
except Exception as e:
print(f'下载失败: {img_url} - {e}')
关键步骤分解:
- 提取图片链接:
img.get('src')获取<img>标签的src属性值 - 处理相对链接:如果是相对路径(如
/images/pic.jpg),需要补全为完整URL - 下载图片数据:
requests.get(img_url).content获取图片的二进制数据 - 保存到文件:以二进制写入模式(
'wb')保存图片 - 错误处理:使用
try-except捕获下载失败的情况
实战演示:3秒批量下载图片
- 保存脚本:将上面的代码保存为
download_images.py - 修改URL:把
https://example.com换成你想下载图片的网页地址 - 运行脚本:打开命令行,输入:
python download_images.py
- 查看结果:当前目录会创建一个
images文件夹,里面就是下载的所有图片!
运行效果:
已下载: image_1.jpg
已下载: image_2.jpg
已下载: image_3.jpg
...
下载失败: https://example.com/ad.jpg - 404 Not Found
总共下载了: 25张图片
举一反三:高级图片下载功能
案例1:下载特定尺寸的图片
def download_large_images(url, min_width=400, min_height=300):
"""只下载大尺寸图片"""
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
for img in soup.find_all('img'):
img_url = img.get('src')
img_width = img.get('width')
img_height = img.get('height')
# 检查图片尺寸
if img_width and img_height:
if int(img_width) >= min_width and int(img_height) >= min_height:
# 下载大图
download_single_image(img_url)
案例2:按类别下载图片
def download_by_category(url, categories):
"""按类别下载图片"""
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
for img in soup.find_all('img'):
img_url = img.get('src')
alt_text = img.get('alt', '').lower() # 获取alt文本
for category in categories:
if category in alt_text or category in img_url:
# 按类别创建文件夹
category_folder = os.path.join('images', category)
os.makedirs(category_folder, exist_ok=True)
# 下载图片到对应文件夹
download_to_folder(img_url, category_folder)
break
案例3:从多个网页批量下载
def download_from_multiple_pages(base_url, page_count):
"""从多个页面下载图片"""
all_images = []
for page in range(1, page_count + 1):
# 构造每个页面的URL
page_url = f'{base_url}?page={page}'
print(f'正在处理第 {page} 页...')
# 获取当前页面的图片
page_images = get_images_from_page(page_url)
all_images.extend(page_images)
# 下载所有图片
for i, img_url in enumerate(all_images):
download_single_image(img_url, f'image_{i+1}.jpg')
print(f'进度: {i+1}/{len(all_images)}')
print(f'下载完成!共下载了 {len(all_images)} 张图片')
案例4:下载高清原图
def download_hd_images(url):
"""下载高清原图(通常data-src属性存放原图)"""
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
for img in soup.find_all('img'):
# 优先使用data-src(通常是高清图)
hd_url = img.get('data-src') or img.get('data-original')
if hd_url:
# 下载高清图
download_single_image(hd_url, prefix='hd_')
else:
# 回退到普通src
normal_url = img.get('src')
if normal_url:
download_single_image(normal_url)
进阶技巧:企业级图片下载系统
添加请求头模拟浏览器
def download_with_headers(url):
"""使用请求头模拟浏览器访问"""
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Accept-Encoding': 'gzip, deflate',
'Connection': 'keep-alive',
}
# 使用请求头访问
response = requests.get(url, headers=headers)
# ... 后续处理
多线程加速下载
import threading
from concurrent.futures import ThreadPoolExecutor
def download_images_fast(url, max_workers=5):
"""多线程快速下载图片"""
# 获取所有图片链接
img_urls = get_all_image_urls(url)
# 使用线程池并发下载
with ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = []
for i, img_url in enumerate(img_urls):
future = executor.submit(download_single_image, img_url, f'image_{i+1}.jpg')
futures.append(future)
# 等待所有任务完成
for future in futures:
future.result()
print(f'快速下载完成!共下载 {len(img_urls)} 张图片')
断点续传功能
def download_with_resume(url, filename):
"""支持断点续传的下载"""
# 检查文件是否已部分下载
if os.path.exists(filename):
file_size = os.path.getsize(filename)
headers = {'Range': f'bytes={file_size}-'}
else:
file_size = 0
headers = {}
# 从断点处继续下载
response = requests.get(url, headers=headers, stream=True)
with open(filename, 'ab' if file_size > 0 else 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
print(f'下载完成: {filename}')
图片去重功能
import hashlib
def get_image_hash(img_data):
"""计算图片的哈希值(用于去重)"""
return hashlib.md5(img_data).hexdigest()
def download_unique_images(url):
"""下载不重复的图片"""
downloaded_hashes = set() # 存储已下载图片的哈希值
img_urls = get_all_image_urls(url)
for img_url in img_urls:
try:
# 下载图片
response = requests.get(img_url, timeout=10)
img_data = response.content
# 计算哈希值
img_hash = get_image_hash(img_data)
# 检查是否重复
if img_hash not in downloaded_hashes:
# 保存图片
save_image(img_data, img_url)
downloaded_hashes.add(img_hash)
print(f'下载新图片: {img_url}')
else:
print(f'跳过重复图片: {img_url}')
except Exception as e:
print(f'下载失败: {img_url} - {e}')
实用场景:图片下载的多种应用
场景1:下载电商网站产品图
def download_product_images(shop_url, product_count=50):
"""下载电商网站产品图片"""
# 模拟真实浏览器访问
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Referer': shop_url
}
# 分析网站结构,获取产品图片
response = requests.get(shop_url, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
# 根据网站结构选择正确的选择器
product_images = []
# 常见电商网站图片选择器
selectors = [
'.product-image img',
'.goods-img',
'.item-img',
'[data-product-image]'
]
for selector in selectors:
images = soup.select(selector)
if images:
product_images.extend([img.get('src') for img in images])
break
# 下载产品图片
for i, img_url in enumerate(product_images[:product_count]):
# 通常产品图有高清版本
hd_url = img_url.replace('thumbnail', 'original').replace('small', 'large')
download_single_image(hd_url, f'product_{i+1}.jpg')
场景2:下载壁纸网站高清壁纸
def download_wallpapers(wallpaper_site, resolution='1920x1080'):
"""下载指定分辨率的壁纸"""
# 构造壁纸下载URL(不同网站格式不同)
if 'wallhaven' in wallpaper_site:
# wallhaven.cc
search_url = f'{wallpaper_site}/search?q=&resolutions={resolution}'
elif 'unsplash' in wallpaper_site:
# unsplash.com
search_url = f'{wallpaper_site}/s/photos/desktop-wallpaper?orientation=landscape'
# 获取壁纸链接
response = requests.get(search_url)
soup = BeautifulSoup(response.text, 'html.parser')
# 下载壁纸
wallpaper_count = 0
for img in soup.find_all('img'):
img_url = img.get('src')
# 检查是否是壁纸图片
if img_url and ('wallpaper' in img_url or resolution in img_url):
download_single_image(img_url, f'wallpaper_{wallpaper_count+1}.jpg')
wallpaper_count += 1
if wallpaper_count >= 20: # 限制下载数量
break
print(f'下载了 {wallpaper_count} 张 {resolution} 壁纸')
场景3:批量下载社交媒体图片
def download_social_media_images(profile_url, platform='instagram'):
"""下载社交媒体图片"""
# 不同平台需要不同的处理方法
if platform == 'instagram':
# Instagram图片通常在meta标签中
response = requests.get(profile_url)
# 使用正则表达式提取图片URL
import re
image_patterns = [
r'"display_url":"([^"]+)"', # Instagram JSON格式
r'property="og:image" content="([^"]+)"' # Open Graph
]
all_images = []
for pattern in image_patterns:
matches = re.findall(pattern, response.text)
all_images.extend(matches)
elif platform == 'pinterest':
# Pinterest使用不同的数据结构
soup = BeautifulSoup(response.text, 'html.parser')
all_images = []
for img in soup.select('img[src*="pinimg.com"]'):
img_url = img.get('src')
# 获取原图(去除尺寸参数)
original_url = img_url.split('?')[0]
all_images.append(original_url)
# 下载所有图片
for i, img_url in enumerate(set(all_images)): # 使用set去重
download_single_image(img_url, f'{platform}_{i+1}.jpg')
注意事项与最佳实践
1. 遵守robots.txt和网站条款
def check_robots_txt(url):
"""检查robots.txt文件"""
from urllib.parse import urlparse
# 获取网站根域名
parsed_url = urlparse(url)
robots_url = f'{parsed_url.scheme}://{parsed_url.netloc}/robots.txt'
try:
response = requests.get(robots_url)
print(f"robots.txt内容:\n{response.text[:500]}...")
# 检查是否允许爬取
if 'Disallow: /' in response.text:
print("警告:该网站可能禁止爬取!")
except:
print("未找到robots.txt文件")
2. 添加延迟避免被封IP
import time
import random
def download_with_delay(url, delay_range=(1, 3)):
"""添加随机延迟下载"""
img_urls = get_all_image_urls(url)
for i, img_url in enumerate(img_urls):
# 下载图片
download_single_image(img_url)
# 添加随机延迟
delay = random.uniform(delay_range[0], delay_range[1])
time.sleep(delay)
print(f'进度: {i+1}/{len(img_urls)},等待 {delay:.1f} 秒')
3. 错误重试机制
def download_with_retry(img_url, max_retries=3):
"""带有重试机制的下载"""
for attempt in range(max_retries):
try:
response = requests.get(img_url, timeout=10)
response.raise_for_status() # 检查HTTP错误
# 保存图片
with open(f'image.jpg', 'wb') as f:
f.write(response.content)
print(f'下载成功: {img_url}')
return True
except Exception as e:
print(f'第 {attempt+1} 次尝试失败: {e}')
if attempt < max_retries - 1:
wait_time = 2 ** attempt # 指数退避
print(f'等待 {wait_time} 秒后重试...')
time.sleep(wait_time)
print(f'下载失败,已达到最大重试次数: {img_url}')
return False
结语:让网络资源为你所用
恭喜!在又一个5分钟内,你掌握了一个强大的网络资源收集技能:
✅ 用15行代码批量下载网页图片
✅ 掌握requests和BeautifulSoup的基本使用
✅ 学会处理相对链接和错误情况
✅ 具备构建高级下载系统的能力
今天你学会的不仅仅是下载图片,而是掌握了自动化获取网络资源的方法论。
想象一下,你还可以: - 批量下载某个主题的所有参考图片 - 自动备份你喜欢的网站图片资源 - 为机器学习项目收集训练图片 - 监控竞争对手的产品图片更新 - 构建自己的图片素材库
信息时代,重要的不是拥有多少资源,而是知道如何快速获取需要的资源。
现在,就找一个你感兴趣的网站,试试批量下载它的图片吧!在评论区分享你下载了什么有趣的图片,或者遇到了什么挑战!
记得关注我,下一篇我们挑战更有趣的Python自动化技巧!