微信图片批量保存的办法
已经给官方提建议了,目前还没在最新版看到相关功能。
解决办法:python 脚本(通过pywinauto 控制点击下一张和下载按钮,然后通过判断文件夹里的文件md5值重复阈值来间接达到判断没有下一张的目的)
操作步骤,登录电脑版微信,打开相关聊天记录,打开图片查看功能,界面是这个样子的才能用这个脚本(忽略第二个按钮置灰,刚跑完一次)。

此时是可以点击左上角向右箭头(从左数第二个按钮:鼠标放上去提示文字为下一张)和另存为按钮(顶部最右侧的按钮)的,先点即下载按钮,选择保存路径
比如我选择的是 C:\Users\e3724\Desktop\a
那么将这个路径在下面python脚本中有用到
from pywinauto import Application
import time
import os
import hashlib
import threading
from pywinauto.keyboard import send_keys
from collections import defaultdict
# 配置参数
SAVE_FOLDER = r"C:\Users\e3724\Desktop\a" # 目标保存路径
MAX_REPEAT = 2 # MD5重复阈值(达到此次数则停止)
WAIT_DELAY = 0.01 # 操作延迟(秒),如果在电脑上图片没被看过,则此数字要调大至1.0~3.0左右,因为第一次用网络加载需要时间
MONITOR_INTERVAL = 1 # 监控线程扫描间隔(秒)
# 全局变量:文件名→MD5映射(线程安全)
file_md5_map = {}
# 全局变量:MD5出现次数统计
md5_count = defaultdict(int)
# 线程锁
map_lock = threading.Lock()
def calculate_md5(file_path):
"""计算文件MD5值"""
if not os.path.exists(file_path):
return None
try:
hash_md5 = hashlib.md5()
with open(file_path, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
except Exception as e:
print(f"计算MD5失败:{str(e)}")
return None
def folder_monitor():
"""后台线程:监控文件夹并更新MD5映射"""
global file_md5_map, md5_count
while True:
if os.path.exists(SAVE_FOLDER):
for filename in os.listdir(SAVE_FOLDER):
if filename.endswith(".jpg") and filename.split(".")[0].isdigit():
file_path = os.path.join(SAVE_FOLDER, filename)
with map_lock:
current_md5 = calculate_md5(file_path)
if current_md5:
# 处理文件更新(如覆盖保存)
if filename in file_md5_map:
old_md5 = file_md5_map[filename]
md5_count[old_md5] -= 1
if md5_count[old_md5] <= 0:
del md5_count[old_md5]
# 更新映射和计数
file_md5_map[filename] = current_md5
md5_count[current_md5] += 1
time.sleep(MONITOR_INTERVAL)
def wait_for_file(filename, timeout=10):
"""等待文件被监控线程捕获"""
start_time = time.time()
while time.time() - start_time < timeout:
with map_lock:
if filename in file_md5_map:
return True
time.sleep(0.5)
return False
def final_dedup():
"""流程结束后统一删除重复文件(只保留第一个出现的)"""
with map_lock:
# 按文件名排序(确保按顺序保留第一个)
sorted_files = sorted(file_md5_map.keys(), key=lambda x: int(x.split(".")[0]))
md5_first_occurrence = {} # 记录MD5首次出现的文件名
duplicate_files = [] # 记录重复文件
for filename in sorted_files:
md5 = file_md5_map[filename]
if md5 not in md5_first_occurrence:
md5_first_occurrence[md5] = filename
else:
duplicate_files.append(filename)
# 删除重复文件
for filename in duplicate_files:
file_path = os.path.join(SAVE_FOLDER, filename)
if os.path.exists(file_path):
try:
os.remove(file_path)
print(f"最终去重:删除重复文件 {filename}")
except Exception as e:
print(f"删除重复文件失败 {filename}:{str(e)}")
return len(sorted_files) - len(duplicate_files), len(duplicate_files)
def auto_download_wechat_images(window_title, next_btn_text="下一张", save_btn_text="另存为"):
# 记录开始时间
start_time = time.time()
try:
# 启动监控线程
monitor_thread = threading.Thread(target=folder_monitor, daemon=True)
monitor_thread.start()
print("已启动文件夹监控线程...")
time.sleep(2)
# 连接窗口
app = Application(backend="uia").connect(title_re=f".*{window_title}.*", timeout=10)
main_window = app.window(title_re=f".*{window_title}.*")
main_window.set_focus()
print(f"已连接到窗口:{main_window.window_text()}")
click_count = 1
stop_flag = False
while not stop_flag:
# 查找下一张按钮
next_btn = None
for btn in main_window.descendants(control_type="Button"):
btn_text = btn.window_text().strip()
if next_btn_text in btn_text or "→" in btn_text:
next_btn = btn
break
if not next_btn or not next_btn.is_enabled():
print("未找到可用的下一张按钮,停止流程")
break
# 查找另存为按钮
save_btn = None
for btn in main_window.descendants(control_type="Button"):
btn_text = btn.window_text().strip()
if save_btn_text in btn_text or "保存" in btn_text:
save_btn = btn
break
if not save_btn or not save_btn.is_enabled():
print("未找到可用的另存为按钮,跳过")
next_btn.click_input()
click_count += 1
time.sleep(WAIT_DELAY)
continue
# 保存当前图片
current_filename = f"{click_count}.jpg"
print(f"\n===== 处理第{click_count}张图片({current_filename})=====")
save_btn.click_input()
time.sleep(WAIT_DELAY ) # 等待对话框
# 输入文件名(重试机制)
save_success = False
for _ in range(3):
try:
send_keys(current_filename.split(".")[0]) # 输入数字
time.sleep(0.5)
send_keys("{ENTER}")
save_success = True
break
except:
time.sleep(1)
if not save_success:
print("保存失败,跳过")
next_btn.click_input()
click_count += 1
continue
# 等待文件被监控线程捕获
if not wait_for_file(current_filename):
print(f"警告:{current_filename} 未被监控到,可能保存路径错误")
next_btn.click_input()
click_count += 1
continue
# 检查MD5重复情况
with map_lock:
current_md5 = file_md5_map[current_filename]
current_md5_count = md5_count[current_md5]
print(f"当前MD5:{current_md5},累计出现次数:{current_md5_count}")
# 首次重复时输出日志
if current_md5_count == 2:
print(f"⚠️ MD5首次重复(当前文件:{current_filename})")
# 达到重复阈值时停止流程
elif current_md5_count >= MAX_REPEAT:
print(f"⚠️ MD5重复达到阈值({MAX_REPEAT}次),停止流程")
stop_flag = True
break
# 点击下一张
next_btn.click_input()
click_count += 1
time.sleep(WAIT_DELAY * 2)
# 流程结束后统一去重
print("\n开始最终去重...")
total_valid, total_duplicate = final_dedup()
# 计算总耗时
end_time = time.time()
total_time = end_time - start_time
minutes = int(total_time // 60)
seconds = total_time % 60
print(f"\n===== 结果统计 =====")
print(f"总下载文件数:{len(file_md5_map)}")
print(f"去重后保留:{total_valid} 张")
print(f"删除重复文件:{total_duplicate} 张")
print(f"总耗时:{minutes}分{seconds:.2f}秒")
except Exception as e:
# 异常时也统计耗时
end_time = time.time()
total_time = end_time - start_time
print(f"流程出错:{str(e)},已运行{total_time:.2f}秒")
if __name__ == "__main__":
input("请确认路径正确且手动测试过保存功能,按回车开始...")
auto_download_wechat_images(
window_title="图片查看",
next_btn_text="下一张",
save_btn_text="另存为"
)
ubuntu系统,需要这个括号里的图(
)
import pyautogui
import time
import os
import subprocess
import hashlib
# 配置参数
SAVE_BUTTON_IMG = "save_button.png" # 保存按钮截图
WAIT_TIME = 0.3 # 操作间隔隔(秒)
OUTPUT_DIR = os.path.expanduser("/home/swt/桌面/a") # 保存目录
FILE_COUNTER = 1 # 文件名计数器(从1开始)
RECENT_FILES = [] # 最近保存的文件路径
def get_file_md5(file_path):
"""计算文件MD5"""
if not os.path.exists(file_path):
return None
md5_hash = hashlib.md5()
with open(file_path, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
md5_hash.update(chunk)
return md5_hash.hexdigest()
def ensure_output_dir():
"""确保保存目录存在"""
os.makedirs(OUTPUT_DIR, exist_ok=True)
print(f"图片将保存到:{OUTPUT_DIR}")
def find_wechat_image_window():
"""通过wmctrl查找微信图片窗口"""
try:
result = subprocess.check_output(
"wmctrl -l | grep -i '图片'", # 替换为实际窗口标题关键词
shell=True,
text=True
)
return result.split()[0] # 返回窗口ID
except subprocess.CalledProcessError:
print("未找到微信图片窗口,请先打开图片查看模式")
return None
def activate_window(window_id):
"""激活窗口"""
subprocess.run(f"wmctrl -i -a {window_id}", shell=True)
time.sleep(WAIT_TIME)
def click_save_button():
"""点击保存按钮"""
try:
button_pos = pyautogui.locateOnScreen(
SAVE_BUTTON_IMG,
confidence=0.7,
grayscale=True
)
if button_pos:
pyautogui.click(pyautogui.center(button_pos))
print("已点击保存按钮")
return True
print("未找到保存按钮")
return False
except Exception as e:
print(f"按钮识别错误:{e}")
return False
def handle_save_dialog():
"""处理保存对话框,直接输入纯数字文件名"""
global FILE_COUNTER
time.sleep(WAIT_TIME) # 等待对话框弹出
# 1. 全选默认文件名(确保覆盖)
pyautogui.hotkey("ctrl", "a")
#time.sleep(0.5)
# 2. 直接输入当前计数器(纯数字,不带扩展名)
pyautogui.typewrite(str(FILE_COUNTER))
#time.sleep(0.5)
# 3. 按Enter确认保存
pyautogui.press("enter")
print(f"已保存为:{FILE_COUNTER}")
# 4. 记录文件路径并递增计数器
# 注:实际保存的文件会自动带扩展名(微信默认添加)
saved_path = os.path.join(OUTPUT_DIR, f"{FILE_COUNTER}") # 后续系统会自动补全扩展名
RECENT_FILES.append(saved_path)
FILE_COUNTER += 1 # 下次保存+1
time.sleep(WAIT_TIME)
def next_image():
"""切换到下一张图片"""
pyautogui.press("right")
print("切换到下一张图片")
time.sleep(WAIT_TIME)
def check_md5_duplicate():
"""检查最近2张图片MD5是否一致"""
if len(RECENT_FILES) >= 2:
# 补全实际文件名(微信会自动添加扩展名,如.png)
file1 = find_actual_file(RECENT_FILES[-2])
file2 = find_actual_file(RECENT_FILES[-1])
if not file1 or not file2:
return False
md5_1 = get_file_md5(file1)
md5_2 = get_file_md5(file2)
if md5_1 and md5_2 and md5_1 == md5_2:
print(f"\n检测到连续2张图片MD5一致:{md5_1}")
return True
return False
def find_actual_file(base_name):
"""查找带扩展名的实际文件(如输入1,实际可能是1.png)"""
for ext in [".png", ".jpg", ".jpeg"]: # 常见图片扩展名
candidate = f"{base_name}{ext}"
if os.path.exists(candidate):
return candidate
return None # 未找到对应文件
def batch_save_images(max_count=20):
"""批量保存图片,支持纯数字文件名和重复检测"""
ensure_output_dir()
window_id = find_wechat_image_window()
if not window_id:
return
activate_window(window_id)
for i in range(max_count):
print(f"\n处理第{i+1}/{max_count}张图片")
if click_save_button():
handle_save_dialog()
# 检查连续2张是否重复
if check_md5_duplicate():
print("程序终止:连续2张图片重复")
return
else:
print("跳过当前图片")
next_image()
print("\n批量保存完成(已达最大数量)")
if __name__ == "__main__":
input("请确保已打开微信图片查看窗口,按Enter开始...")
batch_save_images(max_count=20)

浙公网安备 33010602011771号