当前位置: 首页 > news >正文

微信图片批量保存的办法

已经给官方提建议了,目前还没在最新版看到相关功能。

解决办法:python 脚本(通过pywinauto 控制点击下一张和下载按钮,然后通过判断文件夹里的文件md5值重复阈值来间接达到判断没有下一张的目的)

操作步骤,登录电脑版微信,打开相关聊天记录,打开图片查看功能,界面是这个样子的才能用这个脚本(忽略第二个按钮置灰,刚跑完一次)。

a

 

 

 

 

 

此时是可以点击左上角向右箭头(从左数第二个按钮:鼠标放上去提示文字为下一张)和另存为按钮(顶部最右侧的按钮)的,先点即下载按钮,选择保存路径

比如我选择的是 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 Nonetry: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 Nonedef folder_monitor():"""后台线程:监控文件夹并更新MD5映射"""global file_md5_map, md5_countwhile 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] -= 1if md5_count[old_md5] <= 0:del md5_count[old_md5]# 更新映射和计数file_md5_map[filename] = current_md5md5_count[current_md5] += 1time.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 Truetime.sleep(0.5)return Falsedef 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] = filenameelse: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 = 1stop_flag = Falsewhile not stop_flag:# 查找下一张按钮next_btn = Nonefor 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 = btnbreakif not next_btn or not next_btn.is_enabled():print("未找到可用的下一张按钮,停止流程")break# 查找另存为按钮save_btn = Nonefor 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 = btnbreakif not save_btn or not save_btn.is_enabled():print("未找到可用的另存为按钮,跳过")next_btn.click_input()click_count += 1time.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 = Falsefor _ in range(3):try:send_keys(current_filename.split(".")[0])  # 输入数字time.sleep(0.5)send_keys("{ENTER}")save_success = Truebreakexcept:time.sleep(1)if not save_success:print("保存失败,跳过")next_btn.click_input()click_count += 1continue# 等待文件被监控线程捕获if not wait_for_file(current_filename):print(f"警告:{current_filename} 未被监控到,可能保存路径错误")next_btn.click_input()click_count += 1continue# 检查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 = Truebreak# 点击下一张next_btn.click_input()click_count += 1time.sleep(WAIT_DELAY * 2)# 流程结束后统一去重print("\n开始最终去重...")total_valid, total_duplicate = final_dedup()# 计算总耗时end_time = time.time()total_time = end_time - start_timeminutes = int(total_time // 60)seconds = total_time % 60print(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_timeprint(f"流程出错:{str(e)},已运行{total_time:.2f}秒")if __name__ == "__main__":input("请确认路径正确且手动测试过保存功能,按回车开始...")auto_download_wechat_images(window_title="图片查看",next_btn_text="下一张",save_btn_text="另存为")

  

http://www.hskmm.com/?act=detail&tid=23813

相关文章:

  • 详细介绍:使用 C# 设置 Excel 单元格数据验证
  • 10.3 闲话-分散层叠
  • 博客园实验1
  • arm汇编
  • 模型与分词器
  • subclipse最新版本更新地址
  • 板子2
  • 从DQN到Double DQN:分离动作选择与价值评估,解决强化学习中的Q值过估计问题
  • P9877/QOJ5069 Vacation
  • CF1916G Optimizations From Chelsu
  • 详细介绍:微服务架构:基于Spring Cloud ,构建同城生活服务平台
  • 云锵投资 2025 年 9 月简报
  • 【游记】北京师范大学讲课
  • 字符串Hash
  • 详细介绍:代码世界的“数字刑侦”:深入解析代码审计实战
  • 三霍尔BLDC如何测量Hall同步角度(需要示波器)
  • QBXT2025S刷题 Day2
  • PyCharm中搭建PyTorch和YOLOv10开发环境 - 实践
  • 基于PCIe(XDMA)的多路(1-32路)信号采集与回放子系统, 多路视频、AD、光纤等信号,支持PR over PCIe
  • Spring事务管理:@Transactional注解
  • AI元人文的未来:软硬件协同发展研究报告——声明Ai研究
  • 个人主页网址
  • 10.3考试t3(similarity)solution
  • 安卓渗透测试流
  • 日志|寻找旋转排序数组中的最小值|寻找两个正序数组的中位数|二分查找
  • 有关三角剖分的性质
  • 西门子通信-自制示意
  • Vue之刷新页面会触发的生命周期函数
  • 傅里叶的一生
  • Dos命令学习(新手)