230 lines
8.0 KiB
Python
230 lines
8.0 KiB
Python
"""
|
|
任务:打开飞书客户端,找到"资产管理组"群聊并截图
|
|
|
|
流程:
|
|
1. 启动飞书桌面客户端(或连接已运行的实例)
|
|
2. 等待窗口加载并激活
|
|
3. 使用搜索功能找到"资产管理组"群聊
|
|
4. 点击进入群聊
|
|
5. 截取群聊页面
|
|
6. 保存今日全部聊天记录
|
|
"""
|
|
from ast import main
|
|
import os
|
|
import subprocess
|
|
import time
|
|
from datetime import datetime
|
|
|
|
import pygetwindow as gw
|
|
from pywinauto import Application
|
|
|
|
from config import FEISHU_DESKTOP_PATH, OUTPUT_DIR, FEISHU_GROUPS
|
|
from utils import get_logger
|
|
from utils.screenshot import take_window_screenshot
|
|
|
|
log = get_logger("feishu_chat")
|
|
|
|
# 飞书窗口标题可能的关键词
|
|
FEISHU_WINDOW_TITLES = ["飞书", "Lark"]
|
|
|
|
|
|
def _find_feishu_window():
|
|
"""查找已运行的飞书窗口,返回窗口标题"""
|
|
for keyword in FEISHU_WINDOW_TITLES:
|
|
windows = gw.getWindowsWithTitle(keyword)
|
|
if windows:
|
|
return windows[0].title
|
|
return None
|
|
|
|
|
|
def _connect_feishu(max_retries: int = 6, interval: int = 5):
|
|
"""
|
|
连接飞书窗口,带重试机制
|
|
|
|
Args:
|
|
max_retries: 最大重试次数
|
|
interval: 每次重试间隔(秒)
|
|
"""
|
|
for attempt in range(1, max_retries + 1):
|
|
# 先检查飞书窗口是否已出现
|
|
win_title = _find_feishu_window()
|
|
if win_title:
|
|
log.info("检测到飞书窗口: '%s'(第 %d 次尝试)", win_title, attempt)
|
|
app = Application(backend="uia").connect(
|
|
title=win_title, timeout=10
|
|
)
|
|
main_win = app.window(title=win_title)
|
|
main_win.wait("visible", timeout=10)
|
|
main_win.set_focus()
|
|
# 全屏显示
|
|
main_win.maximize()
|
|
# // 全屏显示
|
|
main_win.fullscreen = True
|
|
return app, main_win
|
|
|
|
log.info("等待飞书窗口出现...(第 %d/%d 次)", attempt, max_retries)
|
|
time.sleep(interval)
|
|
|
|
raise TimeoutError(
|
|
f"等待飞书窗口超时({max_retries * interval}秒),"
|
|
"请确认飞书客户端已正确安装且路径正确: " + FEISHU_DESKTOP_PATH
|
|
)
|
|
|
|
|
|
def save_today_chat_history(app, chat_name: str) -> str:
|
|
"""
|
|
通过滚动截图保存今日全部聊天记录
|
|
|
|
从当前聊天位置向上滚动,逐屏截图,
|
|
直到检测到今日日期分隔线或达到最大滚动次数。
|
|
|
|
Args:
|
|
app: pywinauto Application 对象
|
|
chat_name: 群聊名称
|
|
|
|
Returns:
|
|
截图保存目录路径
|
|
"""
|
|
today_str = datetime.now().strftime("%Y-%m-%d")
|
|
# 按日期创建子目录,如 output/20260826/
|
|
output_dir = os.path.join(OUTPUT_DIR, datetime.now().strftime("%Y%m%d"))
|
|
os.makedirs(output_dir, exist_ok=True)
|
|
|
|
import pyautogui
|
|
|
|
try:
|
|
# 直接通过 pygetwindow 查找聊天窗口(避免 pywinauto 多窗口匹配问题)
|
|
candidates = (
|
|
gw.getWindowsWithTitle(chat_name)
|
|
or gw.getWindowsWithTitle("飞书")
|
|
or gw.getWindowsWithTitle("Lark")
|
|
)
|
|
if not candidates:
|
|
raise ValueError(f"未找到飞书或群聊窗口: {chat_name}")
|
|
|
|
win = candidates[0]
|
|
# 激活窗口到前台(最小化时先还原)
|
|
try:
|
|
if win.isMinimized:
|
|
win.restore()
|
|
win.activate()
|
|
except Exception:
|
|
log.warning("窗口激活失败,尝试继续截图")
|
|
time.sleep(0.5)
|
|
win_bbox = (win.left, win.top, win.width, win.height)
|
|
|
|
max_scrolls = 30 # 最大滚动次数
|
|
scroll_pause = 0.8 # 每次滚动后等待时间
|
|
shot_index = 1
|
|
|
|
log.info("开始滚动截图,最多 %d 屏...", max_scrolls)
|
|
log.info("先滚动到聊天框最底部...")
|
|
scroll_to_bottom_times = 30
|
|
for _ in range(scroll_to_bottom_times):
|
|
center_x = win.left + win.width - 100 # 聊天区域右侧中间位置
|
|
center_y = win.top + win.height // 2
|
|
pyautogui.moveTo(center_x, center_y)
|
|
pyautogui.scroll(-500000) # 向下滚动(负数表示向下,显示最新消息)
|
|
time.sleep(scroll_pause)
|
|
|
|
for i in range(max_scrolls):
|
|
# 截图
|
|
shot_name = f"{chat_name}_{today_str}_{shot_index:03d}"
|
|
shot_path = os.path.join(output_dir, f"{shot_name}.png")
|
|
screenshot = pyautogui.screenshot(region=win_bbox)
|
|
screenshot.save(shot_path)
|
|
log.info("截图 %d/%d: %s", shot_index, max_scrolls, shot_path)
|
|
shot_index += 1
|
|
|
|
# 向上滚动(鼠标滚轮向上滚动加载历史消息)
|
|
# 将鼠标移到聊天区域右侧
|
|
center_x = win.left + win.width - 100
|
|
center_y = win.top + win.height // 2
|
|
# // 滚动
|
|
pyautogui.moveTo(center_x, center_y)
|
|
pyautogui.scroll(500) # 向上滚动
|
|
time.sleep(scroll_pause)
|
|
|
|
# 检测是否已到达顶部(通过检查是否有日期分隔线)
|
|
# 简单策略:如果连续滚动后内容不再变化则停止
|
|
# 这里用固定次数,实际可根据图像相似度判断
|
|
|
|
log.info("滚动截图完成,共 %d 张,保存在: %s", shot_index - 1, output_dir)
|
|
return output_dir
|
|
|
|
except Exception as e:
|
|
log.error("滚动截图失败: %s", e)
|
|
return output_dir
|
|
|
|
def feishu_groups_list():
|
|
log.info("获取飞书群组")
|
|
# 任务开始前弹出桌面警告倒计时
|
|
for chat_name in FEISHU_GROUPS:
|
|
open_feishu_and_find_chat(chat_name=chat_name)
|
|
log.info(f"获取群组列表完成{chat_name}")
|
|
def open_feishu_and_find_chat(
|
|
chat_name: str = "资产管理组",
|
|
screenshot_name: str = None,
|
|
save_chat_history: bool = True,
|
|
):
|
|
"""
|
|
打开飞书客户端,找到指定群聊并截图
|
|
|
|
Args:
|
|
chat_name: 群聊名称,默认"资产管理组"
|
|
screenshot_name: 截图文件名(不含扩展名),默认为时间戳
|
|
save_chat_history: 是否保存今日聊天记录
|
|
"""
|
|
log.info("===== 开始任务:打开飞书并查找群聊 '%s' =====", chat_name)
|
|
|
|
# 1. 检查飞书是否已在运行
|
|
existing_title = _find_feishu_window()
|
|
if existing_title:
|
|
log.info("步骤 1: 飞书已在运行,直接连接")
|
|
else:
|
|
log.info("步骤 1: 启动飞书客户端")
|
|
try:
|
|
subprocess.Popen(FEISHU_DESKTOP_PATH)
|
|
except FileNotFoundError:
|
|
log.error("未找到飞书客户端,请检查路径: %s", FEISHU_DESKTOP_PATH)
|
|
raise
|
|
|
|
# 2. 连接飞书窗口(带重试)
|
|
log.info("步骤 2: 等待飞书窗口加载...")
|
|
app, main_win = _connect_feishu()
|
|
log.info("飞书窗口已激活")
|
|
|
|
# 3. 打开搜索(飞书支持 Ctrl+K 快捷键打开搜索)
|
|
log.info("步骤 3: 打开搜索框")
|
|
main_win.type_keys("^k") # Ctrl+K
|
|
time.sleep(1.5)
|
|
|
|
# 4. 输入群聊名称
|
|
log.info("步骤 4: 搜索 '%s'", chat_name)
|
|
# 先清空搜索框
|
|
main_win.type_keys("^a")
|
|
time.sleep(0.3)
|
|
main_win.type_keys(chat_name, with_spaces=True)
|
|
time.sleep(2) # 等待搜索结果
|
|
|
|
# 5. 按回车选中第一个搜索结果
|
|
log.info("步骤 5: 选中搜索结果")
|
|
main_win.type_keys("{ENTER}")
|
|
time.sleep(2) # 等待群聊页面加载
|
|
|
|
# 6. 保存今日聊天记录
|
|
if save_chat_history:
|
|
log.info("步骤 6: 保存今日聊天记录")
|
|
chat_file = save_today_chat_history(app, chat_name)
|
|
log.info("聊天记录已保存: %s", chat_file)
|
|
|
|
log.info("===== 任务完成 =====")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# 任务开始前弹出桌面警告倒计时
|
|
from utils import show_warning_countdown
|
|
|
|
show_warning_countdown(message="即将开始自动截图", seconds=5)
|
|
open_feishu_and_find_chat()
|