

引言#
在当今互联网时代,数据采集已成为许多业务和技术研究的基础工作。本文将详细介绍一个实用的Python图片爬虫开发过程,该爬虫能够从目标网站随机获取页面,提取其中的图片资源,并自动整理保存到本地。我们将深入探讨爬虫的各个技术环节,包括随机页面获取、HTML解析、图片下载和本地文件管理等。
项目概述#
这个爬虫项目主要实现以下功能:
- 从目标网站随机获取一个页面
- 解析页面内容,提取标题和图片URL
- 对图片URL进行去重处理
- 创建本地目录并按顺序保存图片
- 自动打开保存图片的文件夹
技术栈分析#
1. 核心库介绍#
import os
import platform
import re
from pathlib import Path
from urllib.parse import urlparse
import requests
from bs4 import BeautifulSouppython- requests:用于发送HTTP请求,获取网页内容
- BeautifulSoup:HTML解析库,用于提取页面中的特定元素
- pathlib:提供面向对象的文件系统路径操作
- urllib.parse:用于URL解析和处理
- platform:获取操作系统信息,实现跨平台功能
2. 随机页面获取机制#
def get_random_page_url():
response = requests.get(f"{BASE_URL}/random.html", headers=HEADERS, timeout=10)
soup = BeautifulSoup(response.text, 'html.parser')
script = soup.find('script', string=lambda t: t and 'location=' in t)
return script.text.split('location="')[1].split('"')[0] if script else Nonepython这段代码通过访问网站的/random.html页面获取随机跳转链接,利用BeautifulSoup解析页面中的JavaScript跳转代码,提取目标URL。
3. 页面内容解析#
def extract_page_data(url):
response = requests.get(url, headers=HEADERS, timeout=10)
soup = BeautifulSoup(response.text, 'html.parser')
title = soup.find('h1', class_='text-xxl').get_text(strip=True)
images = [img['data-src'] for img in soup.find_all('img', {'data-src': True})]
return title, [img for img in images if img not in DUPLICATE_URLS]python这里我们:
- 通过CSS选择器定位标题元素
- 提取所有带有
data-src属性的图片标签 - 使用预设的
DUPLICATE_URLS集合进行URL去重
4. 文件名处理#
def sanitize_filename(filename):
title = re.sub(r'\s*\[\d+\]\s*$', '', filename.strip())
invalid_chars = '<>:"/\\|?*'
processed_title = []
for char in title:
processed_title.append('_' if char in invalid_chars else char)
return ''.join(processed_title).strip()python文件名处理包含三个关键步骤:
- 移除标题末尾的
[数字]格式内容 - 替换Windows文件名非法字符为下划线
- 去除首尾空白字符
5. 图片下载#
def download_image(url, path):
response = requests.get(url, headers=HEADERS, timeout=10, stream=True)
with open(path, 'wb') as f:
for chunk in response.iter_content(1024):
f.write(chunk)python使用stream=True参数实现流式下载,避免大文件占用过多内存,通过分块写入提高下载稳定性。
关键技术深度解析#
1. 反爬虫策略应对#
- User-Agent设置:模拟浏览器访问
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"
}python- 请求超时处理:避免长时间等待
requests.get(..., timeout=10)python- 异常处理机制:增强程序健壮性
try:
# 可能失败的代码
except Exception as e:
print(f"错误信息: {e}")python2. 跨平台文件处理#
def open_folder(path):
if platform.system() == "Windows":
os.startfile(path)
elif platform.system() == "Darwin":
os.system(f'open "{path}"')
else:
os.system(f'xdg-open "{path}"')python根据操作系统类型选择不同的命令打开文件管理器,提升用户体验。
3. 性能优化实践#
- URL去重:使用集合(Set)实现高效查找
DUPLICATE_URLS = {
"https://pic1.imgdb.cn/item/67f9c15f88c538a9b5cb7a98.jpg",
# 其他已知重复URL...
}python- 流式下载:节省内存,支持大文件
response = requests.get(..., stream=True)
for chunk in response.iter_content(1024):
# 处理数据块python项目扩展思路#
- 多线程下载:使用
concurrent.futures实现并行下载,提高效率 - 断点续传:记录下载进度,支持中断后继续
- 代理支持:添加代理池应对IP封锁
- GUI界面:使用PyQt或Tkinter开发图形界面
- 自动压缩:下载完成后打包为ZIP文件
完整代码下载#
import os
import platform
import re
from pathlib import Path
from urllib.parse import urlparse
import requests
from bs4 import BeautifulSoup
# 请求头配置
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"
}
BASE_URL = "https://www.jk.rs"
DUPLICATE_URLS = {
"https://pic1.imgdb.cn/item/67f9c15f88c538a9b5cb7a98.jpg",
"https://pic.imgdb.cn/item/675fcf9bd0e0a243d4e487f2.webp",
"https://pic.imgdb.cn/item/675fd214d0e0a243d4e48999.webp",
"https://pic1.imgdb.cn/item/67fc873988c538a9b5cf9e84.jpg",
"https://pic.imgdb.cn/item/676ba651d0e0a243d4e9d3aa.webp",
"https://pic.imgdb.cn/item/6767d6d8d0e0a243d4e8043f.webp",
"https://pic.imgdb.cn/item/6767d846d0e0a243d4e804b5.webp",
"https://pic.imgdb.cn/item/675fd089d0e0a243d4e48879.webp"
}
def get_random_page_url():
"""获取随机页面URL"""
try:
response = requests.get(f"{BASE_URL}/random.html", headers=HEADERS, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
script = soup.find('script', string=lambda t: t and 'location=' in t)
return script.text.split('location="')[1].split('"')[0] if script else None
except Exception as e:
print(f"获取随机页面失败: {e}")
return None
def extract_page_data(url):
"""提取页面中的标题和图片URL"""
try:
response = requests.get(url, headers=HEADERS, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
# 提取标题
title = soup.find('h1', class_='text-xxl').get_text(strip=True)
for sup in soup.find_all('sup'):
sup.decompose()
# 提取图片URL并去重
images = [img['data-src'] for img in soup.find_all('img', {'data-src': True})]
return title, [img for img in images if img not in DUPLICATE_URLS]
except Exception as e:
print(f"解析页面失败: {e}")
return None, []
def sanitize_filename(filename):
"""处理文件名的非法字符和末尾的[数字]内容"""
if not filename:
return "未命名"
# 移除末尾的[数字]内容
title = re.sub(r'\s*\[\d+\]\s*$', '', filename.strip())
# 替换文件名非法字符
invalid_chars = '<>:"/\\|?*'
processed_title = []
for char in title:
if char in invalid_chars:
processed_title.append('_')
else:
processed_title.append(char)
# 去除首尾空白并返回
return ''.join(processed_title).strip()
def download_image(url, path):
"""下载图片"""
try:
response = requests.get(url, headers=HEADERS, timeout=10, stream=True)
response.raise_for_status()
with open(path, 'wb') as f:
for chunk in response.iter_content(1024):
f.write(chunk)
return True
except Exception as e:
print(f"下载失败 {url}: {e}")
return False
def open_folder(path):
"""跨平台打开文件夹"""
try:
if platform.system() == "Windows":
os.startfile(path)
elif platform.system() == "Darwin": # macOS
os.system(f'open "{path}"')
else: # Linux
os.system(f'xdg-open "{path}"')
except Exception as e:
print(f"无法打开文件夹: {e}")
def main():
"""主执行函数"""
# 获取随机页面
page_url = get_random_page_url()
if not page_url:
print("无法获取随机页面,程序退出")
return
print(f"开始处理页面: {page_url}")
# 提取页面数据
title, image_urls = extract_page_data(page_url)
if not title or not image_urls:
print("未找到有效数据,程序退出")
return
# 创建保存目录
clean_title = sanitize_filename(title)
save_dir = Path(clean_title)
save_dir.mkdir(parents=True, exist_ok=True)
print(f"创建目录: {save_dir}")
# 下载图片
success = 0
for i, url in enumerate(image_urls, 1):
ext = os.path.splitext(urlparse(url).path)[1] or '.jpg'
filename = f"{i}{ext}"
filepath = save_dir / filename
print(f"正在下载 ({i}/{len(image_urls)}): {url}")
if download_image(url, filepath):
success += 1
print(f"\n下载完成! 成功下载 {success}/{len(image_urls)} 张图片")
print(f"图片保存在: {save_dir.absolute()}")
open_folder(save_dir.absolute())
if __name__ == "__main__":
main()
python结语#
本文详细讲解了一个实用网站图片爬虫的开发过程,涵盖了从页面获取、内容解析到文件保存的完整流程。通过这个项目,我们不仅学习了Python网络爬虫的基础技术,还探讨了反爬虫策略、跨平台开发和性能优化等进阶话题。读者可以根据实际需求扩展功能,打造更强大的数据采集工具。
注意事项:在实际使用爬虫时,请遵守目标网站的robots.txt协议和相关法律法规,尊重网站的数据版权和访问限制。