前言:
如果你也想自动操作微信、自动转发微信中的文件,甚至想处理特定文件后转发,请接着往下看,这篇文章就是你想要的!
我本人也是因为公司经常有业务需求,需要从一个群接收文件,处理表格之后,转发到另一个群,所以多次尝试之后形成了如下最佳方案。
简介:
通过uiautomation库操作微信,提取信息后,使用pywin32库调用预先写好的PQ查询,另存结果,然后再使用xlwings、openpyxl等库对结果进行图片另存、文字提取等操作,最后再转发到目标微信群。
详细步骤:
首先最核心的操作微信:python的uiautomation,是一位国人yinkaisheng编写的,基于windows的wpf进行树查找、操作、取值,非常方便实用,关键是相对于别的比较暴力的微信操作方式,此方法绝对不会被封号,但也有缺点,就是它会占用鼠标键盘和剪贴板(如果你需要的话),所以只要运行起来,这台电脑就只能做这一件事。另外,要注意差错处理,以便它能持续运行。uiautomation
我的代码其中的get_chat_records方法是获取微信消息的核心部分,是我从某个博主那里借鉴过来,经过三个月的长期打磨最终形成的简洁版,只获取文字和文件(图片是无法从wpf树直接获取的,所以想直接转发图片的同志们可能要另外花点心思)
def get_chat_records(wechatWindow, page: int = 1, sessionName="沟通群") -> list:
talks = list() # 所有的聊天记录,真正说的话,列表。去掉红包、状态、时间等。
all_msgs = wechatWindow.ListControl(Name="消息").GetChildren()
# for msg_node in get_last_10_elements(all_msgs):
for msg_node in all_msgs:
try:
msg = msg_node.Name
if not msg:
continue
if "邀请你加入" in msg:
continue
if msg in ["以下为新消息", "查看更多消息", "该类型文件可能存在安全风险,建议先检查文件安全性后再打开。", "已撤回"]:
# print(1)
continue
if (
"撤回了一条消息" in msg
or "尝试撤回上一条消息" in msg
or "加入了群聊" in msg
or "与群里其他人都不是朋友关系,请注意隐私安全" in msg
):
# print(2)
continue
if msg == "[图片]":
# print(3)
continue
# if msg_node.PaneControl().Exists(3, 1) and msg_node.PaneControl().Name: # 只有时间窗格会有Name值,别的都是空,
# print('日期,跳过')
# # talk_at = getRightTime(msg_node.PaneControl().Name)
# # print(talk_at)
# continue
if msg in [
"发出红包,请在手机上查看",
"收到红包,请在手机上查看",
"你发送了一次转账收款提醒,请在手机上查看",
"你收到了一次转账收款提醒,请在手机上查看",
]:
# print(4)
continue
if "领取了你的红包" in msg:
# print(5)
continue
if "引用" in msg and "的消息" in msg:
# print(6)
continue
if msg == "[文件]":
fileName = msg_node.TextControl(foundIndex=2).Name
sender = msg_node.TextControl(foundIndex=1).Name
print("微信收到文件",fileName)
if "cared_sender" not in sender:
print("忽略")
continue
if "在途工单预警通报" not in fileName:
continue
talk_data = {
"sender": sender,
"type": "file",
"content": fileName,
"session": sessionName,
}
talk_data["md5"] = generate_md5(talk_data)
talks.append(talk_data)
continue
if msg == "微信转账":
print(8)
continue
if msg == "[聊天记录]":
print(9)
continue
if msg_node.TextControl(foundIndex=1).Exists(3, 1):
talk_data = {
"sender": msg_node.TextControl(foundIndex=1).Name,
"type": "text",
"content": msg,
"session": sessionName,
}
talk_data["md5"] = generate_md5(talk_data)
# print("是对话", msg)
talks.append(talk_data)
except LookupError as e:
print("无法找到对象", msg)
return talks
其次,针对excel的处理,我们常用的需求就是收到excel然后处理(分劈、筛选等),我花了两周尝试了openpyxl、xlwings、pywin32、pandas等多种库,来回组合配合使用,都没达到理想的效果,要么是格式没了,要么是数不对了,要么是xls与xlsx来回转换非常麻烦。后来我才突发奇想,有没有一种可能,让power query处理excel,而python只负责调用它、获取结果?
有了该想法之后,我立刻动手,查了下资料好少,这么犄角旮旯的思路果然不是人人都用的哈哈。总之,经过没一会的折腾,就已经成功使用python操作pq了。这种方法的优势在于,表本来是啥样,最终还是啥样,跟你用手做的一样,原汁原味。整个pq查询的编写完全交给业务口,咱不用操这个心,只需要留好文件夹给它就行了。使用python操作pq的代码仅寥寥数行如下:
import time, os
import win32com.client
from clear_folder import clear_folder
def run_pq(pq_excel_file_path):
# 打开Excel应用程序
excel_app = win32com.client.Dispatch("Excel.Application")
excel_app.Visible = False # 可见Excel界面
# 打开Excel文件
print(f"PQ运行中……{pq_excel_file_path}")
full_path = os.path.abspath(pq_excel_file_path)
workbook = excel_app.Workbooks.Open(full_path)
# 刷新Power Query查询(假设你需要刷新所有工作表,你可以根据实际情况调整)
workbook.RefreshAll()
# 等待刷新完成
# 读取刷新后的结果表中第一个工作表的A1单元格的值
result_sheet = workbook.Sheets(1) # 假设结果表是第一个工作表
result_value = result_sheet.Range("A1").Value
# 另存为以A1单元格的值命名的.xlsx文件
result_file_path = f"{result_value}.xlsx"
# 选择B22到B34范围的单元格
cell_range = result_sheet.Range("B22:B34")
# 从每个单元格中获取文本内容
text_content = [cell.Value for cell in cell_range]
# 打印部分内容以验证
print("3. 文字:", text_content[0:30])
# 另存为result.xlsx
result_dir_path = os.path.abspath(r"pq_process\result")
clear_folder(result_dir_path)
result_file_full_path = os.path.join(result_dir_path, result_file_path)
workbook.SaveAs(result_file_full_path)
# 将内容保存为txt文件
txt_filename = "文字.txt"
txt_filepath = os.path.join(result_dir_path, txt_filename)
with open(txt_filepath, "w", encoding="utf-8") as txt_file:
for text in text_content:
txt_file.write(str(text) + "\n")
print(f"文本已成功保存到{txt_filepath}文件。")
# 关闭Excel文件
workbook.Close()
# 退出Excel应用程序
excel_app.Quit()
print(f"处理完成:{result_file_full_path}")
return result_file_full_path
if __name__ == "__main__":
run_pq()
踩坑记录:
坑1:使用任何python的库,都无法原汁原味呈现excel处理,不过最接近的是pywin32
坑2:excel如果想截图发微信群,是要花一番功夫的,我这里指定了区域,你也可以用usedrange。
坑3:将文件复制到剪贴板,中间一定要等几秒,不然windows反应不过来。我这里使用的是powershell拼接的方式,如果有更好的方法欢迎留言。
请关注我,后期我会发布更方便的傻瓜版哦!