用Python自动化脚本批量导入微信收藏文章到ima知识库
用Python自动化脚本批量导入微信收藏文章到ima知识库
背景
日常学习中,我们经常在微信收藏中积累大量优质的公众号文章。随着数量增长,微信收藏的搜索和管理能力显得捉襟见肘——没有全文搜索、没有标签分类、没有知识关联。将这批文章迁移到专业的知识库工具(如ima)中,可以显著提升知识管理效率。
但问题来了:微信收藏没有"导出"功能,手动逐条复制链接再粘贴到知识库,面对上千篇文章显然不现实。
本文分享一套Python自动化方案,分两步完成迁移:
- 批量提取:自动遍历微信收藏列表,右键复制每篇文章的链接
- 批量导入:自动将链接分组粘贴到ima知识库的"网页链接"导入框
整套方案纯Python实现,不依赖微信或ima的任何API,仅通过Windows GUI自动化完成。
技术方案
整体架构
微信收藏 (1356篇)
│
▼ wx_extract.py (GUI自动化)
链接文件 (txt, 每10条一组)
│
▼ ima_import.py (GUI自动化)
ima知识库 (1641篇)
环境信息
- 操作系统:Windows 11
- 微信版本:4.1.12.55(基于Qt框架)
- ima知识库:基于Electron
- Python:3.10+
- 依赖库:
pyautogui,pyperclip,numpy,Pillow
关键技术选型
| 需求 | 方案 | 原因 |
|---|---|---|
| 窗口操作 | ctypes + Win32 API |
需要PostMessage后台点击,pyautogui无法做到 |
| 鼠标键盘 | pyautogui |
成熟的GUI自动化库 |
| 剪贴板 | pyperclip |
读取复制的链接 |
| 图像识别 | numpy + PIL |
像素扫描定位UI元素,不依赖OCR |
| 屏幕截图 | pyautogui.screenshot |
截取窗口区域用于分析 |
第一步:批量提取微信收藏链接
核心挑战
微信桌面版(Qt框架)有几个特殊行为:
- 没有导出功能:只能逐条右键复制链接
- 右键菜单是独立窗口:类名
Qt51514QWindowToolSaveBits,不能用普通方式点击 - 窗口内容会变空白:如果用
MoveWindow调整窗口大小,内容会消失
窗口识别
def find_wx_window():
results = []
def cb(hwnd, lparam):
if not user32.IsWindowVisible(hwnd):
return True
cls = ctypes.create_unicode_buffer(256)
user32.GetClassNameW(hwnd, cls, 256)
if 'Qt51514QWindowIcon' in cls.value:
r = wintypes.RECT()
user32.GetWindowRect(hwnd, ctypes.byref(r))
w = r.right - r.left
h = r.bottom - r.top
if w > 500 and h > 400:
results.append((hwnd, r.left, r.top, w, h))
return True
user32.EnumWindows(...)
return results[0] if results else None
通过窗口类名 Qt51514QWindowIcon 识别微信主窗口,过滤掉过小的子窗口。
文章列表定位
微信收藏的文章列表没有可访问的UI树结构,需要通过像素扫描定位每篇文章的位置:
def find_ys(left, top, w, h):
img = pyautogui.screenshot(region=(left, top, w, h))
arr = np.array(img)
# 在窗口15%-55%宽度范围内扫描
for x_test in range(int(w*0.15), int(w*0.55), 50):
col = arr[:, x_test, :3]
# 查找深色文字像素(文章标题)
dark_text = (col[:, 0] < 120) & (col[:, 1] < 120) & (col[:, 2] < 120)
# 按行分组,找到标题行
# 行高12-50px,行间距>80px
...
核心思路:文章标题是深色文字,在特定像素列上会形成连续的深色区域。通过分析这些区域的垂直分布,就能定位每篇文章的Y坐标。
右键复制链接
微信的右键菜单是独立的Qt工具窗口,需要用 PostMessage 进行后台点击:
def get_link(left, top, article_x, article_y):
# 1. 右键点击文章
pyautogui.rightClick(abs_x, abs_y)
time.sleep(0.35)
# 2. 找到右键菜单窗口
menu_hwnd, menu_w, menu_h = find_menu_hwnd()
# 3. PostMessage点击"复制链接"(菜单第一项)
click_x = menu_w // 2
click_y = 60
lparam = click_y << 16 | click_x
user32.PostMessageW(menu_hwnd, WM_LBUTTONDOWN, 1, lparam)
user32.PostMessageW(menu_hwnd, WM_LBUTTONUP, 0, lparam)
# 4. 从剪贴板读取链接
link = pyperclip.paste()
为什么用 PostMessage 而不是 pyautogui.click?因为 PostMessage 是后台点击,不会触发窗口焦点切换,更稳定。
标签切换与重置
提取过程中,列表可能滚动异常或卡住。设计了重置机制:
def reset_to_tag(tag_rel_pos):
win = find_wx_window()
hwnd, left, top, w, h = win
# 最小化再恢复(不能用MoveWindow!)
user32.ShowWindow(hwnd, 6) # SW_MINIMIZE
time.sleep(1)
user32.ShowWindow(hwnd, 9) # SW_RESTORE
time.sleep(2)
user32.SetForegroundWindow(hwnd)
# 点击标签重新进入收藏列表
pyautogui.click(left + tag_rel_pos[0], top + tag_rel_pos[1])
踩坑记录:最初尝试用 MoveWindow 调整微信窗口大小以便截图,结果窗口内容完全变空白。原因是Qt窗口在大小变化时会重绘,但某些情况下重绘失败。解决方案是只用 ShowWindow 最小化再恢复。
自动滚动与去重
while len(existing) + len(new_links) < target_count:
# 1. 定位当前页面文章
list_x, ys = find_ys(left, top, w, h)
# 2. 逐条复制链接
for ay in ys:
link = get_link(left, top, list_x, ay)
if link and link not in existing_set:
new_links.append(link)
# 3. 滚动到下一页
for _ in range(4):
user32.mouse_event(0x0800, 0, 0, ctypes.c_long(-120), 0)
# 4. 连续50个重复时重置窗口
if consecutive_dup >= 50:
win = reset_to_tag(tag_rel_pos)
# 快速滚动到之前的位置
for _ in range(fast_scrolls):
user32.mouse_event(0x0800, 0, 0, ctypes.c_long(-120), 0)
参数化设计
优化后的脚本支持任意标签和输出文件:
python wx_extract.py --tag 编程 --output 编程文章链接.txt --target 500
启动时自动激活微信窗口,用户将鼠标移到目标标签上,脚本记录位置后自动开始提取。也可以通过 --tag-x 和 --tag-y 跳过交互。
第二步:批量导入ima知识库
核心挑战
ima知识库(Electron应用)的导入流程是:
- 点击
+按钮 - 在弹出菜单中选择「网页链接」
- 在输入框粘贴链接
- 点击「导入」按钮
看似简单,但有几个坑:
坐标漂移问题
ima的 + 按钮位置会随窗口位置变化而漂移。最初定位在 (2725, 372),后来变成 (2972, 378)。
解决方案:坐标作为命令行参数,方便随时调整。同时提供自动检测「导入」按钮的功能:
def find_import_button():
"""通过像素扫描找到导入按钮(深色背景+白色文字)"""
img = pyautogui.screenshot()
arr = np.array(img)
# 查找near-black区域
dark_mask = (arr[:, :, :3].mean(axis=2) < 60)
# 按行分组,找到按钮高度(25-55px)和宽度(80-200px)的区域
...
菜单点击需要moveTo
ima的弹出菜单项如果直接 pyautogui.click() 会失败,必须先 moveTo 再 click:
# 直接点击会失败!
# pyautogui.click(3056, 751)
# 正确做法:先moveTo再click
pyautogui.moveTo(3056, 751, duration=0.3)
time.sleep(0.3)
pyautogui.click(3056, 751)
推测原因是Electron的菜单有鼠标进入事件检测,直接click不会触发hover状态。
窗口焦点保持
导入过程中,其他窗口可能抢焦点。每次操作前都检查并恢复ima的前台状态:
def ensure_fg(ima_hwnd):
fg = user32.GetForegroundWindow()
if fg != ima_hwnd:
user32.SetForegroundWindow(ima_hwnd)
time.sleep(0.3)
return user32.GetForegroundWindow() == ima_hwnd
分组导入
链接文件每10条用 ============ 分隔,导入时按组处理:
def import_one_group(links):
# 1. 点击+按钮
pyautogui.click(PLUS_BTN[0], PLUS_BTN[1])
time.sleep(1.0)
# 2. moveTo + 点击"网页链接"
pyautogui.moveTo(WEBLINK_MENU[0], WEBLINK_MENU[1], duration=0.3)
pyautogui.click(WEBLINK_MENU[0], WEBLINK_MENU[1])
time.sleep(1.5)
# 3. 点击输入框 + 粘贴链接
pyautogui.click(TEXT_INPUT[0], TEXT_INPUT[1])
pyperclip.copy('\n'.join(links))
pyautogui.hotkey('ctrl', 'v')
time.sleep(0.5)
# 4. 点击导入按钮
pyautogui.click(IMPORT_BTN[0], IMPORT_BTN[1])
time.sleep(4.0)
支持断点续传:
# 从第50组开始,导入20组
python ima_import.py links.txt --start 50 --num 20
实战结果
提取阶段
- 从微信"考证"标签提取 1356个唯一链接
- 耗时约8分钟
- 输出为136组(每组10条,最后一组6条)
导入阶段
- 136组全部成功导入ima知识库
- 耗时约12分钟
- 原有413篇 → 最终 1641篇(新增1228篇,128个为重复跳过)
整体耗时
约20分钟完成1356条链接的迁移,全程无需人工干预。
经验总结
1. GUI自动化的核心是"定位"
没有API时,UI元素定位是最大挑战。本文使用了三种定位方式:
| 方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 固定坐标 | 按钮等稳定元素 | 简单快速 | 会漂移 |
| 像素扫描 | 深色/亮色按钮 | 不依赖OCR | 颜色敏感 |
| 窗口类名 | 主窗口识别 | 最可靠 | 仅限窗口级 |
2. Qt窗口的特殊行为
微信桌面版基于Qt,有几个需要注意的特性:
- 右键菜单是独立窗口(
Qt51514QWindowToolSaveBits) MoveWindow会导致内容空白- 需要用
ShowWindow最小化再恢复来重置
3. Electron窗口的菜单交互
ima基于Electron,弹出菜单需要先 moveTo 触发hover再 click,直接click会失败。
4. 断点续传很重要
GUI自动化随时可能失败(窗口弹窗、焦点切换等)。设计断点续传机制可以避免从头重来:
# 提取脚本:自动保存进度,重跑会跳过已有链接
python wx_extract.py --tag 考证 --output out.txt --target 1376
# 导入脚本:支持从任意组开始
python ima_import.py out.txt --start 50 --num 20
5. 参数化设计
将硬编码的标签名、文件路径、坐标等提取为命令行参数,使脚本可以复用于不同场景:
# 不同标签
python wx_extract.py --tag 编程 --output 编程.txt --target 300
python wx_extract.py --tag 英语 --output 英语.txt --target 200
# 不同坐标(ima更新后)
python ima_import.py links.txt --plus 2980,380 --menu 3060,755
完整代码
脚本已开源,包含:
wx_extract.py:微信收藏链接提取(支持任意标签)ima_import.py:ima知识库批量导入(支持坐标参数化)wx_to_ima_skill.md:完整使用文档
结语
GUI自动化虽然不如API调用优雅,但在没有官方API的场景下,它是解决实际问题的有效手段。本文方案的核心理念是:用像素扫描代替OCR,用PostMessage代替直接点击,用断点续传应对不确定性。
如果你也有类似的知识迁移需求,希望这套方案能给你提供参考。完整脚本和文档已放在项目中,可以根据自己的环境调整坐标参数后直接使用。
- 点赞
- 收藏
- 关注作者
评论(0)