每次旅行结束,相机和手机里总会塞满几百甚至上千张照片:风景、美食、自拍、随手拍混杂在一起,想要按行程整理成相册,往往要在电脑前坐上大半天。其实这件事完全可以交给程序去做。一个照片自动整理Agent,能够读取每张照片的拍摄时间和GPS信息,识别照片内容属于哪种场景,然后自动建立类似“Day1-杭州西湖”这样的文件夹,把照片分门别类放进去。本文就从原理到代码,完整讲解如何用Python实现这样一个Agent。

一、自动整理的核心原理:EXIF元数据加图像识别
照片自动整理的基础是照片自带的元数据。绝大多数手机和相机拍摄的照片都包含EXIF(Exchangeable Image File)信息,其中记录了拍摄时间、GPS经纬度、设备型号、光圈快门等数据。只要解析出拍摄时间,就能把照片按天分组;解析出GPS坐标,就能通过逆地理编码反查出拍摄地点的城市甚至景点名称。
但仅有EXIF还不够。GPS在室内可能失效,而且“时间加地点”无法区分同一地点下的风景照、人物照和美食照。因此一个完整的整理Agent还需要引入图像识别能力,判断照片的内容类别,作为归类的辅助维度。目前主流做法有两种:一是调用云端图像识别API(如百度AI、阿里云视觉智能开放平台的场景识别接口),识别准确率高、部署简单,但需要联网且有调用配额;二是使用本地模型,例如通过onnxruntime加载轻量级的MobileNet分类模型,完全离线运行,适合对隐私敏感的场景。
整个Agent的决策流程可以概括为:扫描目录下所有照片文件,逐张解析EXIF获取时间与坐标,没有EXIF的照片则回退使用文件修改时间,再结合图像识别的场景标签,最终生成“日期-地点-场景”三级文件夹结构并执行文件移动。这个流程本质上就是一个规则驱动的Agent:感知(读取照片信息)、决策(生成归档路径)、执行(移动文件)三个环节清晰分离,方便后续扩展。
二、实战代码:从EXIF解析到自动归档
下面用Python实现核心逻辑。依赖库方面,解析EXIF推荐使用exifread,文件操作使用shutil,逆地理编码可以调用免费的开源服务Nominatim。安装命令为pip install exifread requests。
import os
import shutil
import exifread
from datetime import datetime
def get_exif_info(photo_path):
"""解析照片EXIF,返回拍摄时间和GPS坐标"""
with open(photo_path, 'rb') as f:
tags = exifread.process_file(f, details=False)
# 提取拍摄时间,优先DateTimeOriginal
time_str = str(tags.get('EXIF DateTimeOriginal', ''))
taken_time = None
if time_str:
taken_time = datetime.strptime(time_str, '%Y:%m:%d %H:%M:%S')
# 提取GPS坐标
def to_degrees(v):
d, m, s = [float(x.num) / float(x.den) for x in v.values]
return d + m / 60 + s / 3600
lat, lon = None, None
if 'GPS GPSLatitude' in tags:
lat = to_degrees(tags['GPS GPSLatitude'])
lon = to_degrees(tags['GPS GPSLongitude'])
if str(tags.get('GPS GPSLatitudeRef', 'N')) == 'S':
lat = -lat
if str(tags.get('GPS GPSLongitudeRef', 'E')) == 'W':
lon = -lon
return taken_time, (lat, lon)
def reverse_geocode(lat, lon):
"""根据经纬度反查地名"""
import requests
url = 'https://nominatim.openstreetmap.org/reverse'
params = {'lat': lat, 'lon': lon, 'format': 'json', 'accept-language': 'zh-CN'}
headers = {'User-Agent': 'photo-agent-demo'}
resp = requests.get(url, params=params, headers=headers, timeout=10)
addr = resp.json().get('address', {})
# 优先返回城市和景点信息
return addr.get('city') or addr.get('town') or addr.get('state') or '未知地点'
def organize_photos(src_dir, dst_dir):
"""主流程:扫描、解析、归类、移动"""
exts = ('.jpg', '.jpeg', '.png', '.heic')
for filename in os.listdir(src_dir):
if not filename.lower().endswith(exts):
continue
path = os.path.join(src_dir, filename)
taken_time, (lat, lon) = get_exif_info(path)
# 兜底:无EXIF时使用文件修改时间
if taken_time is None:
taken_time = datetime.fromtimestamp(os.path.getmtime(path))
place = reverse_geocode(lat, lon) if lat else '未知地点'
day = taken_time.strftime('Day%m%d')
target_dir = os.path.join(dst_dir, day + '-' + place)
os.makedirs(target_dir, exist_ok=True)
shutil.move(path, os.path.join(target_dir, filename))
print(f'{filename} -> {target_dir}')
if __name__ == '__main__':
organize_photos(r'D:\Travel\raw', r'D:\Travel\sorted')
代码中有几个细节值得注意。第一,exifread读取GPS时返回的是有理数分数形式,必须手动换算成十进制度数,并处理南纬、西经的负号问题。第二,逆地理编码调用Nominatim时务必设置User-Agent请求头,否则会被服务拒绝,且免费接口有每秒一次的限流要求,实际使用时应加缓存:相同坐标只查询一次,可以用一个字典缓存结果。第三,移动文件前建议先用os.path.exists检查目标文件是否重名,重名时在文件名后追加时间戳,避免覆盖。
三、进阶优化:去重、场景识别与自动化运行
基本的归档流程跑通后,还有三个方向可以优化。首先是重复照片去重。旅行中经常出现连拍、截图转发导致的多份相同文件,简单的方式是计算文件的MD5值做精确去重;更聪明的做法是用感知哈希(pHash),通过Pillow的ImageHash库把每张图片压缩成32位的哈希指纹,海明距离小于5即视为相似照片,这样即使分辨率不同也能识别出来。
其次是场景识别的引入。可以在归档前调用图像识别接口获取标签,当识别结果为“食物”时归入“美食”子目录,识别为“人物”时归入“人像”子目录。以本地方案为例,用onnxruntime加载MobileNet模型,单张推理耗时在普通笔记本上约50毫秒,一千张照片只需一分钟左右,完全离线可用,适合处理包含隐私内容的照片。
最后是把它变成真正的Agent:让程序自动监控文件夹。Windows下可以用watchdog库监听目录变化,一旦有新照片写入(比如手机通过自动同步工具上传到指定目录),就触发整理流程,实现“拍完即归档”的体验。再配合系统计划任务或crontab定时运行,一个无人值守的照片整理Agent就搭建完成了。整体架构上,感知模块(EXIF与图像识别)、决策模块(归类规则)、执行模块(文件操作)彼此解耦,后续想加入按人物人脸聚类、自动挑选精选照片等功能,只需替换或增加决策模块即可,这也是Agent式程序相比普通脚本最大的优势。
总结一下,照片自动整理Agent并没有想象中复杂,核心就是EXIF解析、逆地理编码和图像识别三块能力的组合。用文中不到一百行代码就能解决日常百分之八十的整理需求,再根据实际情况逐步叠加去重和监控功能即可。动手试一试,下次旅行归来,照片已经静静地躺在整理好的文件夹里了。
照片自动整理Python Agent图像识别修改时间:2026-09-02 06:30:31