├── .gitignore ├── .idea ├── .gitignore ├── PyOfficeRobot.iml ├── inspectionProfiles │ └── profiles_settings.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── LICENSE ├── PyOfficeRobot ├── __init__.py ├── api │ ├── __init__.py │ ├── chat.py │ ├── file.py │ ├── friend.py │ └── group.py ├── core │ ├── WeChatType.py │ ├── __init__.py │ └── group │ │ ├── Start.py │ │ ├── __init__.py │ │ └── ui_file_py.py ├── imgs │ └── 5、定时发送 │ │ └── 5、定时发送.jpg └── lib │ ├── CONST.py │ ├── __init__.py │ ├── dec │ ├── __init__.py │ └── act_dec.py │ └── decorator_utils │ ├── __init__.py │ └── instruction_url.py ├── README.md ├── docs └── 文章配图 │ ├── img.py │ ├── imgs │ └── 公众号+Web.jpg │ └── mark_img │ └── 公众号+Web.jpg ├── examples ├── PR │ ├── Dumogu │ │ ├── Pdbot.py │ │ └── WeChatType.py │ ├── gen │ │ ├── 群发 │ │ │ ├── Start.py │ │ │ ├── content.txt │ │ │ ├── ui_file_py.py │ │ │ ├── 群发对象.xls │ │ │ └── 获取群名字.py │ │ └── 自动加好友 │ │ │ ├── Auto_Log.txt │ │ │ └── main.py │ └── tang │ │ ├── test_copy.py │ │ └── weixin_version.py ├── demo │ ├── 001-发一条信息.py │ ├── 002-发文件.py │ ├── 003-根据关键词回复.py │ ├── 004-定时发送.py │ ├── 005-自定义功能.py │ ├── 006-独立版本.py │ ├── 007-收集群消息.py │ ├── 008-发消息换行.py │ ├── 009-批量加好友.py │ ├── 010-定时群发.py │ ├── 010-定时群发的资料 │ │ ├── content.txt │ │ └── 群发对象.xls │ ├── 011-chat_chatgpt.py │ ├── 012-智能聊天.py │ ├── 013-阿里大模型.py │ ├── 014-智谱大模型.py │ └── 015-DeepSeek大模型.py └── dev │ ├── another_test1.py │ ├── test.py │ ├── userMessage.txt │ ├── 关键字自动回复 │ ├── keywords_data.csv │ └── main.py │ ├── 开发记录.md │ ├── 微信群信息收集 │ └── main.py │ └── 收集群消息.py ├── requirements.txt ├── script ├── clean.sh └── upload.sh ├── setup.cfg ├── setup.py └── tests ├── __init__.py ├── test_code └── test_file.py └── test_files └── 0816.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # demo 3 | .idea/ 4 | *.idea/ 5 | .gitee/ 6 | node_modules 7 | .cache 8 | .temp 9 | venv/ 10 | build/ 11 | dist/ 12 | *.egg-info 13 | __pycache__ 14 | .idea/PyOfficeRobot.iml 15 | .idea/misc.xml 16 | *.iml 17 | .idea/PyOfficeRobot.iml 18 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /workspace.xml 3 | -------------------------------------------------------------------------------- /.idea/PyOfficeRobot.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 程序员晚枫 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PyOfficeRobot/__init__.py: -------------------------------------------------------------------------------- 1 | from PyOfficeRobot.api import chat 2 | from PyOfficeRobot.api import file 3 | from PyOfficeRobot.api import friend 4 | from PyOfficeRobot.api import group 5 | from PyOfficeRobot.lib.CONST import SPLIT_LINE 6 | 7 | __version__ = '0.1.25' -------------------------------------------------------------------------------- /PyOfficeRobot/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderWanFeng/PyOfficeRobot/c92ba08f35efe41613ef052a0f043b35d77f8b5c/PyOfficeRobot/api/__init__.py -------------------------------------------------------------------------------- /PyOfficeRobot/api/chat.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import os 3 | 4 | import poai 5 | import porobot as porobot 6 | import schedule 7 | 8 | from PyOfficeRobot.core.WeChatType import WeChat 9 | from PyOfficeRobot.lib.decorator_utils.instruction_url import instruction 10 | 11 | wx = WeChat() 12 | 13 | 14 | # @act_info(ACT_TYPE.MESSAGE) 15 | @instruction 16 | def send_message(who: str, message: str) -> None: 17 | """ 18 | 给指定人,发送一条消息 19 | :param who: 20 | :param message: 21 | :return: 22 | """ 23 | 24 | # 获取会话列表 25 | wx.GetSessionList() 26 | wx.ChatWith(who) # 打开`who`聊天窗口 27 | # for i in range(10): 28 | wx.SendMsg(message, who) # 向`who`发送消息:你好~ 29 | 30 | 31 | @instruction 32 | def chat_by_keywords(who: str, keywords: str): 33 | wx.GetSessionList() # 获取会话列表 34 | wx.ChatWith(who) # 打开`who`聊天窗口 35 | temp_msg = '' 36 | while True: 37 | try: 38 | friend_name, receive_msg = wx.GetAllMessage[-1][0], wx.GetAllMessage[-1][1] # 获取朋友的名字、发送的信息 39 | if (friend_name == who) & (receive_msg != temp_msg) & (receive_msg in keywords.keys()): 40 | """ 41 | 条件: 42 | 朋友名字正确:(friend_name == who) 43 | 不是上次的对话:(receive_msg != temp_msg) 44 | 对方内容在自己的预设里:(receive_msg in kv.keys()) 45 | """ 46 | 47 | temp_msg = receive_msg 48 | wx.SendMsg(keywords[receive_msg], who) # 向`who`发送消息 49 | except: 50 | pass 51 | 52 | 53 | @instruction 54 | def receive_message(who='文件传输助手', txt='userMessage.txt', output_path='./'): 55 | wx.GetSessionList() # 获取会话列表 56 | wx.ChatWith(who) # 打开`who`聊天窗口 57 | while True: 58 | friend_name, receive_msg = wx.GetAllMessage[-1][0], wx.GetAllMessage[-1][1] # 获取朋友的名字、发送的信息 59 | current_time = datetime.datetime.now() 60 | cut_line = '^^^----------^^^' 61 | print('--' * 88) 62 | with open(os.path.join(output_path, txt), 'a+') as output_file: 63 | output_file.write('\n') 64 | output_file.write(cut_line) 65 | output_file.write('\n') 66 | output_file.write(str(current_time)) 67 | output_file.write('\n') 68 | output_file.write(str(friend_name)) 69 | output_file.write('\n') 70 | output_file.write(str(receive_msg)) 71 | output_file.write('\n') 72 | 73 | 74 | @instruction 75 | def send_message_by_time(who, message, time): 76 | schedule.every().day.at(time).do(send_message, who=who, message=message) 77 | while True: 78 | schedule.run_pending() 79 | 80 | 81 | @instruction 82 | def chat_by_gpt(who, api_key, model_engine="text-davinci-002", max_tokens=1024, n=1, stop=None, temperature=0.5, 83 | top_p=1, 84 | frequency_penalty=0.0, presence_penalty=0.6): 85 | wx.GetSessionList() # 获取会话列表 86 | wx.ChatWith(who) # 打开`who`聊天窗口 87 | temp_msg = None 88 | while True: 89 | try: 90 | friend_name, receive_msg = wx.GetAllMessage[-1][0], wx.GetAllMessage[-1][1] # 获取朋友的名字、发送的信息 91 | if (friend_name == who) & (receive_msg != temp_msg): 92 | """ 93 | 条件: 94 | 朋友名字正确:(friend_name == who) 95 | 不是上次的对话:(receive_msg != temp_msg) 96 | 对方内容在自己的预设里:(receive_msg in kv.keys()) 97 | """ 98 | print(f'【{who}】发送:【{receive_msg}】') 99 | temp_msg = receive_msg 100 | reply_msg = poai.chatgpt.chat(api_key, receive_msg, 101 | model_engine, max_tokens, n, stop, temperature, 102 | top_p, frequency_penalty, presence_penalty) 103 | wx.SendMsg(reply_msg, who) # 向`who`发送消息 104 | except: 105 | pass 106 | 107 | 108 | @instruction 109 | def chat_robot(who): 110 | wx.GetSessionList() # 获取会话列表 111 | wx.ChatWith(who) # 打开`who`聊天窗口 112 | temp_msg = None 113 | while True: 114 | try: 115 | friend_name, receive_msg = wx.GetAllMessage[-1][0], wx.GetAllMessage[-1][1] # 获取朋友的名字、发送的信息 116 | if (friend_name == who) & (receive_msg != temp_msg): 117 | """ 118 | 条件: 119 | 朋友名字正确:(friend_name == who) 120 | 不是上次的对话:(receive_msg != temp_msg) 121 | 对方内容在自己的预设里:(receive_msg in kv.keys()) 122 | """ 123 | print(f'【{who}】发送:【{receive_msg}】') 124 | temp_msg = receive_msg 125 | reply_msg = porobot.normal.chat(receive_msg) 126 | wx.SendMsg(reply_msg, who) # 向`who`发送消息 127 | except: 128 | pass 129 | 130 | 131 | @instruction 132 | def chat_ali(who, key): 133 | wx.GetSessionList() # 获取会话列表 134 | wx.ChatWith(who) # 打开`who`聊天窗口 135 | temp_msg = None 136 | while True: 137 | try: 138 | friend_name, receive_msg = wx.GetAllMessage[-1][0], wx.GetAllMessage[-1][1] # 获取朋友的名字、发送的信息 139 | if (friend_name == who) & (receive_msg != temp_msg): 140 | """ 141 | 条件: 142 | 朋友名字正确:(friend_name == who) 143 | 不是上次的对话:(receive_msg != temp_msg) 144 | 对方内容在自己的预设里:(receive_msg in kv.keys()) 145 | """ 146 | print(f'【{who}】发送:【{receive_msg}】') 147 | reply_msg = poai.chat.ali(key, prompt=receive_msg) 148 | wx.SendMsg(reply_msg, who) # 向`who`发送消息 149 | except: 150 | pass 151 | 152 | 153 | def chat_by_zhipu(who, key, model='glm-4'): 154 | wx.GetSessionList() # 获取会话列表 155 | wx.ChatWith(who) # 打开`who`聊天窗口 156 | temp_msg = None 157 | while True: 158 | try: 159 | friend_name, receive_msg = wx.GetAllMessage[-1][0], wx.GetAllMessage[-1][1] # 获取朋友的名字、发送的信息 160 | if (friend_name == who) & (receive_msg != temp_msg): 161 | """ 162 | 条件: 163 | 朋友名字正确:(friend_name == who) 164 | 不是上次的对话:(receive_msg != temp_msg) 165 | 对方内容在自己的预设里:(receive_msg in kv.keys()) 166 | """ 167 | print(f'【{who}】发送:【{receive_msg}】') 168 | reply_msg = poai.chat.zhipu(key, prompt=receive_msg, model=model) 169 | wx.SendMsg(reply_msg, who) # 向`who`发送消息 170 | except: 171 | pass 172 | 173 | 174 | def chat_by_deepseek(who, api_key): 175 | wx.GetSessionList() # 获取会话列表 176 | wx.ChatWith(who) # 打开`who`聊天窗口 177 | temp_msg = None 178 | while True: 179 | try: 180 | friend_name, receive_msg = wx.GetAllMessage[-1][0], wx.GetAllMessage[-1][1] # 获取朋友的名字、发送的信息 181 | if (friend_name == who) & (receive_msg != temp_msg): 182 | """ 183 | 条件: 184 | 朋友名字正确:(friend_name == who) 185 | 不是上次的对话:(receive_msg != temp_msg) 186 | 对方内容在自己的预设里:(receive_msg in kv.keys()) 187 | """ 188 | print(f'【{who}】发送:【{receive_msg}】') 189 | reply_msg = poai.chat.deepseek(api_key, content=receive_msg) 190 | wx.SendMsg(reply_msg, who) # 向`who`发送消息 191 | except: 192 | pass 193 | -------------------------------------------------------------------------------- /PyOfficeRobot/api/file.py: -------------------------------------------------------------------------------- 1 | from PyOfficeRobot.core.WeChatType import WeChat 2 | from PyOfficeRobot.lib.decorator_utils.instruction_url import instruction 3 | 4 | wx = WeChat() 5 | 6 | 7 | # @act_info(ACT_TYPE.FILE) 8 | @instruction 9 | def send_file(who: str, file: str): 10 | """ 11 | 发送任意类型的文件 12 | :param who: 13 | :param file: 文件路径 14 | :return: 15 | """ 16 | wx.ChatWith(who) # 打开聊天窗口 17 | # wx.SendFiles(file) 18 | wx.test_SendFiles(filepath=file, who=who) # 添加who参数:雷杰 19 | 20 | # 注:为保证发送文件稳定性,首次发送文件可能花费时间较长,后续调用会缩短发送时间 21 | 22 | 23 | import uiautomation as ui_CoderWanFeng 24 | 25 | """ isinstance()函数知识点: 26 | 27 | type判断函数类型是什么,而isinstance是通过判断对象是否是已知的类型 28 | 但是isinstance比type高级一些(功能上的差异) 29 | type() ,不考虑继承关系(子类不是父类类型) 30 | isinstance() ,考虑继承关系(子类是父类类型) 31 | 32 | a = 10086 33 | isinstance (a,int) # true 34 | isinstance (a,str) # false 35 | isinstance (a,(str,int,list)) # 只要满足元组类型中的其中一个即可,答案是满足,所以为false 36 | """ 37 | 38 | 39 | def get_group_list(): 40 | """ 41 | author: Zijian 42 | :return: 43 | """ 44 | ui_CoderWanFeng.uiautomation.SetGlobalSearchTimeout(2) 45 | wechat_win = ui_CoderWanFeng.WindowControl(Depth=1, Name="微信", ClassName="WeChatMainWndForPC") 46 | wechat_win.SwitchToThisWindow() 47 | wechat_win.SetActive() 48 | wechat_win.SetTopmost() 49 | 50 | ### 点击右上角"聊天信息" 51 | chatinfo_button = wechat_win.ButtonControl(Name="聊天信息") 52 | chatinfo_button.Click(waitTime=0.5) 53 | 54 | ### 点击下拉菜单按钮"查看更多" 如果群里人数少这个按钮可能不存在 55 | more_button = wechat_win.ButtonControl(Name="查看更多") 56 | if more_button.Exists(0, 0): 57 | more_button.Click(0, 0, simulateMove=False) 58 | 59 | ### 获取"群聊名称" 先定位"群聊名称",再获取下一个兄弟节点,再获取第一个子节点,.Name取出里面的文字 60 | group_name = wechat_win.TextControl(Name="群聊名称").GetNextSiblingControl().GetFirstChildControl().Name 61 | print(group_name) 62 | 63 | ### 获取聊天成员列表控件,并且要获取边框范围 64 | nums = wechat_win.ListControl(Name="聊天成员") 65 | rect = nums.GetParentControl().BoundingRectangle # 获取父级范围 66 | print(rect) 67 | numbers = nums.GetChildren() 68 | # for member in numbers: 69 | sum_info = [] 70 | for index, member in enumerate(numbers): 71 | # print(type(member)) 72 | # print(ui_CoderWanFeng.ListItemControl) 73 | 74 | # 判断列表的每一个子成员 是不是列表项目控件,如果不是就跳过 75 | if not isinstance(member, ui_CoderWanFeng.ListItemControl): 76 | continue 77 | 78 | # 判断列表的每一个子成员 是不是列表项目控件的名称是否存在名字,或有添加,删除,移除的关键字,如果不是就跳过。 79 | if not member.Name or member.Name in ("添加", "删除", "移出"): 80 | continue 81 | 82 | # 再判断当前时候有 快捷键被按下的状态,如果有直接break跳出循环停止采集. 83 | if ui_CoderWanFeng.IsKeyPressed(ui_CoderWanFeng.Keys.VK_F2): 84 | print("F2已被按下,停止采集") 85 | break 86 | 87 | # print(" ------- " + member.Name + " ------- ") 88 | # 判断 每个成员的边界底部是否超出整个列表成员控件边框的底部,如果超过就发送下滚轮热键 89 | pos = member.BoundingRectangle 90 | if pos.bottom >= rect.bottom: 91 | ui_CoderWanFeng.WheelDown(waitTime=0.5) 92 | 93 | ### 先左键点击每个成员,再用右键点击取消 94 | # 左键点击每个成员 95 | member.Click(waitTime=0.01) 96 | 97 | # 左键后会出现一个窗格控件 WalkControl返回的是一个元组类型(control, depth)控件,换句话说就是一个长度为2的元组对象 for循环迭代器时需要用两个变量去接收 如果用一个变量去接受返回的是一个元组长度为2的对象 98 | 99 | user_info_pane = ui_CoderWanFeng.PaneControl(Name="微信") 100 | # user_info_pane拿到用户信息弹窗后截图保存本地文件 101 | # user_info_pane.CaptureToImage(savePath=f"{index}.png") 102 | 103 | # 用户信息字典 104 | user_info = {} 105 | user_info['群列表显示'] = member.Name 106 | for control, depth in ui_CoderWanFeng.WalkControl(user_info_pane): 107 | # print(control) for循环迭代器时需要用两个变量去接收 如果用一个变量去接受返回的是一个元组对象长度为2的 108 | 109 | if control.ControlTypeName == "TextControl": 110 | # k = c.Name.rstrip(":") #rstrip() 删除 string 字符串末尾的指定字符 111 | text = control.Name 112 | if ":" in text: # 如果这个文本控件类型里面的文本包含中文冒号":",就Get他的下一个兄弟节点 再用·Name的方法取出里面的内容 113 | k = text.rstrip(":") 114 | v = control.GetNextSiblingControl().Name 115 | # print(k,v) 116 | user_info[k] = v 117 | if "来源" in text: 118 | k = text 119 | v = control.GetNextSiblingControl().Name 120 | # print(k,v) 121 | user_info[k] = v 122 | if "备注名" in text: 123 | k = text 124 | v = control.GetNextSiblingControl().Name 125 | # print(k,v) 126 | user_info[k] = v 127 | if "企业" == text: 128 | k = text 129 | a = control.GetNextSiblingControl() 130 | v = a.GetNextSiblingControl().Name 131 | # print(k,v) 132 | user_info[k] = v 133 | if "实名" == text: 134 | k = text 135 | a = control.GetNextSiblingControl() 136 | v = a.GetNextSiblingControl().Name 137 | # print(k,v) 138 | user_info[k] = v 139 | if "商城" == text: 140 | k = text 141 | v = control.GetNextSiblingControl().Name 142 | # print(k,v) 143 | user_info[k] = v 144 | print(user_info) 145 | sum_info.append(user_info) 146 | 147 | # 右键点击每个成员取消个人弹框 或者 发送ESC 快捷键 148 | # member.RightClick(waitTime=0.01) 149 | ui_CoderWanFeng.SendKeys('{ESC}') 150 | 151 | print(sum_info) 152 | 153 | ### 将列表字典传给pandas库分析数据 154 | import pandas as pd 155 | save_path = "微信群信息采集.xlsx" 156 | 157 | df = pd.DataFrame(sum_info) 158 | df = df.reset_index(drop=True) ### False是保留原先索引建立新的索引 True是重新建立索引 159 | df.to_excel(excel_writer=save_path, sheet_name='微信群信息采集', index=False) 160 | print(df) 161 | -------------------------------------------------------------------------------- /PyOfficeRobot/api/friend.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @个人网站 :www.python-office.com 6 | @Date :2023/4/23 23:01 7 | @Description : 8 | ''' 9 | from time import sleep 10 | 11 | from pywinauto.application import * 12 | from pywinauto.base_wrapper import * 13 | from pywinauto.controls.uiawrapper import UIAWrapper 14 | from pywinauto.findwindows import ElementNotFoundError 15 | from pywinauto.keyboard import send_keys 16 | from pywinauto.uia_element_info import UIAElementInfo 17 | 18 | from PyOfficeRobot.lib.decorator_utils.instruction_url import instruction 19 | 20 | 21 | def _Carry_TXL(App_Object, Hello_Str, Tel_Number, notes): 22 | """ 23 | 该函数为申请好友验证时的函数胡\n 24 | :param App_Object: 微信窗口操作对象 25 | :param Hello_Str: 打招呼的字符串 26 | :param Tel_Number: 备注名,用于备注该用户的手机号码 27 | :param notes: 备注名 28 | :return: None 29 | """ 30 | # 31 | # Anchor为锚点 Target为目标点 32 | Anchor_1 = None 33 | try: 34 | Anchor_1 = App_Object.child_window(title='发送添加朋友申请') 35 | Anchor_1.draw_outline(colour='green', thickness=5) 36 | except ElementNotFoundError: 37 | # 直接添加上好久就返回 38 | return False 39 | Anchor_1_Wrapper = Anchor_1.wrapper_object() 40 | Anchor_1_Wrapper_Parent = Anchor_1_Wrapper.element_info.parent 41 | Children_1 = Anchor_1_Wrapper_Parent.children() 42 | Target_1 = Children_1[1] 43 | Target_1_Wrapper = UIAWrapper(Target_1) 44 | Target_1_Wrapper.draw_outline(colour='red', thickness=5) 45 | Target_1_Wrapper.click_input() 46 | Target_1_Wrapper.click_input() 47 | for _ in range(50): 48 | send_keys("{VK_END}") 49 | send_keys("{VK_BACK}") 50 | Target_1_Wrapper.type_keys(Hello_Str) 51 | 52 | Anchor_2 = App_Object.child_window(title='备注名') 53 | Anchor_2.draw_outline(colour='green', thickness=5) 54 | Anchor_2_Wrapper = Anchor_2.wrapper_object() 55 | Anchor_2_Wrapper_Parent = Anchor_2_Wrapper.element_info.parent 56 | Children_2 = Anchor_2_Wrapper_Parent.children() 57 | Target_2 = Children_2[1] 58 | Target_2_Wrapper = UIAWrapper(Target_2) 59 | Target_2_Wrapper.draw_outline(colour='red', thickness=5) 60 | Target_2_Wrapper.click_input() 61 | Target_2_Wrapper.click_input() 62 | for _ in range(30): 63 | send_keys("{VK_END}") 64 | send_keys("{VK_BACK}") 65 | Target_2_Wrapper.type_keys(notes) 66 | # 67 | # App_Object.capture_as_image().save(Tel_Number + ".jpg") 68 | 69 | Button_Yes = App_Object.child_window(title='确定') 70 | Button_Yes_Wrapper = Button_Yes.wrapper_object() 71 | Button_Yes_Wrapper.draw_outline(colour='red', thickness=5) 72 | Button_Yes_Wrapper.click_input() 73 | 74 | 75 | def Get_NowTime(): 76 | "【当前时间:%s-%s-%s-:%s:%s:%s】正在读取第%s行数据,该公司的联系电话有如下:\n【%s】" 77 | return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) 78 | 79 | 80 | def _find_friend(WX_Windows, Tel_Number, ErrorCount): 81 | """ 82 | 该函数用于在进入通讯录界面,输入手机号码一系列的操作\n 83 | :param WX_Windows: 微信窗口对象 84 | :param Tel_Number: 需要搜索的手机号码 85 | :param ErrorCount: 86 | :return: 87 | """ 88 | # 89 | print("提示:当前在正在对输入的手机号码进行一个查找") 90 | Button_AddFrient = WX_Windows.child_window(title="添加朋友") 91 | Button_AddFrient_Wrapper = Button_AddFrient.wrapper_object() 92 | """:type : pywinauto.controls.uiawrapper.UIAWrapper""" 93 | Button_AddFrient_Wrapper.draw_outline(colour='red', thickness=5) 94 | Button_AddFrient_Wrapper.click_input() 95 | 96 | Edit_Number = WX_Windows.child_window(title="微信号/手机号") 97 | Edit_Number_Wrapper = Edit_Number.wrapper_object() 98 | """:type : pywinauto.controls.uiawrapper.UIAWrapper""" 99 | Edit_Number_Wrapper.draw_outline(colour='red', thickness=5) 100 | Edit_Number_Wrapper.click_input() 101 | Edit_Number_Wrapper.type_keys(Tel_Number) 102 | # 会获取到两个搜索的title,使用迭代方式 103 | Button_Find = WX_Windows.descendants(title='搜索:' + Tel_Number) 104 | """:type : pywinauto.controls.uiawrapper.UIAWrapper""" 105 | Button_Find[0].draw_outline(colour='red', thickness=5) 106 | Button_Find[0].click_input() 107 | try: 108 | 109 | Button_AddTXL = WX_Windows.child_window(title='添加到通讯录') 110 | Button_AddTXL_Wrapper = Button_AddTXL.wrapper_object() 111 | """:type : pywinauto.controls.uiawrapper.UIAWrapper""" 112 | Button_AddTXL_Wrapper.draw_outline(colour="red", thickness=5) 113 | Button_AddTXL_Wrapper.click_input() 114 | print("提示:当前号码[ %s ]可以进行一个添加" % (Tel_Number)) 115 | 116 | return True 117 | except: 118 | try: 119 | print( 120 | "错误:当前号码出现错误,可能原因为 1.已经添加过该好友 2.该号码不存在 3.出现频繁次数了 当前号码为 : %s" % ( 121 | Tel_Number)) 122 | print("注意:当前出错次数为 : %d" % (ErrorCount)) 123 | 124 | find_result = WX_Windows.child_window(title=r'搜索结果') 125 | find_result_wrapper = find_result.wrapper_object() 126 | assert isinstance(find_result_wrapper, UIAWrapper) 127 | find_childs = find_result_wrapper.children() 128 | 129 | if (len(find_childs) == 1): 130 | print("\t\t 【警告】:%s-----当前号码并没有进行一个点击,请后续再进行操作" % (Get_NowTime())) 131 | 132 | elif (len(find_childs) == 2): 133 | find_childs[0].draw_outline(colour='red', thickness=5) 134 | find_resule_info = find_childs[0].element_info 135 | assert isinstance(find_resule_info, UIAElementInfo) 136 | print("\t\t 【错误】:%s-----%s" % (Get_NowTime(), find_resule_info.name)) 137 | print("\t\t 【错误】:%s-----%s" % (Get_NowTime(), find_resule_info.name)) 138 | 139 | except: 140 | print("\t\t %s提示:当前遍历号码[ %s ]已经是微信好友" % (Get_NowTime(), Tel_Number)) 141 | print("\t\t %s提示:当前遍历号码[ %s ]已经是微信好友" % (Get_NowTime(), Tel_Number)) 142 | 143 | return False 144 | # 145 | 146 | 147 | def _Open_TXL(Button_LT_Wrapper, Button_TXL_Wrapper, Button_SC_Wrapper): 148 | # 149 | """ 150 | 该函数为打开通讯录界面\n 151 | :return: 152 | """ 153 | print("提示:当前正在进入通讯录界面") 154 | Button_SC_Wrapper.draw_outline(colour="red", thickness=5) 155 | Button_SC_Wrapper.click_input() 156 | sleep(0.5) 157 | # Button_EXE_Wrapper.draw_outline(colour="red", thickness=5) 158 | # Button_EXE_Wrapper.click_input() 159 | sleep(0.5) 160 | Button_LT_Wrapper.draw_outline(colour="red", thickness=5) 161 | Button_LT_Wrapper.click_input() 162 | sleep(0.5) 163 | # Button_EXE_Wrapper.draw_outline(colour="red", thickness=5) 164 | # Button_EXE_Wrapper.click_input() 165 | sleep(0.5) 166 | Button_TXL_Wrapper.draw_outline(colour="red", thickness=5) 167 | Button_TXL_Wrapper.click_input() 168 | sleep(0.5) 169 | # 170 | 171 | 172 | @instruction 173 | def add(num_notes, msg): 174 | # 175 | Get_WeChat_Hwnd = lambda: win32gui.FindWindow("WeChatMainWndForPC", "微信") 176 | WeChat_Hwnd = Get_WeChat_Hwnd() 177 | # 178 | # 179 | win32gui.ShowWindow(WeChat_Hwnd, win32con.SW_RESTORE) 180 | # 保证微信显示在窗口的最前面 181 | win32gui.SetForegroundWindow(WeChat_Hwnd) 182 | # win32gui.SetWindowPos(WeChat_Hwnd, win32con.HWND_TOPMOST, 0,0,800,800, win32con.SWP_NOMOVE | win32con.SWP_NOACTIVATE| win32con.SWP_NOOWNERZORDER|win32con.SWP_SHOWWINDOW) 183 | win32gui.MoveWindow(WeChat_Hwnd, 1920 - 800, 0, 800, 800, True) 184 | print("Msg:窗口设置完毕") 185 | # 186 | 187 | # 188 | App_Object = Application(backend="uia").connect(handle=WeChat_Hwnd) 189 | WX_Windows = App_Object['微信'] 190 | """:type : pywinauto.application.WindowSpecification""" 191 | WX_Wrapper = WX_Windows.wrapper_object() 192 | """:type : pywinauto.controls.uiawrapper.UIAWrapper""" 193 | WX_Wrapper.draw_outline(colour="red", thickness=5) 194 | # 195 | # Button_ZD = WX_Windows.child_window(title='置顶') 196 | # Button_ZD.click_input() 197 | # 198 | Button_LT = WX_Windows.child_window(title='聊天') 199 | Button_TXL = WX_Windows.child_window(title='通讯录') 200 | Button_SC = WX_Windows.child_window(title='收藏') 201 | # Button_EXE = WX_Windows.child_window(title='小程序面板') 202 | 203 | Button_LT_Wrapper = Button_LT.wrapper_object() 204 | Button_TXL_Wrapper = Button_TXL.wrapper_object() 205 | Button_SC_Wrapper = Button_SC.wrapper_object() 206 | # Button_EXE_Wrapper = Button_EXE.wrapper_object() 207 | 208 | Count = 1 209 | # 210 | for num in num_notes.keys(): 211 | _Open_TXL(Button_LT_Wrapper, Button_TXL_Wrapper, Button_SC_Wrapper) 212 | result = _find_friend(WX_Windows=WX_Windows, Tel_Number=num, ErrorCount=Count) 213 | # 如果失败就不用手动添加了 214 | if result: 215 | _Carry_TXL(App_Object=WX_Windows, Hello_Str=msg, 216 | Tel_Number=num, notes=num_notes[num]) 217 | 218 | 219 | if __name__ == "__main__": 220 | msg = "你好,我是程序员晚枫,全网同名。" 221 | # num_list = ['CoderWanFeng'] 222 | num_notes = { 223 | # 'CoderWanFeng': '北京-晚枫-学生', 224 | 'hdylw1024': '上海-晚枫-乞丐', 225 | } 226 | add(msg=msg, num_notes=num_notes) 227 | -------------------------------------------------------------------------------- /PyOfficeRobot/api/group.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | import sys 3 | import time 4 | import pandas as pd 5 | import win32api 6 | import win32con 7 | 8 | from PySide6.QtWidgets import QApplication 9 | 10 | from pathlib import Path 11 | from loguru import logger 12 | from pofile import mkdir 13 | from PyOfficeRobot.core.WeChatType import WeChat 14 | from PyOfficeRobot.core.group.Start import MyWidget 15 | from PyOfficeRobot.lib.decorator_utils.instruction_url import instruction 16 | 17 | wx = WeChat() 18 | 19 | 20 | @instruction 21 | def send(): 22 | app = QApplication(sys.argv) 23 | # 初始化QApplication,界面展示要包含在QApplication初始化之后,结束之前 24 | window = MyWidget() 25 | window.show() 26 | # 初始化并展示我们的界面组件 27 | sys.exit(app.exec_()) 28 | # 结束QApplication 29 | 30 | 31 | def chat_by_keywords(who: str, keywords: dict, match_type: str) -> None: 32 | """ 33 | 根据关键词进行聊天回复。 34 | 35 | Args: 36 | who (str): 要与之聊天的群名。 37 | keywords (dict): 匹配关键字的字典,键为关键词,值为回复内容。 38 | match_type (str): 匹配类型,'exact' 表示完全匹配,'contains' 表示包含匹配。 39 | 40 | Returns: 41 | None 42 | 43 | """ 44 | 45 | wx.GetSessionList() # 获取会话列表 46 | wx.ChatWith(who) # 打开`who`聊天窗口 47 | last_processed_msg = None 48 | while True: 49 | time.sleep(3) 50 | last_msg = wx.MsgList.GetChildren()[-1].Name 51 | if last_msg and last_msg != last_processed_msg: 52 | if last_msg not in keywords.values(): 53 | matched_reply = None 54 | if match_type == 'exact': 55 | matched_reply = keywords.get(last_msg) 56 | elif match_type == 'contains': 57 | matched_reply = next((value for key, value in keywords.items() if key in last_msg), None) 58 | if matched_reply: 59 | wx.SendMsg(matched_reply, who) 60 | last_processed_msg = last_msg 61 | else: 62 | print(f"没有匹配的关键字,匹配类型:{match_type}") 63 | else: 64 | print("最后一条消息是自动回复内容,跳过回复") 65 | else: 66 | print("没有新消息") 67 | 68 | 69 | def collect_msg(who='文件传输助手', output_excel_path='userMessage.txt', output_path='./',names=None, scroll_num=6): 70 | 71 | wx.GetSessionList() # 获取会话列表 72 | wx.ChatWith(who) # 打开`who`聊天窗口 73 | 74 | # 获取当前鼠标位置 75 | x, y = win32api.GetCursorPos() 76 | 77 | # 向右移动 250 像素 78 | win32api.SetCursorPos((x + 250, y)) 79 | 80 | # 向上滚动鼠标 scroll_num 次 81 | for i in range(scroll_num): 82 | # 向上滚动鼠标 83 | scroll_up() 84 | print(f"向上滚动鼠标{i + 1}次") 85 | time.sleep(0.5) 86 | 87 | num = 0 88 | messages_list = [] 89 | index = 0 90 | receive_msgs = wx.GetAllMessage # 获取朋友的名字、发送的信息、ID 91 | # print(f"---------{receive_msgs}") 92 | 93 | while True: 94 | if 0 - num == len(receive_msgs): 95 | print('没有更多消息了') 96 | # print(num) 97 | break 98 | num -= 1 99 | friend_name = receive_msgs[num][0] 100 | receive_msg = receive_msgs[num][1] 101 | 102 | # 如果是系统信息,则跳过 103 | if friend_name == 'SYS': 104 | index += 1 105 | continue 106 | 107 | elif friend_name == 'Time': # ('Time', '10:53', '4226902524247') 108 | index += 1 109 | if len(receive_msg.split(' ')) > 1: 110 | today = receive_msg.split(' ')[0] 111 | timestamp = receive_msg.split(' ')[1] 112 | else: 113 | today = None 114 | timestamp = receive_msg 115 | friend_name = None 116 | text = None 117 | image = None 118 | 119 | elif names is not None and friend_name not in names: 120 | continue 121 | 122 | else: 123 | index += 1 124 | today = None 125 | timestamp = None 126 | if receive_msg == '[图片]': 127 | text = None 128 | image = receive_msg 129 | else: 130 | text = receive_msg 131 | image = None 132 | 133 | data = { 134 | "序号": index, 135 | "日期": today, 136 | "时间": timestamp, 137 | "好友": friend_name, 138 | "文字聊天内容":text, 139 | "图片聊天内容":image, 140 | "备注": None, 141 | } 142 | # print(data) 143 | messages_list.append(data) 144 | # print(messages_list) 145 | 146 | mkdir(Path(output_path).absolute()) # 如果不存在,则创建输出目录 147 | if output_excel_path.endswith('.xlsx') or output_excel_path.endswith('xls'): # 如果指定的输出excel结尾不正确,则报错退出 148 | abs_output_excel = Path(output_path).absolute() / output_excel_path 149 | else: # 指定了,但不是xlsx或者xls结束 150 | raise BaseException( 151 | f'输出结果名:output_excel参数,必须以xls或者xlsx结尾,您的输入:{output_excel_path}有误,请修改后重新运行') 152 | 153 | df = pd.DataFrame(messages_list) 154 | df.to_excel(str(abs_output_excel), index=False, engine='openpyxl') 155 | logger.info(f'识别结果已保存到:{output_path}') 156 | 157 | def scroll_up(amount=1): 158 | for _ in range(amount): 159 | win32api.mouse_event(win32con.MOUSEEVENTF_WHEEL, 0, 0, 500) # 500 是滚轮“一个刻度”的值 160 | time.sleep(0.1) # 可选,增加间隔让滚动生效 161 | 162 | 163 | if __name__ == "__main__": 164 | # who = '测试群' 165 | # keywords = { 166 | # "报名": "你好,这是报名链接:www.python-office.com", 167 | # "学习": "你好,这是学习链接:www.python-office.com", 168 | # "课程": "你好,这是课程链接:www.python-office.com" 169 | # } 170 | # match_type = 'contains' # 关键字匹配类型 包含:contains 精确:exact 171 | # chat_by_keywords(who=who, keywords=keywords, match_type=match_type) 172 | collect_msg(who='✨python-office开源小组', output_excel_path='userMessage.xlsx', output_path='./', names=['程序员晚枫'], scroll_num=6) 173 | -------------------------------------------------------------------------------- /PyOfficeRobot/core/WeChatType.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | ''' 3 | @学习网站 :https://www.python-office.com 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫,微信:CoderWanFeng 6 | @代码日期 :2022/9/26 21:43 7 | @本段代码的视频说明 : 8 | ''' 9 | # sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='gb18030') 10 | 11 | import os 12 | import time 13 | from ctypes import * 14 | from pathlib import Path 15 | 16 | import uiautomation as ui_CoderWanFeng 17 | import win32clipboard # pywin32 18 | import win32clipboard as wc 19 | import win32con 20 | import win32gui 21 | 22 | PUBLISH_ID = '公众号:Python自动化办公社区' 23 | 24 | COPYDICT = {} 25 | 26 | 27 | class WxParam: 28 | SYS_TEXT_HEIGHT = 33 29 | TIME_TEXT_HEIGHT = 34 30 | RECALL_TEXT_HEIGHT = 45 31 | CHAT_TEXT_HEIGHT = 52 32 | CHAT_IMG_HEIGHT = 117 33 | SpecialTypes = ['[文件]', '[图片]', '[视频]', '[音乐]', '[链接]'] 34 | 35 | 36 | class WxUtils: 37 | def SplitMessage(MsgItem): 38 | ui_CoderWanFeng.SetGlobalSearchTimeout(0) 39 | MsgItemName = MsgItem.Name 40 | if MsgItem.BoundingRectangle.height() == WxParam.SYS_TEXT_HEIGHT: 41 | Msg = ('SYS', MsgItemName, ''.join([str(i) for i in MsgItem.GetRuntimeId()])) 42 | elif MsgItem.BoundingRectangle.height() == WxParam.TIME_TEXT_HEIGHT: 43 | Msg = ('Time', MsgItemName, ''.join([str(i) for i in MsgItem.GetRuntimeId()])) 44 | elif MsgItem.BoundingRectangle.height() == WxParam.RECALL_TEXT_HEIGHT: 45 | if '撤回' in MsgItemName: 46 | Msg = ('Recall', MsgItemName, ''.join([str(i) for i in MsgItem.GetRuntimeId()])) 47 | else: 48 | Msg = ('SYS', MsgItemName, ''.join([str(i) for i in MsgItem.GetRuntimeId()])) 49 | else: 50 | Index = 1 51 | User = MsgItem.ButtonControl(foundIndex=Index) 52 | try: 53 | while True: 54 | if User.Name == '': 55 | Index += 1 56 | User = MsgItem.ButtonControl(foundIndex=Index) 57 | else: 58 | break 59 | Msg = (User.Name, MsgItemName, ''.join([str(i) for i in MsgItem.GetRuntimeId()])) 60 | except: 61 | Msg = ('SYS', MsgItemName, ''.join([str(i) for i in MsgItem.GetRuntimeId()])) 62 | ui_CoderWanFeng.SetGlobalSearchTimeout(10.0) 63 | return Msg 64 | 65 | def SetClipboard(data, dtype='text'): 66 | '''复制文本信息或图片到剪贴板 67 | data : 要复制的内容,str 或 Image 图像''' 68 | if dtype.upper() == 'TEXT': 69 | type_data = win32con.CF_UNICODETEXT 70 | elif dtype.upper() == 'IMAGE': 71 | from io import BytesIO 72 | type_data = win32con.CF_DIB 73 | output = BytesIO() 74 | data.save(output, 'BMP') 75 | data = output.getvalue()[14:] 76 | else: 77 | raise ValueError('param (dtype) only "text" or "image" supported') 78 | wc.OpenClipboard() 79 | wc.EmptyClipboard() 80 | wc.SetClipboardData(type_data, data) 81 | wc.CloseClipboard() 82 | 83 | def Screenshot(hwnd, to_clipboard=True): 84 | '''为句柄为hwnd的窗口程序截图 85 | hwnd : 句柄 86 | to_clipboard : 是否复制到剪贴板 87 | ''' 88 | import pyscreenshot as shot 89 | bbox = win32gui.GetWindowRect(hwnd) 90 | win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, 0, 0, 0, 0, \ 91 | win32con.SWP_SHOWWINDOW | win32con.SWP_NOMOVE | win32con.SWP_NOSIZE) 92 | win32gui.SetWindowPos(hwnd, win32con.HWND_NOTOPMOST, 0, 0, 0, 0, \ 93 | win32con.SWP_SHOWWINDOW | win32con.SWP_NOMOVE | win32con.SWP_NOSIZE) 94 | win32gui.BringWindowToTop(hwnd) 95 | im = shot.grab(bbox) 96 | if to_clipboard: 97 | WxUtils.SetClipboard(im, 'image') 98 | return im 99 | 100 | def SavePic(savepath=None, filename=None): 101 | Pic = ui_CoderWanFeng.WindowControl(ClassName='ImagePreviewWnd', Name='图片查看') 102 | Pic.SendKeys('{Ctrl}s') 103 | SaveAs = Pic.WindowControl(ClassName='#32770', Name='另存为...') 104 | SaveAsEdit = SaveAs.EditControl(ClassName='Edit', Name='文件名:') 105 | SaveButton = Pic.ButtonControl(ClassName='Button', Name='保存(S)') 106 | PicName, Ex = os.path.splitext(SaveAsEdit.GetValuePattern().Value) 107 | if not savepath: 108 | savepath = os.getcwd() 109 | if not filename: 110 | filename = PicName 111 | FilePath = os.path.realpath(os.path.join(savepath, filename + Ex)) 112 | SaveAsEdit.SendKeys(FilePath) 113 | SaveButton.Click() 114 | Pic.SendKeys('{Esc}') 115 | 116 | def ControlSize(control): 117 | locate = control.BoundingRectangle 118 | size = (locate.width(), locate.height()) 119 | return size 120 | 121 | def ClipboardFormats(unit=0, *units): 122 | units = list(units) 123 | wc.OpenClipboard() 124 | u = wc.EnumClipboardFormats(unit) 125 | wc.CloseClipboard() 126 | units.append(u) 127 | if u: 128 | units = WxUtils.ClipboardFormats(u, *units) 129 | return units 130 | 131 | def CopyDict(): 132 | Dict = {} 133 | for i in WxUtils.ClipboardFormats(): 134 | if i == 0: 135 | continue 136 | wc.OpenClipboard() 137 | try: 138 | content = wc.GetClipboardData(i) 139 | wc.CloseClipboard() 140 | except: 141 | wc.CloseClipboard() 142 | raise ValueError 143 | if len(str(i)) >= 4: 144 | Dict[str(i)] = content 145 | return Dict 146 | 147 | 148 | class WeChat: 149 | def __init__(self): 150 | self.UiaAPI = ui_CoderWanFeng.WindowControl(ClassName='WeChatMainWndForPC') 151 | self.SessionList = self.UiaAPI.ListControl(Name='会话') 152 | # self.EditMsg = self.UiaAPI.EditControl(Name='编辑') 153 | self.SearchBox = self.UiaAPI.EditControl(Name='搜索') 154 | self.MsgList = self.UiaAPI.ListControl(Name='消息') 155 | self.SessionItemList = [] 156 | 157 | def GetSessionList(self, reset=False): 158 | '''获取当前会话列表,更新会话列表''' 159 | self.SessionItem = self.SessionList.ListItemControl() 160 | SessionList = [] 161 | if reset: 162 | self.SessionItemList = [] 163 | for i in range(100): 164 | try: 165 | wf_name = self.SessionItem.Name 166 | except: 167 | break 168 | if wf_name not in self.SessionItemList: 169 | self.SessionItemList.append(wf_name) 170 | if wf_name not in SessionList: 171 | SessionList.append(wf_name) 172 | self.SessionItem = self.SessionItem.GetNextSiblingControl() 173 | return SessionList 174 | 175 | def Search(self, keyword): 176 | ''' 177 | 查找微信好友或关键词 178 | keywords: 要查找的关键词,str * 最好完整匹配,不完全匹配只会选取搜索框第一个 179 | ''' 180 | self.UiaAPI.SetFocus() 181 | time.sleep(0.2) 182 | self.UiaAPI.SendKeys('{Ctrl}f', waitTime=1) 183 | self.SearchBox.SendKeys(keyword, waitTime=1.5) 184 | self.SearchBox.SendKeys('{Enter}') 185 | 186 | def ChatWith(self, who, RollTimes=None): 187 | ''' 188 | 打开某个聊天框 189 | who : 要打开的聊天框好友名,str; * 最好完整匹配,不完全匹配只会选取搜索框第一个 190 | RollTimes : 默认向下滚动多少次,再进行搜索 191 | ''' 192 | while win32gui.FindWindow('ChatWnd', None): 193 | ui_CoderWanFeng.WindowControl(ClassName='ChatWnd').SwitchToThisWindow() 194 | ui_CoderWanFeng.WindowControl(ClassName='ChatWnd').ButtonControl(Name='关闭').Click(simulateMove=False) 195 | self.UiaAPI.SwitchToThisWindow() 196 | RollTimes = 10 if not RollTimes else RollTimes 197 | 198 | def roll_to(who=who, RollTimes=RollTimes): 199 | for i in range(RollTimes): 200 | if who not in self.GetSessionList()[:-1]: 201 | self.SessionList.WheelDown(wheelTimes=3, waitTime=0.1 * i) 202 | else: 203 | time.sleep(0.5) 204 | self.SessionList.ListItemControl(Name=who).Click(simulateMove=False) 205 | return 1 206 | return 0 207 | 208 | rollresult = roll_to() 209 | if rollresult: 210 | return 1 211 | else: 212 | self.Search(who) 213 | return roll_to(RollTimes=1) 214 | 215 | def SendMsg(self, msg, who, clear=True): 216 | '''向当前窗口发送消息 217 | msg : 要发送的消息 218 | clear : 是否清除当前已编辑内容 219 | ''' 220 | self.UiaAPI.SwitchToThisWindow() 221 | self.EditMsg = self.UiaAPI.EditControl(SubName=who) 222 | if clear: 223 | self.EditMsg.SendKeys('{Ctrl}a', waitTime=0) 224 | self.EditMsg.SendKeys(msg, waitTime=0) 225 | self.EditMsg.SendKeys('{Enter}', waitTime=0) 226 | 227 | def SendFiles(self, *filepath, not_exists='ignore'): 228 | """向当前聊天窗口发送文件 229 | not_exists: 如果未找到指定文件,继续或终止程序 230 | *filepath: 要复制文件的绝对路径""" 231 | global COPYDICT 232 | key = '' 233 | for file in filepath: 234 | file = os.path.realpath(file) 235 | if not os.path.exists(file): 236 | if not_exists.upper() == 'IGNORE': 237 | print('File not exists:', file) 238 | continue 239 | elif not_exists.upper() == 'RAISE': 240 | raise FileExistsError('File Not Exists: %s' % file) 241 | else: 242 | raise ValueError('param not_exists only "ignore" or "raise" supported') 243 | key += '' % file 244 | if not key: 245 | return 0 246 | if not COPYDICT: 247 | self.EditMsg.SendKeys(' ', waitTime=0) 248 | self.EditMsg.SendKeys('{Ctrl}a', waitTime=0) 249 | self.EditMsg.SendKeys('{Ctrl}c', waitTime=0) 250 | self.EditMsg.SendKeys('{Delete}', waitTime=0) 251 | while True: 252 | try: 253 | COPYDICT = WxUtils.CopyDict() 254 | break 255 | except: 256 | pass 257 | wc.OpenClipboard() 258 | wc.EmptyClipboard() 259 | wc.SetClipboardData(13, '') 260 | wc.SetClipboardData(16, b'\x04\x08\x00\x00') 261 | wc.SetClipboardData(1, b'') 262 | wc.SetClipboardData(7, b'') 263 | for i in COPYDICT: 264 | copydata = COPYDICT[i].replace(b'', 265 | key.encode()).replace(b'type="0"', b'type="3"') 266 | wc.SetClipboardData(int(i), copydata) 267 | wc.CloseClipboard() 268 | self.SendClipboard() 269 | return 1 270 | 271 | def SendClipboard(self, who): 272 | '''向当前聊天页面发送剪贴板复制的内容''' 273 | self.SendMsg('{Ctrl}v', who) 274 | 275 | @property 276 | def GetAllMessage(self): 277 | '''获取当前窗口中加载的所有聊天记录''' 278 | MsgDocker = [] 279 | MsgItems = self.MsgList.GetChildren() 280 | for MsgItem in MsgItems: 281 | MsgDocker.append(WxUtils.SplitMessage(MsgItem)) 282 | return MsgDocker 283 | 284 | @property 285 | def GetLastMessage(self): 286 | '''获取当前窗口中最后一条聊天记录''' 287 | ui_CoderWanFeng.SetGlobalSearchTimeout(1.0) # 每秒更新一次 288 | MsgItem = self.MsgList.GetChildren()[-1] 289 | Msg = WxUtils.SplitMessage(MsgItem) 290 | ui_CoderWanFeng.SetGlobalSearchTimeout(10.0) 291 | return Msg 292 | 293 | def LoadMoreMessage(self, n=0.1): 294 | '''定位到当前聊天页面,并往上滚动鼠标滚轮,加载更多聊天记录到内存''' 295 | n = 0.1 if n < 0.1 else 1 if n > 1 else n 296 | self.MsgList.WheelUp(wheelTimes=int(500 * n), waitTime=0.1) 297 | 298 | def SendScreenshot(self, name=None, classname=None): 299 | '''发送某个桌面程序的截图,如:微信、记事本... 300 | name : 要发送的桌面程序名字,如:微信 301 | classname : 要发送的桌面程序类别名,一般配合 spy 小工具使用,以获取类名,如:微信的类名为 WeChatMainWndForPC''' 302 | if name and classname: 303 | return 0 304 | else: 305 | hwnd = win32gui.FindWindow(classname, name) 306 | if hwnd: 307 | WxUtils.Screenshot(hwnd) 308 | self.SendClipboard() 309 | return 1 310 | else: 311 | return 0 312 | 313 | def SavePic(self, savepath=None, filename=None): 314 | WxUtils.SavePic() 315 | # Pic = ui_CoderWanFeng.WindowControl(ClassName='ImagePreviewWnd', Name='图片查看') 316 | 317 | ################################微信发文件崩溃 https://blog.csdn.net/weixin_45081575/article/details/126810748 318 | 319 | def test_SendFiles(self, filepath, who, not_exists='ignore'): 320 | """向当前聊天窗口发送文件 321 | not_exists: 如果未找到指定文件,继续或终止程序 322 | filepath: 要复制文件的绝对路径""" 323 | if not Path(filepath).exists(): 324 | raise BaseException(f'你指定的文件不存在,请检查filepath后,重新运行:{filepath}') 325 | 326 | class DROPFILES(Structure): 327 | _fields_ = [ 328 | ("pFiles", c_uint), 329 | ("x", c_long), 330 | ("y", c_long), 331 | ("fNC", c_int), 332 | ("fWide", c_bool), 333 | ] 334 | 335 | def setClipboardFiles(paths): 336 | files = ("\0".join(paths)).replace("/", "\\") 337 | data = files.encode("U16")[2:] + b"\0\0" 338 | wc.OpenClipboard() 339 | try: 340 | wc.EmptyClipboard() 341 | wc.SetClipboardData( 342 | wc.CF_HDROP, matedata + data) 343 | finally: 344 | wc.CloseClipboard() 345 | 346 | def readClipboardFilePaths(): 347 | wc.OpenClipboard() 348 | try: 349 | return wc.GetClipboardData(win32clipboard.CF_HDROP) 350 | finally: 351 | wc.CloseClipboard() 352 | 353 | pDropFiles = DROPFILES() 354 | pDropFiles.pFiles = sizeof(DROPFILES) 355 | pDropFiles.fWide = True 356 | matedata = bytes(pDropFiles) 357 | filepath = str(Path(filepath).absolute()) 358 | filename = [r"%s" % filepath] 359 | setClipboardFiles(filename) 360 | 361 | # wc.CloseClipboard() 362 | self.SendClipboard(who) 363 | return 1 364 | -------------------------------------------------------------------------------- /PyOfficeRobot/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderWanFeng/PyOfficeRobot/c92ba08f35efe41613ef052a0f043b35d77f8b5c/PyOfficeRobot/core/__init__.py -------------------------------------------------------------------------------- /PyOfficeRobot/core/group/Start.py: -------------------------------------------------------------------------------- 1 | # -*- codeing = utf-8 -*- 2 | # @Time : 2023/3/14 18:18 3 | # @Project_File : Start.py 4 | # @Dir_Path : _____Release_File/微信自动化/微信群发消息 5 | # @File : QT.py 6 | # @IDE_Name : PyCharm 7 | # ============================================================ 8 | # ============================================================ 9 | # ============================================================ 10 | # ============================================================ 11 | # ============================================================ 12 | 13 | import sys 14 | import threading 15 | 16 | import xlrd 17 | from PySide6.QtCore import QStringListModel, QModelIndex 18 | from PySide6.QtWidgets import QApplication, QWidget 19 | from PySide6.QtWidgets import QFileDialog 20 | 21 | from PyOfficeRobot.api.chat import send_message 22 | from PyOfficeRobot.core.group.ui_file_py import Ui_Form 23 | 24 | 25 | # 继承QWidget类,以获取其属性和方法 26 | class MyWidget(QWidget): 27 | def __init__(self): 28 | super().__init__() 29 | # 设置界面为我们生成的界面 30 | self.ui = Ui_Form() 31 | self.ui.setupUi(self) 32 | self.set_ui() 33 | 34 | self.sendtext: str = str() 35 | self.groupslist: list = list() 36 | self.groupslistfilename: str = str() 37 | self.sendtextfilename: str = str() 38 | self.state = True 39 | 40 | def set_ui(self): 41 | self.setWindowTitle("Python自动化办公社区") 42 | self.ui.pushButton_load.clicked.connect(self.OnPushbutton_load_Cliked) 43 | self.ui.pushButton_start.clicked.connect(self.OnPushbutton_Start_Cliked) 44 | self.ui.pushButton_close.clicked.connect(self._OnPushbutton_Close_Clicked) 45 | self.ui.listView.clicked.connect(self.test) 46 | 47 | def test(self, index: QModelIndex): 48 | count = self.model.rowCount() 49 | print(count) 50 | for _ in range(count): 51 | print(self.model.index(_).data()) 52 | 53 | def OnPushbutton_load_Cliked(self): 54 | 55 | self.groupslist.clear() 56 | 57 | self.groupslistfilename = QFileDialog.getOpenFileName(caption='选择群发列表', filter='*.xls')[0] 58 | self.sendtextfilename = QFileDialog.getOpenFileName(caption='选择群发的文本', filter='*.txt')[0] 59 | 60 | # 61 | work = xlrd.open_workbook(filename=self.groupslistfilename) 62 | sheet = work.sheet_by_index(0) 63 | for _ in range(sheet.nrows): 64 | itme = sheet.cell_value(_, 0) 65 | state = sheet.cell_value(_, 1) 66 | 67 | if state == "True": 68 | if itme != '': 69 | self.groupslist.append(sheet.cell_value(_, 0)) 70 | # 71 | 72 | # 73 | file = open(file=self.sendtextfilename, encoding='utf-8') 74 | for _ in file.readlines(): 75 | self.sendtext = self.sendtext + _ + '{ctrl}{ENTER}' 76 | # 77 | 78 | # 79 | self.model = QStringListModel() 80 | self.model.setStringList(self.groupslist) 81 | self.ui.listView.setModel(self.model) 82 | # 83 | 84 | def threadfunction(self): 85 | for _ in self.groupslist: 86 | thread_start = threading.Thread(target=send_message, args=(_, self.sendtext)) 87 | thread_start.start() 88 | thread_start.join() 89 | 90 | def OnPushbutton_Start_Cliked(self): 91 | self.thread_1 = threading.Thread(target=self.threadfunction) 92 | self.thread_1.start() 93 | 94 | def _OnPushbutton_Close_Clicked(self): 95 | sys.exit(0) 96 | 97 | 98 | # 程序入口 99 | if __name__ == "__main__": 100 | app = QApplication(sys.argv) 101 | # 初始化QApplication,界面展示要包含在QApplication初始化之后,结束之前 102 | 103 | window = MyWidget() 104 | window.show() 105 | # 初始化并展示我们的界面组件 106 | 107 | sys.exit(app.exec_()) 108 | # 结束QApplication 109 | -------------------------------------------------------------------------------- /PyOfficeRobot/core/group/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderWanFeng/PyOfficeRobot/c92ba08f35efe41613ef052a0f043b35d77f8b5c/PyOfficeRobot/core/group/__init__.py -------------------------------------------------------------------------------- /PyOfficeRobot/core/group/ui_file_py.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ################################################################################ 4 | ## Form generated from reading UI file 'ui_file.ui' 5 | ## 6 | ## Created by: Qt User Interface Compiler version 6.4.2 7 | ## 8 | ## WARNING! All changes made in this file will be lost when recompiling UI file! 9 | ################################################################################ 10 | 11 | from PySide6.QtCore import (QCoreApplication, QMetaObject, QRect, 12 | QSize) 13 | from PySide6.QtGui import (QFont) 14 | from PySide6.QtWidgets import (QLabel, QListView, QPushButton) 15 | 16 | 17 | class Ui_Form(object): 18 | def setupUi(self, Form): 19 | if not Form.objectName(): 20 | Form.setObjectName(u"Form") 21 | Form.resize(500, 600) 22 | Form.setMinimumSize(QSize(500, 600)) 23 | Form.setMaximumSize(QSize(500, 600)) 24 | self.listView = QListView(Form) 25 | self.listView.setObjectName(u"listView") 26 | self.listView.setGeometry(QRect(10, 50, 341, 541)) 27 | self.label = QLabel(Form) 28 | self.label.setObjectName(u"label") 29 | self.label.setGeometry(QRect(20, 10, 321, 31)) 30 | font = QFont() 31 | font.setPointSize(20) 32 | self.label.setFont(font) 33 | self.pushButton_load = QPushButton(Form) 34 | self.pushButton_load.setObjectName(u"pushButton_load") 35 | self.pushButton_load.setGeometry(QRect(360, 50, 131, 141)) 36 | font1 = QFont() 37 | font1.setPointSize(30) 38 | self.pushButton_load.setFont(font1) 39 | self.pushButton_start = QPushButton(Form) 40 | self.pushButton_start.setObjectName(u"pushButton_start") 41 | self.pushButton_start.setGeometry(QRect(360, 410, 131, 141)) 42 | self.pushButton_start.setFont(font1) 43 | self.pushButton_close = QPushButton(Form) 44 | self.pushButton_close.setObjectName(u"pushButton_close") 45 | self.pushButton_close.setGeometry(QRect(360, 230, 131, 141)) 46 | self.pushButton_close.setFont(font1) 47 | 48 | self.retranslateUi(Form) 49 | 50 | QMetaObject.connectSlotsByName(Form) 51 | 52 | # setupUi 53 | 54 | def retranslateUi(self, Form): 55 | Form.setWindowTitle(QCoreApplication.translate("Form", u"Form", None)) 56 | self.label.setText(QCoreApplication.translate("Form", u"\u7fa4\u53d1\u5217\u8868 : ", None)) 57 | self.pushButton_load.setText(QCoreApplication.translate("Form", u"\u52a0\u8f7d", None)) 58 | self.pushButton_start.setText(QCoreApplication.translate("Form", u"\u7fa4\u53d1", None)) 59 | self.pushButton_close.setText(QCoreApplication.translate("Form", u"\u6682\u505c", None)) 60 | # retranslateUi 61 | -------------------------------------------------------------------------------- /PyOfficeRobot/imgs/5、定时发送/5、定时发送.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderWanFeng/PyOfficeRobot/c92ba08f35efe41613ef052a0f043b35d77f8b5c/PyOfficeRobot/imgs/5、定时发送/5、定时发送.jpg -------------------------------------------------------------------------------- /PyOfficeRobot/lib/CONST.py: -------------------------------------------------------------------------------- 1 | class ACT_TYPE(): 2 | MESSAGE = '文本' 3 | FILE = '文件' 4 | 5 | 6 | SPLIT_LINE = '=' * 30 7 | 8 | NEW_LINE = '{ctrl}{ENTER}' 9 | 10 | GPT_TYPE = {"ALI": "qianwen"} 11 | -------------------------------------------------------------------------------- /PyOfficeRobot/lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderWanFeng/PyOfficeRobot/c92ba08f35efe41613ef052a0f043b35d77f8b5c/PyOfficeRobot/lib/__init__.py -------------------------------------------------------------------------------- /PyOfficeRobot/lib/dec/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderWanFeng/PyOfficeRobot/c92ba08f35efe41613ef052a0f043b35d77f8b5c/PyOfficeRobot/lib/dec/__init__.py -------------------------------------------------------------------------------- /PyOfficeRobot/lib/dec/act_dec.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | 4 | # 统一的动作输出 5 | def act_info(act='消息'): 6 | def wrapper(func): 7 | @wraps(func) 8 | def inner_wrapper(*args, **kwargs): 9 | print(f'开始:发送{act}') 10 | res = func(*args, **kwargs) 11 | print(f'结束:发送{act}') 12 | return res 13 | 14 | return inner_wrapper 15 | 16 | return wrapper 17 | -------------------------------------------------------------------------------- /PyOfficeRobot/lib/decorator_utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderWanFeng/PyOfficeRobot/c92ba08f35efe41613ef052a0f043b35d77f8b5c/PyOfficeRobot/lib/decorator_utils/__init__.py -------------------------------------------------------------------------------- /PyOfficeRobot/lib/decorator_utils/instruction_url.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | ############################################# 5 | # File Name: instruction_url.py 6 | # Mail: 1957875073@qq.com 7 | # Created Time: 2022-12-17 08:14:34 8 | # Description: 有关 方法说明 的装饰器 9 | ############################################# 10 | 11 | import os 12 | # 每个文件的具体方法说明 13 | from functools import wraps 14 | 15 | from PyOfficeRobot.lib.CONST import SPLIT_LINE 16 | 17 | chat_dict = { 18 | "send_message": "https://www.bilibili.com/video/BV1S84y1m7xd?p=3", 19 | "chat_by_keywords": "https://www.bilibili.com/video/BV1S84y1m7xd?p=5", 20 | "send_message_by_time": "https://www.bilibili.com/video/BV1S84y1m7xd?p=7", 21 | "chat_by_gpt": "https://www.bilibili.com/video/BV1S84y1m7xd?p=11", 22 | "chat_robot": "https://www.bilibili.com/video/BV1S84y1m7xd?p=11", 23 | "chat_ali": "https://mp.weixin.qq.com/s/SfNA34bC6wMLRaKONfOWhw", 24 | "receive_message": "", 25 | } 26 | file_dict = { 27 | "send_file": "https://www.bilibili.com/video/BV1S84y1m7xd?p=4", 28 | 29 | } 30 | 31 | friend_dict = { 32 | "add": "https://www.bilibili.com/video/BV1S84y1m7xd?p=9", 33 | 34 | } 35 | 36 | group_dict = { 37 | "send": "https://www.bilibili.com/video/BV1S84y1m7xd?p=10", 38 | } 39 | 40 | # 有多少文件需要说明 41 | instruction_file_dict = { 42 | "chat.py": chat_dict, 43 | "file.py": file_dict, 44 | "friend.py": friend_dict, 45 | "group.py": group_dict, 46 | } 47 | 48 | 49 | def instruction(func): 50 | @wraps(func) 51 | def instruction_wrapper(*args, **kwargs): 52 | func_filename = os.path.basename(func.__code__.co_filename) # 取出方法所在的文件名 53 | # 如果有这个文件,并且已经配置了方法名对应的说明链接,则打印出来 54 | if func_filename in instruction_file_dict.keys() and instruction_file_dict[func_filename][func.__name__]: 55 | print(SPLIT_LINE) 56 | print('【PyOfficeRobot,微信机器人全部功能】:https://www.python-office.com/course-002/10-PyOfficeRobot/10-PyOfficeRobot.html') 57 | print(SPLIT_LINE) 58 | print( 59 | f'正在运行:PyOfficeRobot.{os.path.basename(func_filename)[:-3]}.{func.__name__} , 这个方法的使用说明:{instruction_file_dict[func_filename][func.__name__]}') 60 | print(SPLIT_LINE) 61 | instruction_res = func(*args, **kwargs) 62 | return instruction_res 63 | 64 | return instruction_wrapper 65 | 66 | 67 | ############################################# 68 | # 以下是本文件的工具模块,用来更新方法和链接 69 | from inspect import getmembers, isfunction 70 | 71 | 72 | # 获取模块包含的方法名 73 | def get_method_name(file): 74 | for method_name in getmembers(file): 75 | if isfunction(method_name[1]): 76 | print(f'"{method_name[0]}":"",') 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

6 |

7 | 👉 项目官网 👈 8 |

9 |

10 | 👉 本开源项目的交流群 👈 11 |

12 | 13 | 14 |

15 | 16 | github star 17 | 18 | 19 | gitee star 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |

29 | 30 | # 又一个微信聊天机器人横空出世了,人人可用! 31 | 32 | 之前给大家分享过一个微信机器人:[一个15分钟的视频,教你用Python创建自己的微信聊天机器人!](http://t.cn/A66p30bI) 33 | 34 | 但是之前这个机器人,需要基于网页版才能用(有网页版微信的同学,还可以去继续用);然而很多朋友的微信,是不能登录网页版微信的。 35 | 36 | > 有没有一种微信机器人,任何人的微信都可以用,不需要网页微信功能呢? 37 | 38 | 39 | 在经过技术检索和开发以后,支持所有微信使用的:**PyOfficeRobot**来啦~ 40 | 41 | ## 1、安装PyOfficeRobot 42 | 43 | 1行命令,安装PyOfficeRobot这个库。[安装视频](https://www.bilibili.com/video/BV1S84y1m7xd/?p=2/) 44 | 45 | ``` 46 | pip install -i https://mirrors.aliyun.com/pypi/simple/ PyOfficeRobot -U 47 | ``` 48 | 49 | 目前不支持最新版微信,支持的微信版本时3.9,下载链接:[https://pan.quark.cn/s/f32e9b832284](https://pan.quark.cn/s/f32e9b832284) 50 | 51 | ## 2、功能演示 52 | 53 | - ⭐本机器人使用完全免费,全部功能的演示视频,扫码下图直达👇 + 54 | 项目源码:[Github](https://gitee.com/CoderWanFeng/PyOfficeRobot/demo)、[gitee](https://gitee.com/CoderWanFeng/PyOfficeRobot) 55 | 56 |

57 | 58 | 59 | 60 |

61 | 62 | > 持续更新中,交流群:[点我加入](http://www.python4office.cn/wechat-group/) 63 | 64 | #### 微信机器人-其它实现方式 65 | 66 | | 功能说明 | 视频 | 代码 | 67 | |-----------------|------------------------------------------------------|-----------------------------------------------------------| 68 | | 机器人.exe | [点我直达](https://www.bilibili.com/video/BV1Q64y1Z7TB/) | | 69 | | ChatGPT版本 | [点我直达](https://www.bilibili.com/video/BV1Dx4y157qy) | [点我直达](https://mp.weixin.qq.com/s/HJfLZILUOWn4TK8qk3DL9w) | 70 | | ⌚wxpy-24小时,后台运行 | [点我直达](https://www.bilibili.com/video/BV11L411L7oi/) | [点我直达](https://mp.weixin.qq.com/s/ubJ1OhOFVKfFVT8sBNZ0pg) | 71 | | 企业微信机器人 | | [点我直达](https://mp.weixin.qq.com/s/mt-ONvz0DdhbMB96eTZDKA) | 72 | 73 | ## 3、功能Demo 74 | 75 | 我最近开源了这个库的全部源代码,功能正在开发中,欢迎大家参与开发~ 76 | 77 | - [演示代码](https://github.com/CoderWanFeng/PyOfficeRobot/tree/main/demo) 78 | 79 | 80 | --- 81 | 82 |

83 | 84 | 85 | 86 |

87 | 88 | ## ⭐Star 89 | 90 | [![Stargazers over time](https://starchart.cc/CoderWanFeng/PyOfficeRobot.svg)](https://starchart.cc/CoderWanFeng/PyOfficeRobot) 91 | 92 | ## 致谢项目 93 | 94 | - [wxauto](https://github.com/cluic/wxauto) -------------------------------------------------------------------------------- /docs/文章配图/img.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @个人网站 :www.python-office.com 6 | @Date :2023/3/19 21:04 7 | @Description : 8 | ''' 9 | import office 10 | 11 | office.image.add_watermark(file=r'imgs/公众号+Web.jpg', mark='程序员晚枫') 12 | -------------------------------------------------------------------------------- /docs/文章配图/imgs/公众号+Web.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderWanFeng/PyOfficeRobot/c92ba08f35efe41613ef052a0f043b35d77f8b5c/docs/文章配图/imgs/公众号+Web.jpg -------------------------------------------------------------------------------- /docs/文章配图/mark_img/公众号+Web.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderWanFeng/PyOfficeRobot/c92ba08f35efe41613ef052a0f043b35d77f8b5c/docs/文章配图/mark_img/公众号+Web.jpg -------------------------------------------------------------------------------- /examples/PR/Dumogu/Pdbot.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | 3 | 4 | class BRAIN: 5 | """机器人的大脑: /.putin /.find """ 6 | def __init__(self, path, tup): 7 | self.lie_name = tup 8 | self.path = path 9 | self.conn = sqlite3.connect(self.path) 10 | self.c = self.conn.cursor() 11 | try: 12 | self.c.execute(f'''CREATE TABLE BRAIN({self.lie_name})''') 13 | except sqlite3.OperationalError: 14 | pass 15 | 16 | def __open__(self): 17 | """打开数据库""" 18 | self.conn = sqlite3.connect(self.path) 19 | self.c = self.conn.cursor() 20 | 21 | def __cmd__(self, command): 22 | """数据库命令""" 23 | self.__open__() 24 | rang = self.c.execute(f"{command}") 25 | for row in rang: 26 | return row[1] 27 | 28 | def putin(self, msg): 29 | """向数据库加数据 30 | :type msg: str,tuple,list[tuple] 31 | """ 32 | self.__open__() 33 | rang = self.all_question 34 | if type(msg) == str and '+' in msg: 35 | msgs = msg.split("+") 36 | if msgs[0] in self.sp_question[0].keys() or msgs[0] in self.sp_question[1].keys(): 37 | self.delete(msgs[0]) 38 | ds = (msgs[0], msgs[1], 'lang') if len(msg.split("+")) == 2 \ 39 | else (tuple(msgs) if len(msgs) == 3 else ('测试', '这是个测试!', 'lang')) 40 | self.c.execute(f"INSERT INTO BRAIN VALUES (?,?,?)", ds) if ds not in rang else print('数据已有![str]') 41 | elif type(msg) == tuple: 42 | ds = msg 43 | self.c.execute(f"INSERT INTO BRAIN VALUES (?,?,?)", ds) if ds not in rang else print('数据已有![tuple]') 44 | elif type(msg) == list: 45 | ds = msg 46 | for dl in ds: 47 | print('数据已有![list]') if dl in rang else print() 48 | self.c.executemany(f"INSERT INTO BRAIN VALUES (?,?,?)", msg) 49 | else: 50 | ds = list(('测试', '失败')) 51 | self.conn.commit() 52 | self.conn.close() 53 | return f'{ds[0]}:{ds[1]}' 54 | 55 | def find(self, item: str, tup: str) -> list[tuple]: 56 | """查找具体的项目,3个表头均可""" 57 | self.__open__() 58 | rang = self.c.execute(f'SELECT * FROM BRAIN WHERE {item}=?', (tup,)) 59 | return [raw for raw in rang] 60 | 61 | def love(self, xinxi): 62 | """亲密问题""" 63 | self.__open__() 64 | return self.__cmd__(f"SELECT * FROM BRAIN WHERE question='{xinxi}' AND type='love'") 65 | 66 | def lang(self, xinxi): 67 | """普通问题""" 68 | self.__open__() 69 | return self.__cmd__(f"SELECT * FROM BRAIN WHERE question='{xinxi}' AND type='lang'") 70 | 71 | def all(self, xinxi): 72 | """所有问题""" 73 | self.__open__() 74 | return self.__cmd__(f"SELECT * FROM BRAIN WHERE question='{xinxi}'") 75 | 76 | def delete(self, question, typename=''): 77 | """删除某个问题""" 78 | self.__open__() 79 | if typename == '': 80 | self.c.execute(f"DELETE FROM BRAIN WHERE question='{question}'") 81 | else: 82 | self.c.execute(f"DELETE FROM BRAIN WHERE question='{question}' AND type='{typename}'") 83 | self.conn.commit() 84 | self.conn.close() 85 | self.__open__() 86 | pr = f'[{question}]问题删除!' if typename == '' else f'[{question}|{typename}]问题删除!' 87 | return pr 88 | 89 | def update(self, question, answer=''): 90 | """将问题升级或者回复修改""" 91 | self.__open__() 92 | if answer == '': 93 | self.c.execute(f"UPDATE BRAIN SET type = 'love' WHERE question = '{question}'") 94 | else: 95 | self.c.execute(f"UPDATE BRAIN SET answer = '{answer}' WHERE question = '{question}'") 96 | self.conn.commit() 97 | self.conn.close() 98 | self.conn = sqlite3.connect(self.path) 99 | return f'[{question}]问题升级!' 100 | 101 | @property 102 | def all_question(self) -> list: 103 | """快速显示所有的问题""" 104 | self.__open__() 105 | rang = self.c.execute(f'SELECT * FROM BRAIN') 106 | return [raw[0] for raw in rang] 107 | 108 | @property 109 | def sp_question(self): 110 | """显示所有的问题,将私密问题和公开问题分开""" 111 | dic_love, dic_lang = {}, {} 112 | for raw in self.findall: 113 | if raw[2] == 'love': 114 | dic_love[raw[0]] = raw[1] 115 | elif raw[2] == 'lang': 116 | dic_lang[raw[0]] = raw[1] 117 | return [dic_love, dic_lang] 118 | 119 | @property 120 | def all_sheet(self) -> list: 121 | """返回所有表头""" 122 | self.__open__() 123 | return [x for x in self.c.execute("SELECT tbl_name FROM sqlite_master")] 124 | 125 | @property 126 | def findall(self): 127 | """找到所有问题""" 128 | self.__open__() 129 | rang = self.c.execute(f'SELECT * FROM BRAIN') 130 | return rang 131 | 132 | 133 | def main(): 134 | """这是个测试函数!""" 135 | data = BRAIN(f'I:/EXE/WX/Log/Data_brain.db', 'question,answer,type') 136 | # for i in data.findall: 137 | # print(i) 138 | print(data.find('type', 'lang')) 139 | 140 | 141 | if __name__ == '__main__': 142 | """该函数仅在本模块儿运行""" 143 | main() 144 | -------------------------------------------------------------------------------- /examples/PR/Dumogu/WeChatType.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='gb18030') 3 | 4 | 5 | import uiautomation as uia 6 | import win32gui, win32con 7 | import win32clipboard as wc 8 | import time 9 | import os 10 | 11 | PUBLISH_ID = '公众号:程序员晚枫' 12 | 13 | COPYDICT = {} 14 | 15 | class WxParam: 16 | SYS_TEXT_HEIGHT = 33 17 | TIME_TEXT_HEIGHT = 34 18 | RECALL_TEXT_HEIGHT = 45 19 | CHAT_TEXT_HEIGHT = 52 20 | CHAT_IMG_HEIGHT = 117 21 | SpecialTypes = ['[文件]', '[图片]', '[视频]', '[音乐]', '[链接]'] 22 | 23 | 24 | class WxUtils: 25 | def SplitMessage(MsgItem): 26 | uia.SetGlobalSearchTimeout(0) 27 | MsgItemName = MsgItem.Name 28 | if MsgItem.BoundingRectangle.height() == WxParam.SYS_TEXT_HEIGHT: 29 | Msg = ('SYS', MsgItemName, ''.join([str(i) for i in MsgItem.GetRuntimeId()])) 30 | elif MsgItem.BoundingRectangle.height() == WxParam.TIME_TEXT_HEIGHT: 31 | Msg = ('Time', MsgItemName, ''.join([str(i) for i in MsgItem.GetRuntimeId()])) 32 | elif MsgItem.BoundingRectangle.height() == WxParam.RECALL_TEXT_HEIGHT: 33 | if '撤回' in MsgItemName: 34 | Msg = ('Recall', MsgItemName, ''.join([str(i) for i in MsgItem.GetRuntimeId()])) 35 | else: 36 | Msg = ('SYS', MsgItemName, ''.join([str(i) for i in MsgItem.GetRuntimeId()])) 37 | else: 38 | Index = 1 39 | User = MsgItem.ButtonControl(foundIndex=Index) 40 | try: 41 | while True: 42 | if User.Name == '': 43 | Index += 1 44 | User = MsgItem.ButtonControl(foundIndex=Index) 45 | else: 46 | break 47 | Msg = (User.Name, MsgItemName, ''.join([str(i) for i in MsgItem.GetRuntimeId()])) 48 | except: 49 | Msg = ('SYS', MsgItemName, ''.join([str(i) for i in MsgItem.GetRuntimeId()])) 50 | uia.SetGlobalSearchTimeout(10.0) 51 | return Msg 52 | 53 | def SetClipboard(data, dtype='text'): 54 | '''复制文本信息或图片到剪贴板 55 | data : 要复制的内容,str 或 Image 图像''' 56 | if dtype.upper() == 'TEXT': 57 | type_data = win32con.CF_UNICODETEXT 58 | elif dtype.upper() == 'IMAGE': 59 | from io import BytesIO 60 | type_data = win32con.CF_DIB 61 | output = BytesIO() 62 | data.save(output, 'BMP') 63 | data = output.getvalue()[14:] 64 | else: 65 | raise ValueError('param (dtype) only "text" or "image" supported') 66 | wc.OpenClipboard() 67 | wc.EmptyClipboard() 68 | wc.SetClipboardData(type_data, data) 69 | wc.CloseClipboard() 70 | 71 | def Screenshot(hwnd, to_clipboard=True): 72 | '''为句柄为hwnd的窗口程序截图 73 | hwnd : 句柄 74 | to_clipboard : 是否复制到剪贴板 75 | ''' 76 | import pyscreenshot as shot 77 | bbox = win32gui.GetWindowRect(hwnd) 78 | win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, 0, 0, 0, 0, \ 79 | win32con.SWP_SHOWWINDOW | win32con.SWP_NOMOVE | win32con.SWP_NOSIZE) 80 | win32gui.SetWindowPos(hwnd, win32con.HWND_NOTOPMOST, 0, 0, 0, 0, \ 81 | win32con.SWP_SHOWWINDOW | win32con.SWP_NOMOVE | win32con.SWP_NOSIZE) 82 | win32gui.BringWindowToTop(hwnd) 83 | im = shot.grab(bbox) 84 | if to_clipboard: 85 | WxUtils.SetClipboard(im, 'image') 86 | return im 87 | 88 | def SavePic(savepath=None, filename=None): 89 | Pic = uia.WindowControl(ClassName='ImagePreviewWnd', Name='图片查看') 90 | Pic.SendKeys('{Ctrl}s') 91 | SaveAs = Pic.WindowControl(ClassName='#32770', Name='另存为...') 92 | SaveAsEdit = SaveAs.EditControl(ClassName='Edit', Name='文件名:') 93 | SaveButton = Pic.ButtonControl(ClassName='Button', Name='保存(S)') 94 | PicName, Ex = os.path.splitext(SaveAsEdit.GetValuePattern().Value) 95 | if not savepath: 96 | savepath = os.getcwd() 97 | if not filename: 98 | filename = PicName 99 | FilePath = os.path.realpath(os.path.join(savepath, filename + Ex)) 100 | SaveAsEdit.SendKeys(FilePath) 101 | SaveButton.Click() 102 | Pic.SendKeys('{Esc}') 103 | 104 | def ControlSize(control): 105 | locate = control.BoundingRectangle 106 | size = (locate.width(), locate.height()) 107 | return size 108 | 109 | def ClipboardFormats(unit=0, *units): 110 | units = list(units) 111 | wc.OpenClipboard() 112 | u = wc.EnumClipboardFormats(unit) 113 | wc.CloseClipboard() 114 | units.append(u) 115 | if u: 116 | units = WxUtils.ClipboardFormats(u, *units) 117 | return units 118 | 119 | def CopyDict(self): 120 | Dict = {} 121 | for i in WxUtils.ClipboardFormats(): 122 | if i == 0: 123 | continue 124 | wc.OpenClipboard() 125 | try: 126 | content = wc.GetClipboardData(i) 127 | wc.CloseClipboard() 128 | except: 129 | wc.CloseClipboard() 130 | raise ValueError 131 | if len(str(i)) >= 4: 132 | Dict[str(i)] = content 133 | return Dict 134 | 135 | 136 | class WeChat: 137 | def __init__(self): 138 | self.UiaAPI = uia.WindowControl(ClassName='WeChatMainWndForPC') 139 | 140 | self.SessionList = self.UiaAPI.ListControl(Name='会话') 141 | self.EditMsg = self.UiaAPI.EditControl(Name='输入') 142 | self.SearchBox = self.UiaAPI.EditControl(Name='搜索') 143 | self.MsgList = self.UiaAPI.ListControl(Name='消息') 144 | self.SessionItemList = [] 145 | self.Group = self.UiaAPI.ButtonControl().Name 146 | 147 | def GetSessionList(self, reset=False): 148 | '''获取当前会话列表,更新会话列表''' 149 | self.SessionItem = self.SessionList.ListItemControl() 150 | SessionList = [] 151 | if reset: 152 | self.SessionItemList = [] 153 | for i in range(100): 154 | try: 155 | name = self.SessionItem.Name 156 | except: 157 | break 158 | if name not in self.SessionItemList: 159 | self.SessionItemList.append(name) 160 | if name not in SessionList: 161 | SessionList.append(name) 162 | self.SessionItem = self.SessionItem.GetNextSiblingControl() 163 | return SessionList 164 | 165 | def Search(self, keyword): 166 | ''' 167 | 查找微信好友或关键词 168 | keywords: 要查找的关键词,str * 最好完整匹配,不完全匹配只会选取搜索框第一个 169 | ''' 170 | self.UiaAPI.SetFocus() 171 | time.sleep(0.1) 172 | self.UiaAPI.SendKeys('{Ctrl}f{Ctrl}a', waitTime=0.2) 173 | self.SearchBox.SendKeys(keyword, waitTime=0.2) 174 | self.SearchBox.SendKeys('{Enter}') 175 | 176 | def ChatWith(self, who, RollTimes=None): 177 | ''' 178 | 打开某个聊天框 179 | who : 要打开的聊天框好友名,str; * 最好完整匹配,不完全匹配只会选取搜索框第一个 180 | RollTimes : 默认向下滚动多少次,再进行搜索 181 | ''' 182 | self.UiaAPI.SwitchToThisWindow() 183 | RollTimes = 1 if not RollTimes else RollTimes 184 | 185 | def roll_to(who=who, RollTimes=RollTimes): 186 | for i in range(RollTimes): 187 | if who not in self.GetSessionList()[:-1]: 188 | self.SessionList.WheelDown(wheelTimes=1, waitTime=0.01 * i) 189 | else: 190 | time.sleep(0.1) 191 | self.SessionList.ListItemControl(Name=who).Click(simulateMove=False) 192 | return 1 193 | return 0 194 | 195 | rollresult = roll_to() 196 | if rollresult: 197 | return 1 198 | else: 199 | self.Search(who) 200 | return roll_to(RollTimes=1) 201 | 202 | def SendMsg(self, msg, clear=True): 203 | '''向当前窗口发送消息 204 | msg : 要发送的消息 205 | clear : 是否清除当前已编辑内容 206 | ''' 207 | self.UiaAPI.SwitchToThisWindow() 208 | if clear: 209 | self.EditMsg.SendKeys('{Ctrl}a', waitTime=0) 210 | self.EditMsg.SendKeys(msg, waitTime=0) 211 | self.EditMsg.SendKeys('{Ctrl}{Enter}', waitTime=0) 212 | 213 | def SendEnd(self, clear=False): 214 | '''向当前窗口发送消息 215 | msg : 要发送的消息 216 | clear : 是否清除当前已编辑内容 217 | ''' 218 | self.UiaAPI.SwitchToThisWindow() 219 | self.EditMsg.SendKeys('{Enter}', waitTime=0) 220 | 221 | def SendFiles(self, *filepath, not_exists='ignore'): 222 | """向当前聊天窗口发送文件 223 | not_exists: 如果未找到指定文件,继续或终止程序 224 | *filepath: 要复制文件的绝对路径""" 225 | global COPYDICT 226 | key = '' 227 | for file in filepath: 228 | file = os.path.realpath(file) 229 | if not os.path.exists(file): 230 | if not_exists.upper() == 'IGNORE': 231 | print('File not exists:', file) 232 | continue 233 | elif not_exists.upper() == 'RAISE': 234 | raise FileExistsError('File Not Exists: %s' % file) 235 | else: 236 | raise ValueError('param not_exists only "ignore" or "raise" supported') 237 | key += '' % file 238 | if not key: 239 | return 0 240 | if not COPYDICT: 241 | self.EditMsg.SendKeys(' ', waitTime=0) 242 | self.EditMsg.SendKeys('{Ctrl}a', waitTime=0) 243 | self.EditMsg.SendKeys('{Ctrl}c', waitTime=0) 244 | self.EditMsg.SendKeys('{Delete}', waitTime=0) 245 | while True: 246 | try: 247 | COPYDICT = WxUtils.CopyDict() 248 | break 249 | except: 250 | pass 251 | wc.OpenClipboard() 252 | wc.EmptyClipboard() 253 | wc.SetClipboardData(13, '') 254 | wc.SetClipboardData(16, b'\x04\x08\x00\x00') 255 | wc.SetClipboardData(1, b'') 256 | wc.SetClipboardData(7, b'') 257 | for i in COPYDICT: 258 | copydata = COPYDICT[i].replace(b'', 259 | key.encode()).replace(b'type="0"', b'type="3"') 260 | wc.SetClipboardData(int(i), copydata) 261 | wc.CloseClipboard() 262 | self.SendClipboard() 263 | return 1 264 | 265 | def SendClipboard(self): 266 | '''向当前聊天页面发送剪贴板复制的内容''' 267 | self.SendMsg('{Ctrl}v') 268 | 269 | @property 270 | def GetAllMessage(self): 271 | '''获取当前窗口中加载的所有聊天记录''' 272 | MsgDocker = [] 273 | MsgItems = self.MsgList.GetChildren() 274 | for MsgItem in MsgItems: 275 | MsgDocker.append(WxUtils.SplitMessage(MsgItem)) 276 | return MsgDocker 277 | 278 | @property 279 | def GetLastMessage(self): 280 | '''获取当前窗口中最后一条聊天记录''' 281 | try: 282 | uia.SetGlobalSearchTimeout(1.0) 283 | MsgItem = self.MsgList.GetChildren()[-1] 284 | ChatName = MsgItem.ButtonControl() # 聊天对象应当从消息子目录获取 285 | uia.SetGlobalSearchTimeout(2.0) 286 | return MsgItem.Name, ChatName.Name # 返回正确的聊天信息和聊天对象 287 | except LookupError: 288 | pass 289 | 290 | def LoadMoreMessage(self, n=0.1): 291 | '''定位到当前聊天页面,并往上滚动鼠标滚轮,加载更多聊天记录到内存''' 292 | n = 0.1 if n < 0.1 else 1 if n > 1 else n 293 | self.MsgList.WheelUp(wheelTimes=int(500 * n), waitTime=0.1) 294 | 295 | def SendScreenshot(self, name=None, classname=None): 296 | '''发送某个桌面程序的截图,如:微信、记事本... 297 | name : 要发送的桌面程序名字,如:微信 298 | classname : 要发送的桌面程序类别名,一般配合 spy 小工具使用,以获取类名,如:微信的类名为 WeChatMainWndForPC''' 299 | if name and classname: 300 | return 0 301 | else: 302 | hwnd = win32gui.FindWindow(classname, name) 303 | if hwnd: 304 | WxUtils.Screenshot(hwnd) 305 | self.SendClipboard() 306 | return 1 307 | else: 308 | return 0 309 | 310 | def SavePic(self, savepath=None, filename=None): 311 | WxUtils.SavePic() 312 | # Pic = uia.WindowControl(ClassName='ImagePreviewWnd', Name='图片查看') 313 | -------------------------------------------------------------------------------- /examples/PR/gen/群发/Start.py: -------------------------------------------------------------------------------- 1 | # # -*- codeing = utf-8 -*- 2 | # # @Time : 2023/3/14 18:18 3 | # # @Project_File : Start.py 4 | # # @Dir_Path : _____Release_File/微信自动化/微信群发消息 5 | # # @File : QT.py 6 | # # @IDE_Name : PyCharm 7 | # # ============================================================ 8 | # # ============================================================ 9 | # # ============================================================ 10 | # # ============================================================ 11 | # # ============================================================ 12 | # 13 | # import sys 14 | # import threading 15 | # 16 | # import xlrd 17 | # from PySide6.QtCore import QStringListModel, QModelIndex 18 | # from PySide6.QtWidgets import QApplication, QWidget 19 | # from PySide6.QtWidgets import QFileDialog 20 | # 21 | # from PyOfficeRobot.api.chat import send_message 22 | # from ui_file_py import Ui_Form 23 | # 24 | # 25 | # # 继承QWidget类,以获取其属性和方法 26 | # class MyWidget(QWidget): 27 | # def __init__(self): 28 | # super().__init__() 29 | # # 设置界面为我们生成的界面 30 | # self.ui = Ui_Form() 31 | # self.ui.setupUi(self) 32 | # self.set_ui() 33 | # 34 | # self.sendtext: str = str() 35 | # self.groupslist: list = list() 36 | # self.groupslistfilename: str = str() 37 | # self.sendtextfilename: str = str() 38 | # self.state = True 39 | # 40 | # def set_ui(self): 41 | # self.setWindowTitle("微信自动化-----群发消息") 42 | # self.ui.pushButton_load.clicked.connect(self.OnPushbutton_load_Cliked) 43 | # self.ui.pushButton_start.clicked.connect(self.OnPushbutton_Start_Cliked) 44 | # self.ui.pushButton_close.clicked.connect(self._OnPushbutton_Close_Clicked) 45 | # self.ui.listView.clicked.connect(self.test) 46 | # 47 | # def test(self, index: QModelIndex): 48 | # """print(index.data()) 49 | # print(index.model()) 50 | # print(index.row()) 51 | # print(index.flags()) 52 | # print(id(index)) 53 | # #self.model.setData(index,"hellowrold") 54 | # s = self.model.index(5) 55 | # print(s) 56 | # print(type(s))""" 57 | # count = self.model.rowCount() 58 | # print(count) 59 | # for _ in range(count): 60 | # print(self.model.index(_).data()) 61 | # 62 | # def OnPushbutton_load_Cliked(self): 63 | # 64 | # self.groupslist.clear() 65 | # 66 | # self.groupslistfilename = QFileDialog.getOpenFileName(caption='选择群发列表', filter='*.xls')[0] 67 | # self.sendtextfilename = QFileDialog.getOpenFileName(caption='选择群发的文本', filter='*.txt')[0] 68 | # 69 | # # 70 | # work = xlrd.open_workbook(filename=self.groupslistfilename) 71 | # sheet = work.sheet_by_index(0) 72 | # for _ in range(sheet.nrows): 73 | # itme = sheet.cell_value(_, 0) 74 | # state = sheet.cell_value(_, 1) 75 | # 76 | # if state == "True": 77 | # if itme != '': 78 | # self.groupslist.append(sheet.cell_value(_, 0)) 79 | # # 80 | # 81 | # # 82 | # file = open(file=self.sendtextfilename, encoding='utf-8') 83 | # for _ in file.readlines(): 84 | # self.sendtext = self.sendtext + _ + '{ctrl}{ENTER}' 85 | # # 86 | # 87 | # # 88 | # self.model = QStringListModel() 89 | # self.model.setStringList(self.groupslist) 90 | # self.ui.listView.setModel(self.model) 91 | # # 92 | # 93 | # def threadfunction(self): 94 | # for _ in self.groupslist: 95 | # thread_start = threading.Thread(target=send_message, args=(_, self.sendtext)) 96 | # thread_start.start() 97 | # thread_start.join() 98 | # 99 | # def OnPushbutton_Start_Cliked(self): 100 | # self.thread_1 = threading.Thread(target=self.threadfunction) 101 | # self.thread_1.start() 102 | # 103 | # def _OnPushbutton_Close_Clicked(self): 104 | # sys.exit(0) 105 | # 106 | # 107 | # # 程序入口 108 | # if __name__ == "__main__": 109 | # app = QApplication(sys.argv) 110 | # # 初始化QApplication,界面展示要包含在QApplication初始化之后,结束之前 111 | # 112 | # window = MyWidget() 113 | # window.show() 114 | # # 初始化并展示我们的界面组件 115 | # 116 | # sys.exit(app.exec_()) 117 | # # 结束QApplication 118 | -------------------------------------------------------------------------------- /examples/PR/gen/群发/content.txt: -------------------------------------------------------------------------------- 1 | 你好 2 | -------------------------------------------------------------------------------- /examples/PR/gen/群发/ui_file_py.py: -------------------------------------------------------------------------------- 1 | # # -*- coding: utf-8 -*- 2 | # 3 | # ################################################################################ 4 | # ## Form generated from reading UI file 'ui_file.ui' 5 | # ## 6 | # ## Created by: Qt User Interface Compiler version 6.4.2 7 | # ## 8 | # ## WARNING! All changes made in this file will be lost when recompiling UI file! 9 | # ################################################################################ 10 | # 11 | # from PySide6.QtCore import (QCoreApplication, QMetaObject, QRect, 12 | # QSize) 13 | # from PySide6.QtGui import (QFont) 14 | # from PySide6.QtWidgets import (QLabel, QListView, QPushButton) 15 | # 16 | # 17 | # class Ui_Form(object): 18 | # def setupUi(self, Form): 19 | # if not Form.objectName(): 20 | # Form.setObjectName(u"Form") 21 | # Form.resize(500, 600) 22 | # Form.setMinimumSize(QSize(500, 600)) 23 | # Form.setMaximumSize(QSize(500, 600)) 24 | # self.listView = QListView(Form) 25 | # self.listView.setObjectName(u"listView") 26 | # self.listView.setGeometry(QRect(10, 50, 341, 541)) 27 | # self.label = QLabel(Form) 28 | # self.label.setObjectName(u"label") 29 | # self.label.setGeometry(QRect(20, 10, 321, 31)) 30 | # font = QFont() 31 | # font.setPointSize(20) 32 | # self.label.setFont(font) 33 | # self.pushButton_load = QPushButton(Form) 34 | # self.pushButton_load.setObjectName(u"pushButton_load") 35 | # self.pushButton_load.setGeometry(QRect(360, 50, 131, 141)) 36 | # font1 = QFont() 37 | # font1.setPointSize(30) 38 | # self.pushButton_load.setFont(font1) 39 | # self.pushButton_start = QPushButton(Form) 40 | # self.pushButton_start.setObjectName(u"pushButton_start") 41 | # self.pushButton_start.setGeometry(QRect(360, 410, 131, 141)) 42 | # self.pushButton_start.setFont(font1) 43 | # self.pushButton_close = QPushButton(Form) 44 | # self.pushButton_close.setObjectName(u"pushButton_close") 45 | # self.pushButton_close.setGeometry(QRect(360, 230, 131, 141)) 46 | # self.pushButton_close.setFont(font1) 47 | # 48 | # self.retranslateUi(Form) 49 | # 50 | # QMetaObject.connectSlotsByName(Form) 51 | # 52 | # # setupUi 53 | # 54 | # def retranslateUi(self, Form): 55 | # Form.setWindowTitle(QCoreApplication.translate("Form", u"Form", None)) 56 | # self.label.setText(QCoreApplication.translate("Form", u"\u7fa4\u53d1\u5217\u8868 : ", None)) 57 | # self.pushButton_load.setText(QCoreApplication.translate("Form", u"\u52a0\u8f7d", None)) 58 | # self.pushButton_start.setText(QCoreApplication.translate("Form", u"\u7fa4\u53d1", None)) 59 | # self.pushButton_close.setText(QCoreApplication.translate("Form", u"\u6682\u505c", None)) 60 | # # retranslateUi 61 | -------------------------------------------------------------------------------- /examples/PR/gen/群发/群发对象.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderWanFeng/PyOfficeRobot/c92ba08f35efe41613ef052a0f043b35d77f8b5c/examples/PR/gen/群发/群发对象.xls -------------------------------------------------------------------------------- /examples/PR/gen/群发/获取群名字.py: -------------------------------------------------------------------------------- 1 | # -*- codeing = utf-8 -*- 2 | # @Time : 2023/3/7 15:43 3 | # @Project_File : Start.py 4 | # @Dir_Path : 成品区/获取微信群聊名称 5 | # @File : TEMPLATE.py.py 6 | # @IDE_Name : PyCharm 7 | # ============================================================ 8 | # ============================================================ 9 | # ============================================================ 10 | # ============================================================ 11 | # ============================================================ 12 | 13 | import time 14 | 15 | import win32gui 16 | from pywinauto.application import Application 17 | from pywinauto.controls.uiawrapper import UIAWrapper 18 | from pywinauto.element_info import ElementInfo 19 | from pywinauto.controls.uia_controls import ListItemWrapper 20 | from pywinauto.controls.uia_controls import ButtonWrapper 21 | from pywinauto.keyboard import send_keys 22 | 23 | from win32gui import FindWindow 24 | from win32gui import ShowWindow 25 | from win32gui import MoveWindow 26 | from win32gui import SetForegroundWindow 27 | 28 | from xlwt.Workbook import Workbook 29 | from xlwt.Worksheet import Worksheet 30 | 31 | 32 | 33 | Group_Names = set() 34 | 35 | def Open_the_address_book_manager(): 36 | """ 37 | 打开通讯录管理器\n 38 | :return: 39 | :rtype: 40 | """ 41 | 42 | # 43 | Hwnd = FindWindow("WeChatMainWndForPC", "微信") 44 | ShowWindow(Hwnd, 9) 45 | SetForegroundWindow(Hwnd) 46 | MoveWindow(Hwnd,1920-800,0,800,800,True) 47 | App_Object = Application(backend="uia").connect(handle=Hwnd) 48 | WX_Windows = App_Object['微信'] 49 | 50 | WX_Wrapper : UIAWrapper = WX_Windows.wrapper_object() 51 | WX_Wrapper.draw_outline(colour='red',thickness=10) 52 | BUTTON_ADDRESS_ELEMENT = WX_Windows.child_window(title='通讯录') 53 | BUTTON_ADDRESS_WRAPPER : UIAWrapper = BUTTON_ADDRESS_ELEMENT.wrapper_object() 54 | 55 | BUTTON_ADDRESS_WRAPPER.draw_outline(colour='red',thickness=10) 56 | BUTTON_ADDRESS_WRAPPER.click_input() 57 | 58 | BUTTON_ADDRESS_MANAGE_ELEMENT = WX_Windows.child_window(title='通讯录管理') 59 | BUTTON_ADDRESS_MANAGE_WRAPPER : UIAWrapper = BUTTON_ADDRESS_MANAGE_ELEMENT.wrapper_object() 60 | BUTTON_ADDRESS_MANAGE_WRAPPER.draw_outline(colour='red',thickness=10) 61 | BUTTON_ADDRESS_MANAGE_WRAPPER.click_input() 62 | 63 | if(FindWindow("ContactManagerWindow","通讯录管理")): 64 | win32gui.CloseWindow(Hwnd) 65 | print(True) 66 | return True 67 | else: 68 | print(False) 69 | return False 70 | # 71 | 72 | def Get_all_group_names() -> list: 73 | """ 74 | 获取所有群聊的名字,以列表形式返回\n 75 | :return: 76 | :rtype: 77 | """ 78 | # 79 | Hwnd = FindWindow("ContactManagerWindow", "通讯录管理") 80 | x1,y1,x2,y2 = win32gui.GetWindowRect(Hwnd) 81 | width = x2 - x1 82 | height = y2 - y1 83 | point_x1 = 1920-width 84 | point_y1 = 0 85 | win32gui.MoveWindow(Hwnd,point_x1,point_y1,width,height,1) 86 | # 87 | 88 | 89 | # 90 | App_Object = Application(backend="uia").connect(handle=Hwnd) 91 | TXLGQ_Windows = App_Object['通讯录管理'] 92 | TXLGQ_Wrapper: UIAWrapper = TXLGQ_Windows.wrapper_object() 93 | TXLGQ_Wrapper.draw_outline(colour='red', thickness=10) 94 | 95 | Pane_FriendAuthority = TXLGQ_Windows.child_window(title='朋友权限', control_type='Pane') 96 | Pane_Label = TXLGQ_Windows.child_window(title='标签', control_type='Pane') 97 | Pane_Recent_Groups = TXLGQ_Windows.child_window(title='最近群聊', control_type='Pane') 98 | Pane_List_Groups = object() 99 | 100 | Wrapper_Pane_FriendAuthority : UIAWrapper = Pane_FriendAuthority.wrapper_object() 101 | Wrapper_Pane_Label : UIAWrapper = Pane_Label.wrapper_object() 102 | Wrapper_Pane_Recent_Groups : UIAWrapper = Pane_Recent_Groups.wrapper_object() 103 | 104 | Wrapper_Pane_FriendAuthority.draw_outline(colour='red',thickness=5) 105 | Wrapper_Pane_Label.draw_outline(colour='red',thickness=5) 106 | Wrapper_Pane_Recent_Groups.draw_outline(colour='red',thickness=5) 107 | 108 | Wrapper_Parent : UIAWrapper = Wrapper_Pane_FriendAuthority.parent() 109 | 110 | 111 | # 112 | 113 | 114 | # 115 | if(len(Wrapper_Parent.children()) == 4): 116 | Wrapper_Pane_Recent_Groups.draw_outline() 117 | Wrapper_Pane_Recent_Groups.click_input() 118 | Pane_List_Groups : UIAWrapper = Wrapper_Parent.children()[4] 119 | else: 120 | Pane_List_Groups : UIAWrapper = Wrapper_Parent.children()[4] 121 | #BUTTON_RECENT_GROUPS_WRAPPER.click_input() 122 | # 123 | 124 | #内部函数 125 | def Get_ListItem_At_Present() -> list: 126 | """ 127 | 返回当前页面所有的群名字\n 128 | 流程 : 129 | 1.获取所有的 'ListItem' 元素\n 130 | 2.对所有的 'ListItem' 进行迭代遍历,并且在迭代中定位Pane的位置,并且获取其 '文本'\n 131 | 定位 Pane 时,因为 Pane 是 Button 元素的同级元素,需先定位至 Button 元素,然后获取其父元素,再由其 父元素 去获取Pane元素\n 132 | 其中 Pane 元素跟 Button 的位置是固定的 \n 133 | Button 位于 父元素的索引为 0 的位置 \n 134 | Pane 位于 父元素的索引为 1 的位置 \n 135 | :return: 136 | :rtype: 137 | """ 138 | names = list() 139 | LIST_LISTITEM: list = Pane_List_Groups.descendants(control_type='ListItem') 140 | for _ in LIST_LISTITEM: 141 | Button : ButtonWrapper = _.descendants(control_type='Button')[0] 142 | Parent = Button.parent() 143 | Pane = Parent.children()[1] 144 | Pane.draw_outline() 145 | names.append(Pane.element_info.name) 146 | return names 147 | 148 | Pane_List_Groups.descendants(control_type='ListItem')[0].draw_outline(colour='red',thickness=5) 149 | Pane_List_Groups.descendants(control_type='ListItem')[0].click_input() 150 | 151 | #预估群数量(必须大于实际数量) 152 | for _ in range(100): 153 | namelist = Get_ListItem_At_Present() 154 | for _ in namelist: 155 | Group_Names.add(_) 156 | send_keys("{VK_DOWN}") 157 | print("提示:当前已经获取的群数量为 : %d"%(len(Group_Names))) 158 | 159 | 160 | def Save_Groups_To_Xls(groups=Group_Names,savefile="微信群名字.xls"): 161 | """ 162 | 163 | :return: 164 | :rtype: 165 | """ 166 | workbook = Workbook() 167 | worksheet: Worksheet = Workbook.add_sheet(workbook,"sheet1") 168 | 169 | row = int(0) 170 | for _ in Group_Names: 171 | print(_) 172 | worksheet.write(row,0,_) 173 | worksheet.write(row,1,"True") 174 | row = row + 1 175 | workbook.save("微信群名字.xls") 176 | 177 | 178 | if __name__ == "__main__": 179 | result : bool = Open_the_address_book_manager() 180 | 181 | if(result == False): 182 | exit() 183 | 184 | Get_all_group_names() 185 | 186 | Save_Groups_To_Xls() -------------------------------------------------------------------------------- /examples/PR/gen/自动加好友/Auto_Log.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 【当前时间:2023-4-16:23:16:21】-----正在读取第1行数据,当前公司名字为:【企业名称】 4 | 【当前时间:2023-4-16:23:16:21】-----正在读取第1行数据,该公司的联系电话有如下: 5 | 【['电话', '更多电话']】 6 | 【当前时间:2023-4-16:23:16:21】提示:当前遍历号码[ 电话 ] 不为手机号码,此处直接跳过 7 | 【当前时间:2023-4-16:23:16:21】提示:当前遍历号码[ 更多电话 ] 不为手机号码,此处直接跳过 8 | 9 | 10 | 【当前时间:2023-4-16:23:17:9】-----正在读取第1行数据,当前公司名字为:【企业名称】 11 | 【当前时间:2023-4-16:23:17:9】-----正在读取第1行数据,该公司的联系电话有如下: 12 | 【['电话', '更多电话']】 13 | 【当前时间:2023-4-16:23:17:9】提示:当前遍历号码[ 电话 ] 不为手机号码,此处直接跳过 14 | 【当前时间:2023-4-16:23:17:9】提示:当前遍历号码[ 更多电话 ] 不为手机号码,此处直接跳过 15 | 16 | 17 | 【当前时间:2023-4-16:23:25:7】-----正在读取第1行数据,当前公司名字为:【企业名称】 18 | 【当前时间:2023-4-16:23:25:7】-----正在读取第1行数据,该公司的联系电话有如下: 19 | 【['电话', '更多电话']】 20 | 【当前时间:2023-4-16:23:25:7】提示:当前遍历号码[ 电话 ] 不为手机号码,此处直接跳过 21 | 【当前时间:2023-4-16:23:25:7】提示:当前遍历号码[ 更多电话 ] 不为手机号码,此处直接跳过 22 | 23 | 24 | 【当前时间:2023-4-16:23:25:44】-----正在读取第1行数据,当前公司名字为:【企业名称】 25 | 【当前时间:2023-4-16:23:25:44】-----正在读取第1行数据,该公司的联系电话有如下: 26 | 【['电话', '更多电话']】 27 | 【当前时间:2023-4-16:23:25:44】提示:当前遍历号码[ 电话 ] 不为手机号码,此处直接跳过 28 | 【当前时间:2023-4-16:23:25:44】提示:当前遍历号码[ 更多电话 ] 不为手机号码,此处直接跳过 29 | 30 | 31 | 【当前时间:2023-4-16:23:25:44】-----正在读取第2行数据,当前公司名字为:【英德市雅家涂料有限公司】 32 | 【当前时间:2023-4-16:23:25:44】-----正在读取第2行数据,该公司的联系电话有如下: 33 | 【['15603052573.0', '15603052573.0']】 34 | 【当前时间:2023-4-16:23:25:44】提示:当前遍历号码[ 15603052573.0 ] 不为手机号码,此处直接跳过 35 | 【当前时间:2023-4-16:23:25:44】提示:当前遍历号码[ 15603052573.0 ] 不为手机号码,此处直接跳过 36 | 37 | 38 | 【当前时间:2023-4-16:23:28:45】-----正在读取第2行数据,当前公司名字为:【英德市雅家涂料有限公司】 39 | 【当前时间:2023-4-16:23:28:45】-----正在读取第2行数据,该公司的联系电话有如下: 40 | 【['15603052573.0', '15603052573.0']】 41 | 【当前时间:2023-4-16:23:28:45】提示:当前遍历号码[ 15603052573.0 ] 不为手机号码,此处直接跳过 42 | 【当前时间:2023-4-16:23:28:45】提示:当前遍历号码[ 15603052573.0 ] 不为手机号码,此处直接跳过 43 | 44 | 45 | 【当前时间:2023-4-16:23:31:14】-----正在读取第1行数据,当前公司名字为:【企业名称】 46 | 【当前时间:2023-4-16:23:31:14】-----正在读取第1行数据,该公司的联系电话有如下: 47 | 【['电话', '更多电话']】 48 | 【当前时间:2023-4-16:23:31:14】提示:当前遍历号码[ 电话 ] 不为手机号码,此处直接跳过 49 | 【当前时间:2023-4-16:23:31:14】提示:当前遍历号码[ 更多电话 ] 不为手机号码,此处直接跳过 50 | 51 | 52 | 【当前时间:2023-4-16:23:31:14】-----正在读取第2行数据,当前公司名字为:【英德市雅家涂料有限公司】 53 | 【当前时间:2023-4-16:23:31:14】-----正在读取第2行数据,该公司的联系电话有如下: 54 | 【['15603052573.0', '15603052573.0']】 55 | 【当前时间:2023-4-16:23:31:14】提示:当前遍历号码[ 15603052573.0 ] 不为手机号码,此处直接跳过 56 | 【当前时间:2023-4-16:23:31:14】提示:当前遍历号码[ 15603052573.0 ] 不为手机号码,此处直接跳过 57 | 58 | 59 | 【当前时间:2023-4-16:23:32:8】-----正在读取第1行数据,当前公司名字为:【企业名称】 60 | 【当前时间:2023-4-16:23:32:8】-----正在读取第1行数据,该公司的联系电话有如下: 61 | 【['15603052573', '更多电话']】 62 | 【当前时间:2023-4-16:23:32:8】提示:当前遍历号码[ 15603052573 ] 是一个手机号码,可以进行一个添加尝试 63 | 【当前时间:2023-4-16:23:32:45】提示:当前遍历号码[ 15603052573 ] 存在有微信号,已经完成添加好友操作 64 | 【当前时间:2023-4-16:23:33:7】提示:当前遍历号码[ 更多电话 ] 不为手机号码,此处直接跳过 65 | 66 | 67 | 【当前时间:2023-4-16:23:33:7】-----正在读取第2行数据,当前公司名字为:【英德市雅家涂料有限公司】 68 | 【当前时间:2023-4-16:23:33:7】-----正在读取第2行数据,该公司的联系电话有如下: 69 | 【['15603052573', '15603052573.0']】 70 | 【当前时间:2023-4-16:23:33:7】提示:当前遍历号码[ 15603052573 ] 是一个手机号码,可以进行一个添加尝试 71 | -------------------------------------------------------------------------------- /examples/PR/gen/自动加好友/main.py: -------------------------------------------------------------------------------- 1 | # -*- codeing = utf-8 -*- 2 | # @Time : 2023/2/1 14:47 3 | # @Project_File : 项目工程文档 4 | # @Dir_Path : Python工程文档/成品区/微信大漠 5 | # @File : Start.py 6 | # @IDE_Name : PyCharm 7 | # ============================================================ 8 | # ============================================================ 9 | # ============================================================ 10 | # ============================================================ 11 | # ============================================================ 12 | 13 | 14 | # excel_file = 77 line 15 | # log_file = 56 line 16 | 17 | 18 | import random 19 | from datetime import datetime 20 | from time import sleep 21 | 22 | import xlrd 23 | from pywinauto.application import * 24 | from pywinauto.base_wrapper import * 25 | from pywinauto.controls.uia_controls import * 26 | from pywinauto.controls.uiawrapper import * 27 | from pywinauto.keyboard import send_keys 28 | 29 | Count = int(0) 30 | MSG_LINE = int(1) 31 | 32 | 33 | def Get_NowTime(): 34 | "【当前时间:%s-%s-%s-:%s:%s:%s】正在读取第%s行数据,该公司的联系电话有如下:\n【%s】" 35 | year = datetime.now().year 36 | month = datetime.now().month 37 | day = datetime.now().day 38 | hour = datetime.now().hour 39 | minute = datetime.now().minute 40 | second = datetime.now().second 41 | return "【当前时间:{}-{}-{}:{}:{}:{}】".format(year, month, day, hour, minute, second) 42 | 43 | 44 | def Printf_Log(str_log): 45 | """ 46 | 打印日志到指定文件\n 47 | :return: 48 | :rtype: 49 | """ 50 | with open(r"Auto_Log.txt", 'a', encoding='utf-8') as f: 51 | f.write(str_log + "\n") 52 | 53 | 54 | def Is_Tel(TelNumber): 55 | """ 56 | 判断当前输入的联系电话是否为电话号码 57 | :param TelNumber: 58 | :type TelNumber: 59 | :return: 60 | :rtype: 61 | """ 62 | if '-' in TelNumber or len(TelNumber) != 11 or TelNumber[0] != "1": 63 | return False 64 | else: 65 | return True 66 | 67 | 68 | def Read_Excel(row): 69 | """ 70 | 读取整行数据,返回一个字典,字典的key为xls文件中的表头索引,其中 '电话' 这个可key是一个list列表对象\n 71 | :param row: 读取的行数据 72 | :type row: int类型 73 | :return: 整行数据 74 | :rtype: dict类型 75 | """ 76 | # 77 | Excel_Worker = xlrd.open_workbook(filename=r"Excel_File/【企查查】查企业-高级搜索“涂料”(202302030683).xls") 78 | Excel_Sheet = Excel_Worker.sheet_by_index(0) 79 | Excel_Dict_Data = dict() 80 | Excel_Dict_Data['企业名称'] = Excel_Sheet.cell(row, 0).value 81 | Excel_Dict_Data['登记状态'] = Excel_Sheet.cell(row, 1).value 82 | Excel_Dict_Data['法定代表人'] = Excel_Sheet.cell(rowx=row, colx=2).value 83 | Excel_Dict_Data['注册资本'] = Excel_Sheet.cell(rowx=row, colx=3).value 84 | Excel_Dict_Data['成立日期'] = Excel_Sheet.cell(rowx=row, colx=4).value 85 | Excel_Dict_Data['核准日期'] = Excel_Sheet.cell(rowx=row, colx=5).value 86 | Excel_Dict_Data['所属省份'] = Excel_Sheet.cell(rowx=row, colx=6).value 87 | Excel_Dict_Data['所属城市'] = Excel_Sheet.cell(rowx=row, colx=7).value 88 | Excel_Dict_Data['所属区县'] = Excel_Sheet.cell(rowx=row, colx=8).value 89 | Excel_Dict_Data['电话'] = Excel_Sheet.cell(rowx=row, colx=9).value 90 | Excel_Dict_Data['更多电话'] = Excel_Sheet.cell(rowx=row, colx=10).value 91 | Excel_Dict_Data['邮箱'] = Excel_Sheet.cell(rowx=row, colx=11).value 92 | Excel_Dict_Data['更多邮箱'] = Excel_Sheet.cell(rowx=row, colx=12).value 93 | Excel_Dict_Data['统一社会信用代码'] = Excel_Sheet.cell(rowx=row, colx=13).value 94 | Excel_Dict_Data['纳税人识别号'] = Excel_Sheet.cell(rowx=row, colx=14).value 95 | Excel_Dict_Data['注册号'] = Excel_Sheet.cell(rowx=row, colx=15).value 96 | Excel_Dict_Data['组织机构代码'] = Excel_Sheet.cell(rowx=row, colx=16).value 97 | Excel_Dict_Data['参保人数'] = Excel_Sheet.cell(rowx=row, colx=17).value 98 | Excel_Dict_Data['企业(机构)类型'] = Excel_Sheet.cell(rowx=row, colx=18).value 99 | Excel_Dict_Data['国标行业门类'] = Excel_Sheet.cell(rowx=row, colx=19).value 100 | Excel_Dict_Data['国标行业大类'] = Excel_Sheet.cell(rowx=row, colx=20).value 101 | Excel_Dict_Data['国标行业中类'] = Excel_Sheet.cell(rowx=row, colx=21).value 102 | Excel_Dict_Data['国标行业小类'] = Excel_Sheet.cell(rowx=row, colx=22).value 103 | Excel_Dict_Data['曾用名'] = Excel_Sheet.cell(rowx=row, colx=23).value 104 | Excel_Dict_Data['英文名'] = Excel_Sheet.cell(rowx=row, colx=24).value 105 | Excel_Dict_Data['网址'] = Excel_Sheet.cell(rowx=row, colx=25).value 106 | Excel_Dict_Data['企业地址'] = Excel_Sheet.cell(rowx=row, colx=26).value 107 | Excel_Dict_Data['最新年报地址'] = Excel_Sheet.cell(rowx=row, colx=27).value 108 | Excel_Dict_Data['经营范围'] = Excel_Sheet.cell(rowx=row, colx=28).value 109 | Excel_Dict_Data['电话'] = str(Excel_Dict_Data['电话']) + ";" + str(Excel_Dict_Data['更多电话']) 110 | Excel_Dict_Data['电话'] = list(Excel_Dict_Data['电话'].split(";")) 111 | Printf_Log("\n") 112 | Printf_Log("%s-----正在读取第%s行数据,当前公司名字为:【%s】" % (Get_NowTime(), row, Excel_Dict_Data['企业名称'])) 113 | Printf_Log( 114 | "%s-----正在读取第%s行数据,该公司的联系电话有如下:\n【%s】" % (Get_NowTime(), row, Excel_Dict_Data['电话'])) 115 | 116 | return Excel_Dict_Data 117 | # 118 | 119 | 120 | def FindFriend(WX_Windows, Tel_Number, ErrorCount=Count): 121 | """ 122 | 该函数用于在进入通讯录界面,输入手机号码一系列的操作\n 123 | :param WX_Windows: 微信窗口对象 124 | :param Tel_Number: 需要搜索的手机号码 125 | :param ErrorCount: 126 | :return: 127 | """ 128 | # 129 | print("提示:当前在正在对输入的手机号码进行一个查找") 130 | Button_AddFrient = WX_Windows.child_window(title="添加朋友") 131 | Button_AddFrient_Wrapper = Button_AddFrient.wrapper_object() 132 | """:type : pywinauto.controls.uiawrapper.UIAWrapper""" 133 | Button_AddFrient_Wrapper.draw_outline(colour='red', thickness=5) 134 | Button_AddFrient_Wrapper.click_input() 135 | 136 | Edit_Number = WX_Windows.child_window(title="微信号/手机号") 137 | Edit_Number_Wrapper = Edit_Number.wrapper_object() 138 | """:type : pywinauto.controls.uiawrapper.UIAWrapper""" 139 | Edit_Number_Wrapper.draw_outline(colour='red', thickness=5) 140 | Edit_Number_Wrapper.click_input() 141 | Edit_Number_Wrapper.type_keys(Tel_Number) 142 | 143 | Button_Find = WX_Windows.child_window(title='搜索:') 144 | Button_Find_Wrapper = Button_Find.wrapper_object() 145 | """:type : pywinauto.controls.uiawrapper.UIAWrapper""" 146 | Button_Find_Wrapper.draw_outline(colour='red', thickness=5) 147 | Button_Find_Wrapper.click_input() 148 | 149 | try: 150 | 151 | Button_AddTXL = WX_Windows.child_window(title='添加到通讯录') 152 | Button_AddTXL_Wrapper = Button_AddTXL.wrapper_object() 153 | """:type : pywinauto.controls.uiawrapper.UIAWrapper""" 154 | Button_AddTXL_Wrapper.draw_outline(colour="red", thickness=5) 155 | Button_AddTXL_Wrapper.click_input() 156 | print("提示:当前号码[ %s ]可以进行一个添加" % (Tel_Number)) 157 | 158 | return True 159 | except: 160 | try: 161 | print( 162 | "错误:当前号码出现错误,可能原因为 1.已经添加过该好友 2.该号码不存在 3.出现频繁次数了 当前号码为 : %s" % ( 163 | Tel_Number)) 164 | print("注意:当前出错次数为 : %d" % (ErrorCount)) 165 | 166 | find_result = WX_Windows.child_window(title=r'搜索结果') 167 | find_result_wrapper = find_result.wrapper_object() 168 | assert isinstance(find_result_wrapper, UIAWrapper) 169 | find_childs = find_result_wrapper.children() 170 | 171 | if (len(find_childs) == 1): 172 | print("\t\t 【警告】:%s-----当前号码并没有进行一个点击,请后续再进行操作" % (Get_NowTime())) 173 | 174 | elif (len(find_childs) == 2): 175 | find_childs[0].draw_outline(colour='red', thickness=5) 176 | find_resule_info = find_childs[0].element_info 177 | assert isinstance(find_resule_info, UIAElementInfo) 178 | print("\t\t 【错误】:%s-----%s" % (Get_NowTime(), find_resule_info.name)) 179 | Printf_Log("\t\t 【错误】:%s-----%s" % (Get_NowTime(), find_resule_info.name)) 180 | 181 | except: 182 | print("\t\t %s提示:当前遍历号码[ %s ]已经是微信好友" % (Get_NowTime(), Tel_Number)) 183 | Printf_Log("\t\t %s提示:当前遍历号码[ %s ]已经是微信好友" % (Get_NowTime(), Tel_Number)) 184 | 185 | return False 186 | # 187 | 188 | 189 | def Open_TXL(): 190 | # 191 | """ 192 | 该函数为打开通讯录界面\n 193 | :return: 194 | """ 195 | print("提示:当前正在进入通讯录界面") 196 | Button_SC_Wrapper.draw_outline(colour="red", thickness=5) 197 | Button_SC_Wrapper.click_input() 198 | sleep(0.5) 199 | Button_EXE_Wrapper.draw_outline(colour="red", thickness=5) 200 | Button_EXE_Wrapper.click_input() 201 | sleep(0.5) 202 | Button_LT_Wrapper.draw_outline(colour="red", thickness=5) 203 | Button_LT_Wrapper.click_input() 204 | sleep(0.5) 205 | Button_EXE_Wrapper.draw_outline(colour="red", thickness=5) 206 | Button_EXE_Wrapper.click_input() 207 | sleep(0.5) 208 | Button_TXL_Wrapper.draw_outline(colour="red", thickness=5) 209 | Button_TXL_Wrapper.click_input() 210 | sleep(0.5) 211 | # 212 | 213 | 214 | def Carry_TXL(App_Object, Hello_Str, Tel_Number, Excel_Data): 215 | """ 216 | 该函数为申请好友验证时的函数胡\n 217 | :param App_Object: 微信窗口操作对象 218 | :param Hello_Str: 打招呼的字符串 219 | :param Tel_Number: 备注名,用于备注该用户的手机号码 220 | :return: None 221 | """ 222 | # 223 | # Anchor为锚点 Target为目标点 224 | Anchor_1 = App_Object.child_window(title='发送添加朋友申请') 225 | Anchor_1.draw_outline(colour='green', thickness=5) 226 | Anchor_1_Wrapper = Anchor_1.wrapper_object() 227 | Anchor_1_Wrapper_Parent = Anchor_1_Wrapper.element_info.parent 228 | Children_1 = Anchor_1_Wrapper_Parent.children() 229 | Target_1 = Children_1[1] 230 | Target_1_Wrapper = UIAWrapper(Target_1) 231 | Target_1_Wrapper.draw_outline(colour='red', thickness=5) 232 | Target_1_Wrapper.click_input() 233 | Target_1_Wrapper.click_input() 234 | for _ in range(50): 235 | send_keys("{VK_END}") 236 | send_keys("{VK_BACK}") 237 | Target_1_Wrapper.type_keys(Hello_Str) 238 | 239 | Anchor_2 = App_Object.child_window(title='备注名') 240 | Anchor_2.draw_outline(colour='green', thickness=5) 241 | Anchor_2_Wrapper = Anchor_2.wrapper_object() 242 | Anchor_2_Wrapper_Parent = Anchor_2_Wrapper.element_info.parent 243 | Children_2 = Anchor_2_Wrapper_Parent.children() 244 | Target_2 = Children_2[1] 245 | Target_2_Wrapper = UIAWrapper(Target_2) 246 | Target_2_Wrapper.draw_outline(colour='red', thickness=5) 247 | Target_2_Wrapper.click_input() 248 | Target_2_Wrapper.click_input() 249 | for _ in range(30): 250 | send_keys("{VK_END}") 251 | send_keys("{VK_BACK}") 252 | Target_2_Wrapper.type_keys("【%s-%s-%s】" % (Excel_Data['所属城市'], Excel_Data['法定代表人'], Tel_Number)) 253 | # 254 | # App_Object.capture_as_image().save(Tel_Number + ".jpg") 255 | 256 | Button_Yes = App_Object.child_window(title='确定') 257 | Button_Yes_Wrapper = Button_Yes.wrapper_object() 258 | Button_Yes_Wrapper.draw_outline(colour='red', thickness=5) 259 | Button_Yes_Wrapper.click_input() 260 | 261 | # Button_Yes = App_Object.child_window(title='确定') 262 | # Button_Yes_Wrapper = Button_Yes.wrapper_object() 263 | # Button_Parent = Button_Yes_Wrapper.element_info.parent 264 | # Button_No = Button_Parent.children()[1] 265 | # Button_No_Wrapper = UIAWrapper(Button_No) 266 | # Button_No_Wrapper.draw_outline(colour='red',thickness=5) 267 | # Button_No_Wrapper.click_input() 268 | 269 | 270 | if __name__ == "__main__": 271 | 272 | # 273 | Get_WeChat_Hwnd = lambda: win32gui.FindWindow("WeChatMainWndForPC", "微信") 274 | WeChat_Hwnd = Get_WeChat_Hwnd() 275 | # 276 | 277 | # 278 | win32gui.ShowWindow(WeChat_Hwnd, 9) 279 | # win32gui.SetWindowPos(WeChat_Hwnd, win32con.HWND_TOPMOST, 0,0,800,800, win32con.SWP_NOMOVE | win32con.SWP_NOACTIVATE| win32con.SWP_NOOWNERZORDER|win32con.SWP_SHOWWINDOW) 280 | win32gui.MoveWindow(WeChat_Hwnd, 1920 - 800, 0, 800, 800, True) 281 | print("Msg:窗口设置完毕") 282 | # 283 | 284 | # 285 | App_Object = Application(backend="uia").connect(handle=WeChat_Hwnd) 286 | WX_Windows = App_Object['微信'] 287 | """:type : pywinauto.application.WindowSpecification""" 288 | WX_Wrapper = WX_Windows.wrapper_object() 289 | """:type : pywinauto.controls.uiawrapper.UIAWrapper""" 290 | WX_Wrapper.draw_outline(colour="red", thickness=5) 291 | # 292 | 293 | # 294 | Button_LT = WX_Windows.child_window(title='聊天') 295 | Button_TXL = WX_Windows.child_window(title='通讯录') 296 | Button_SC = WX_Windows.child_window(title='收藏') 297 | Button_EXE = WX_Windows.child_window(title='小程序面板') 298 | 299 | Button_LT_Wrapper = Button_LT.wrapper_object() 300 | Button_TXL_Wrapper = Button_TXL.wrapper_object() 301 | Button_SC_Wrapper = Button_SC.wrapper_object() 302 | Button_EXE_Wrapper = Button_EXE.wrapper_object() 303 | 304 | # assert isinstance(Button_LT_Wrapper,UIAWrapper) 305 | # assert isinstance(Button_TXL_Wrapper,UIAWrapper) 306 | # assert isinstance(Button_SC_Wrapper,UIAWrapper) 307 | # assert isinstance(Button_EXE_Wrapper,UIAWrapper) 308 | 309 | # 310 | 311 | row = int(input("请输入在多少行开始 : ")) 312 | while True: 313 | Excel_Data = Read_Excel(row=row) 314 | 315 | print("\n") 316 | print("\n") 317 | print("\n") 318 | print("\n") 319 | print("\n") 320 | print("提示:当前运行至Excel中的第%d行数据" % (row)) 321 | print("提示:当前运行至Excel中的第%d行数据,该公司名字为 : %s" % (row, Excel_Data['企业名称'])) 322 | print("提示:当前运行至Excel中的第%d行数据,该公司法定代表人为 : %s" % (row, Excel_Data['法定代表人'])) 323 | print("提示:当前运行至Excel中的第%d行数据,该公司所属城市为 : %s" % (row, Excel_Data['所属城市'])) 324 | print("提示:当前运行至Excel中的第%d行数据,该公司网址为 : %s" % (row, Excel_Data['网址'])) 325 | print("提示:当前运行至Excel中的第%d行数据,该公司电话为 : %s" % (row, Excel_Data['电话'])) 326 | print("\n") 327 | 328 | for _ in Excel_Data["电话"]: 329 | 330 | if Is_Tel(_): 331 | print("\t\t %s提示:当前遍历号码[ %s ] 是一个手机号码,可以进行一个添加尝试" % (Get_NowTime(), _)) 332 | Printf_Log("\t\t %s提示:当前遍历号码[ %s ] 是一个手机号码,可以进行一个添加尝试" % (Get_NowTime(), _)) 333 | 334 | Open_TXL() 335 | result = FindFriend(WX_Windows=WX_Windows, Tel_Number=_, ErrorCount=Count) 336 | 337 | if (result == False): 338 | Count = Count + 1 339 | print("\t\t %s提示:当前遍历号码[ %s ] 不存在有微信号" % (Get_NowTime(), _)) 340 | Printf_Log("\t\t %s提示:当前遍历号码[ %s ] 不存在有微信号" % (Get_NowTime(), _)) 341 | 342 | elif (result == True): 343 | Carry_TXL(App_Object=WX_Windows, Hello_Str="你好,老板。我们是做大小防白的,有需要可以了解下", 344 | Tel_Number=_, Excel_Data=Excel_Data) 345 | print("\t\t %s提示:当前遍历号码[ %s ] 存在有微信号,已经完成添加好友操作" % (Get_NowTime(), _)) 346 | Printf_Log("\t\t %s提示:当前遍历号码[ %s ] 存在有微信号,已经完成添加好友操作" % (Get_NowTime(), _)) 347 | Random_Wait_Time = random.randint(15, 25) 348 | print("\t\t %s-----随机等待时间为%d秒" % (Get_NowTime(), Random_Wait_Time)) 349 | sleep(Random_Wait_Time) 350 | 351 | else: 352 | print("\t\t %s提示:当前遍历号码[ %s ] 不为手机号码,此处直接跳过" % (Get_NowTime(), _)) 353 | Printf_Log("\t\t %s提示:当前遍历号码[ %s ] 不为手机号码,此处直接跳过" % (Get_NowTime(), _)) 354 | 355 | if Count > 10: 356 | print("\t\t %s错误:当前遍历出现错误过多,此处开始不再添加,具体情况查看日志" % (Get_NowTime())) 357 | Printf_Log("\t\t %s错误:当前遍历出现错误过多,此处开始不再添加,具体情况查看日志" % (Get_NowTime())) 358 | 359 | sleep(8888) 360 | exec 361 | row = row + 1 362 | -------------------------------------------------------------------------------- /examples/PR/tang/test_copy.py: -------------------------------------------------------------------------------- 1 | import win32clipboard 2 | from ctypes import * 3 | 4 | 5 | class DROPFILES(Structure): 6 | _fields_ = [ 7 | ("pFiles", c_uint), 8 | ("x", c_long), 9 | ("y", c_long), 10 | ("fNC", c_int), 11 | ("fWide", c_bool), 12 | ] 13 | 14 | 15 | def setClipboardFiles(paths): 16 | files = ("\0".join(paths)).replace("/", "\\") 17 | data = files.encode("U16")[2:] + b"\0\0" 18 | win32clipboard.OpenClipboard() 19 | try: 20 | win32clipboard.EmptyClipboard() 21 | win32clipboard.SetClipboardData( 22 | win32clipboard.CF_HDROP, matedata + data) 23 | finally: 24 | win32clipboard.CloseClipboard() 25 | 26 | 27 | def readClipboardFilePaths(): 28 | win32clipboard.OpenClipboard() 29 | try: 30 | return win32clipboard.GetClipboardData(win32clipboard.CF_HDROP) 31 | finally: 32 | win32clipboard.CloseClipboard() 33 | 34 | 35 | pDropFiles = DROPFILES() 36 | pDropFiles.pFiles = sizeof(DROPFILES) 37 | pDropFiles.fWide = True 38 | matedata = bytes(pDropFiles) 39 | filename = [r"d:\a.pptx"] 40 | setClipboardFiles(filename) 41 | 42 | # 作者:18037128621 43 | # 链接:https: // juejin.cn / post / 7123461124162322445 44 | # 来源:稀土掘金 45 | # 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 -------------------------------------------------------------------------------- /examples/PR/tang/weixin_version.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @个人网站 :www.python-office.com 6 | @Date :2023/4/16 22:55 7 | @Description : 8 | ''' 9 | -------------------------------------------------------------------------------- /examples/demo/001-发一条信息.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫,微信:CoderWanFeng 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @学习网站 :https://www.python-office.com 6 | @Date :2023/2/13 21:19 7 | @本段代码的视频说明 :https://www.bilibili.com/video/BV1te4y1y7Ro 8 | ''' 9 | 10 | # 首先,将PyOfficeRobot模块导入到我们的代码块中。 11 | import PyOfficeRobot 12 | 13 | # PyOfficeRobot.chat.send_message(who='小红书:程序员晚枫', message='你好') 14 | PyOfficeRobot.chat.send_message(who='晚枫', message='你好') 15 | """ 16 | 17 | """ 18 | -------------------------------------------------------------------------------- /examples/demo/002-发文件.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫,微信:CoderWanFeng 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @学习网站 :https://www.python-office.com 6 | @Date :2023/2/13 21:19 7 | @本段代码的视频说明 :https://www.bilibili.com/video/BV1te4y1y7Ro 8 | ''' 9 | 10 | import PyOfficeRobot 11 | 12 | # PyOfficeRobot.file.send_file(who='B站:程序员晚枫', file=r'C:\Users\Lenovo\Desktop\temp\0.jpg') 13 | PyOfficeRobot.file.send_file(who='程序员晚枫', file=r'003-根据关键词回复.py') 14 | -------------------------------------------------------------------------------- /examples/demo/003-根据关键词回复.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫,微信:CoderWanFeng 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @学习网站 :https://www.python-office.com 6 | @Date :2023/2/13 21:19 7 | @本段代码的视频说明 :https://www.bilibili.com/video/BV1m8411b7LZ 8 | ''' 9 | import PyOfficeRobot 10 | 11 | keywords = { 12 | "我要报名": "你好,这是报名链接:www.python-office.com", 13 | "点赞了吗?": "点了", 14 | "关注了吗?": "必须的", 15 | "投币了吗?": "三连走起", 16 | } 17 | # PyOfficeRobot.chat.chat_by_keywords(who='抖音:程序员晚枫', keywords=keywords) 18 | PyOfficeRobot.chat.chat_by_keywords(who='程序员晚枫', keywords=keywords) 19 | -------------------------------------------------------------------------------- /examples/demo/004-定时发送.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫,微信:CoderWanFeng 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @学习网站 :https://www.python-office.com 6 | @Date :2023/2/13 21:19 7 | @本段代码的视频说明 :https://www.bilibili.com/video/BV1m8411b7LZ 8 | ''' 9 | import PyOfficeRobot 10 | 11 | -------------------------------------------------------------------------------- /examples/demo/005-自定义功能.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫,微信:CoderWanFeng 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @学习网站 :https://www.python-office.com 6 | @代码日期 :2023/7/9 23:22 7 | @本段代码的视频说明 :https://www.bilibili.com/video/BV14R4y127h6 8 | ''' 9 | import office 10 | 11 | import PyOfficeRobot 12 | 13 | keywords = { 14 | "我要报名": "你好,这是报名链接:www.python-office.com", 15 | "来个密码": office.tools.passwordtools(), 16 | } 17 | PyOfficeRobot.chat.chat_by_keywords(who='知乎:程序员晚枫', keywords=keywords) 18 | -------------------------------------------------------------------------------- /examples/demo/006-独立版本.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫,微信:CoderWanFeng 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @学习网站 :https://www.python-office.com 6 | @代码日期 :2023/7/9 23:25 7 | @本段代码的视频说明 :https://www.bilibili.com/video/BV1SY411y7Uh 8 | ''' 9 | 10 | # 原始方式 11 | import office 12 | 13 | office.wechat.send_message(who='百度一下:程序员晚枫', message='点个star吧') 14 | 15 | # 独立方式 16 | import PyOfficeRobot 17 | 18 | PyOfficeRobot.chat.send_message(who='百度一下:程序员晚枫', message='点个star吧') 19 | -------------------------------------------------------------------------------- /examples/demo/007-收集群消息.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫,微信:CoderWanFeng 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @学习网站 :https://www.python-office.com 6 | @代码日期 :2023/7/9 23:28 7 | @本段代码的视频说明 :https://www.bilibili.com/video/BV1eD4y1g7yZ 8 | ''' 9 | 10 | import PyOfficeRobot 11 | 12 | PyOfficeRobot.file.get_group_list() 13 | -------------------------------------------------------------------------------- /examples/demo/008-发消息换行.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫,微信:CoderWanFeng 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @学习网站 :https://www.python-office.com 6 | @代码日期 :2023/7/9 23:29 7 | @本段代码的视频说明 :https://www.bilibili.com/video/BV1Xg4y1s79z 8 | ''' 9 | 10 | import PyOfficeRobot 11 | 12 | PyOfficeRobot.chat.send_message(who='CSDN:程序员晚枫', message='你好' + '{ctrl}{ENTER}' + 'hello') 13 | -------------------------------------------------------------------------------- /examples/demo/009-批量加好友.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @个人网站 :www.python-office.com 6 | @Date :2023/4/27 21:19 7 | @Description : 8 | ''' 9 | 10 | """ 11 | 批量加好友,1行代码实现 12 | """ 13 | # pip install PyOfficeRobot>=0.1.5 14 | import PyOfficeRobot 15 | 16 | msg = "你好,我是程序员晚枫,全网同名。" 17 | num_notes = { 18 | # '微信号/手机号': '你给Ta的备注', 19 | 'hdylw1024': '公众号-程序员晚枫', 20 | # 'CoderWanFeng': '小红书-晚枫', 21 | } 22 | PyOfficeRobot.friend.add(msg=msg, num_notes=num_notes) 23 | -------------------------------------------------------------------------------- /examples/demo/010-定时群发.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @个人网站 :www.python-office.com 6 | @Date :2023/4/27 21:20 7 | @Description : 8 | ''' 9 | 10 | """ 11 | 定时群发消息 12 | """ 13 | 14 | # pip 15 | import PyOfficeRobot 16 | 17 | if __name__ == '__main__': 18 | PyOfficeRobot.group.send() 19 | -------------------------------------------------------------------------------- /examples/demo/010-定时群发的资料/content.txt: -------------------------------------------------------------------------------- 1 | 大家好,这里是程序员晚枫。 2 | 今天的视频更新了! 3 | 【批量添加好友】 4 | 视频链接:https://www.bilibili.com/video/BV1DV4y1o7t2 -------------------------------------------------------------------------------- /examples/demo/010-定时群发的资料/群发对象.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderWanFeng/PyOfficeRobot/c92ba08f35efe41613ef052a0f043b35d77f8b5c/examples/demo/010-定时群发的资料/群发对象.xls -------------------------------------------------------------------------------- /examples/demo/011-chat_chatgpt.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @个人网站 :www.python-office.com 6 | @Date :2023/3/19 18:17 7 | @Description : 8 | ''' 9 | # pip install PyOfficeRobot 10 | import PyOfficeRobot 11 | 12 | # 13 | PyOfficeRobot.chat.chat_by_gpt(who='程序员晚枫', api_key='你的api_key') 14 | 15 | # 24小时、 16 | -------------------------------------------------------------------------------- /examples/demo/012-智能聊天.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @学习网站 :https://www.python-office.com 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫,微信:CoderWanFeng 6 | @代码日期 :2023/7/28 21:54 7 | @本段代码的视频说明 : 8 | ''' 9 | 10 | # pip install PyOfficeRobot 11 | import PyOfficeRobot 12 | 13 | # 智能聊天,只需要一行代码 14 | PyOfficeRobot.chat.chat_robot(who='程序员晚枫') 15 | 16 | -------------------------------------------------------------------------------- /examples/demo/013-阿里大模型.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @学习网站 :https://www.python-office.com 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫,微信:CoderWanFeng 6 | @代码日期 :2024/2/1 0:17 7 | @本段代码的视频说明 : 8 | ''' 9 | 10 | import PyOfficeRobot 11 | 12 | PyOfficeRobot.chat.chat_ali(who='程序员晚枫', key="你的阿里大模型的key,获取地址见下文") 13 | -------------------------------------------------------------------------------- /examples/demo/014-智谱大模型.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @学习网站 :https://www.python-office.com 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫,微信:CoderWanFeng 6 | @代码日期 :2024/2/1 0:17 7 | @本段代码的视频说明 : 8 | ''' 9 | 10 | import PyOfficeRobot 11 | 12 | PyOfficeRobot.chat.chat_by_zhipu(who='程序员晚枫', 13 | key="你的智谱大模型的key,免费获取方式,见下文", 14 | model='glm-4') 15 | -------------------------------------------------------------------------------- /examples/demo/015-DeepSeek大模型.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @学习网站 :https://www.python-office.com 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫,微信:CoderWanFeng 6 | @代码日期 :2025/02/12 0:17 7 | @本段代码的视频说明 : 8 | ''' 9 | 10 | # 导入PyOfficeRobot模块,免费下载:pip install PyOfficeRobot 11 | import PyOfficeRobot 12 | 13 | PyOfficeRobot.chat.chat_by_deepseek(who='晚枫', api_key="你自己的api_key") 14 | 15 | """ 16 | Python和PyCharm的安装:https://www.python-office.com/course-002/15-Python/15-Python.html 17 | 18 | api_key免费获取:https://www.python-office.com/ 19 | """ 20 | -------------------------------------------------------------------------------- /examples/dev/another_test1.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫,微信:CoderWanFeng 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @学习网站 :https://www.python-office.com 6 | @代码日期 :2023/11/9 23:00 7 | @本段代码的视频说明 : 8 | ''' 9 | 10 | #微信定时群发功能 11 | #微信调用模拟类 start 12 | import time 13 | 14 | import win32api 15 | import win32clipboard as w 16 | import win32con 17 | import win32gui 18 | 19 | #微信调用模拟类 end 20 | 21 | #调用HTTP插件类 22 | import requests 23 | 24 | 25 | # 把文字放入剪贴板 26 | def setText(aString): 27 | w.OpenClipboard() 28 | w.EmptyClipboard() 29 | w.SetClipboardData(win32con.CF_UNICODETEXT, aString) 30 | w.CloseClipboard() 31 | 32 | 33 | # 模拟ctrl+V 34 | def ctrlV(): 35 | win32api.keybd_event(17, 0, 0, 0) # 按下ctrl 36 | win32api.keybd_event(86, 0, 0, 0) # 按下V 37 | win32api.keybd_event(86, 0, win32con.KEYEVENTF_KEYUP, 0) # 释放V 38 | win32api.keybd_event(17, 0, win32con.KEYEVENTF_KEYUP, 0) # 释放ctrl 39 | 40 | 41 | # 模拟alt+s 42 | def altS(): 43 | win32api.keybd_event(18, 0, 0, 0) 44 | win32api.keybd_event(83, 0, 0, 0) 45 | win32api.keybd_event(83, 0, win32con.KEYEVENTF_KEYUP, 0) 46 | win32api.keybd_event(18, 0, win32con.KEYEVENTF_KEYUP, 0) 47 | 48 | 49 | # 模拟enter 50 | def enter(): 51 | win32api.keybd_event(13, 0, 0, 0) 52 | win32api.keybd_event(13, 0, win32con.KEYEVENTF_KEYUP, 0) 53 | 54 | 55 | # 模拟鼠标单击 56 | def click(): 57 | win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0) 58 | win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0) 59 | 60 | 61 | # 移动鼠标的位置 62 | def movePos(x, y): 63 | win32api.SetCursorPos((x, y)) 64 | 65 | 66 | if __name__ == "__main__": 67 | target_time = ['17:55', '22:45', '20:00'] # 这里是发送时间 68 | name_list = ['易'] # 这里是要发送信息的联系人 ['易', '天极'] 69 | 70 | payload = dict(date='2023-11-09', store_name='万达二') 71 | r = requests.post('http://wd2.xwdgp.vip/public/admin/selectTodayDeclaration', data=payload) 72 | # print(r.text) 73 | #print(r.json()['copy_text']) 74 | #send_content = r.json()['copy_text']; 75 | # send_content = r.json()['copy_data']['beautician'] 76 | send_content = '' 77 | next_line = '{ctrl}{ENTER}' 78 | for word in r.json()['copy_data']['beautician']: 79 | # print(word)是数组 80 | send_content += word + next_line 81 | 82 | #send_content = "这里是需要发送的信息内容" # 这里是需要发送的信息内容 83 | while True: 84 | now = time.strftime("%m月%d日%H:%M", time.localtime()) # 返回格式化时间 85 | print(now) 86 | if now[-5:] in target_time: # 判断时间是否为设定时间 87 | hwnd = win32gui.FindWindow("WeChatMainWndForPC", '微信') # 返回微信窗口的句柄信息 88 | win32gui.ShowWindow(hwnd, win32con.SW_SHOW) # 激活并显示微信窗口 89 | win32gui.MoveWindow(hwnd, 0, 0, 1000, 700, True) # 将微信窗口移动到指定位置和大小 90 | time.sleep(1) 91 | for name in name_list: 92 | movePos(28, 147) 93 | click() 94 | movePos(148, 35) 95 | click() 96 | time.sleep(1) 97 | setText(name) 98 | ctrlV() 99 | time.sleep(1) # 等待联系人搜索成功 100 | enter() 101 | time.sleep(1) 102 | setText(send_content) 103 | ctrlV() 104 | time.sleep(1) 105 | altS() 106 | time.sleep(1) 107 | win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0) 108 | time.sleep(60) -------------------------------------------------------------------------------- /examples/dev/test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @学习网站 :https://www.python-office.com 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫,微信:CoderWanFeng 6 | @代码日期 :2024/4/12 21:32 7 | @本段代码的视频说明 : 8 | ''' 9 | import porobot 10 | 11 | reply_msg = porobot.normal.chat('你叫什么名字?') 12 | print(reply_msg) 13 | -------------------------------------------------------------------------------- /examples/dev/userMessage.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderWanFeng/PyOfficeRobot/c92ba08f35efe41613ef052a0f043b35d77f8b5c/examples/dev/userMessage.txt -------------------------------------------------------------------------------- /examples/dev/关键字自动回复/keywords_data.csv: -------------------------------------------------------------------------------- 1 | 序号,关键词,回复内容 2 | 1,报名,你好,这是报名链接:www.这是报名链接.com 3 | 2,学习,你好,这是学习链接:www.这是学习链接.com 4 | 3,课程,你好,这是课程链接:www.这是课程链接.com -------------------------------------------------------------------------------- /examples/dev/关键字自动回复/main.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import uiautomation as auto 3 | import time 4 | import logging 5 | 6 | # 配置日志 7 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 8 | 9 | class WeChatBot: 10 | def __init__(self, csv_path, contact_name): 11 | self.df = pd.read_csv(csv_path) 12 | self.contact_name = contact_name 13 | self.wx = self.find_wechat_window() 14 | self.last_processed_msg = None 15 | 16 | def find_wechat_window(self): 17 | try: 18 | wx_window = auto.WindowControl(searchDepth=3, Name='微信') 19 | if wx_window.Exists(0): 20 | wx_window.SwitchToThisWindow() 21 | return wx_window 22 | else: 23 | logging.warning("未找到微信窗口") 24 | return None 25 | except Exception as e: 26 | logging.error(f"查找微信窗口出错: {e}") 27 | return None 28 | 29 | def select_conversation(self): 30 | conversations = self.wx.ListControl() 31 | for conversation in conversations.GetChildren(): 32 | if conversation.Name == self.contact_name: 33 | conversation.Click(simulateMove=False) 34 | break 35 | 36 | def get_last_message(self): 37 | try: 38 | message_list = self.wx.ListControl(Name='消息').GetChildren() 39 | if message_list: 40 | last_msg = message_list[-1].Name 41 | logging.info(f"获取到最后一条消息: {last_msg}") 42 | return last_msg 43 | else: 44 | logging.info("消息列表为空") 45 | return None 46 | except Exception as e: 47 | logging.error(f"获取最后一条消息出错: {e}") 48 | return None 49 | 50 | def send_reply(self, reply): 51 | try: 52 | self.wx.SendKeys(reply, waitTime=0) 53 | self.wx.SendKeys('{Enter}', waitTime=1) 54 | logging.info(f"回复内容是: {reply}") 55 | except Exception as e: 56 | logging.error(f"发送消息出错: {e}") 57 | 58 | def process_messages(self): 59 | while True: 60 | time.sleep(3) 61 | last_msg = self.get_last_message() 62 | if last_msg and last_msg != self.last_processed_msg: 63 | if last_msg not in self.df['回复内容'].values: 64 | matched_replies = self.df[self.df['关键词'].apply(lambda x: x in last_msg)]['回复内容'] 65 | if not matched_replies.empty: 66 | for reply in matched_replies: 67 | reply = reply.replace('{br}', '\n') 68 | self.send_reply(reply) 69 | self.last_processed_msg = last_msg 70 | else: 71 | logging.info("没有匹配的关键字") 72 | else: 73 | logging.info("最后一条消息是自动回复内容,跳过回复") 74 | else: 75 | logging.info("没有新消息或消息已处理") 76 | 77 | # 示例调用 78 | bot = WeChatBot('keywords_data.csv', '测试群2') 79 | if bot.wx: 80 | bot.select_conversation() 81 | bot.process_messages() -------------------------------------------------------------------------------- /examples/dev/开发记录.md: -------------------------------------------------------------------------------- 1 | 1. 发送截图 2 | 2. 保存图片 3 | 3. SendClipboard -------------------------------------------------------------------------------- /examples/dev/微信群信息收集/main.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import uiautomation as auto 3 | import time 4 | import logging 5 | import openpyxl 6 | import os 7 | from openpyxl import Workbook 8 | from openpyxl.styles import Alignment, Font 9 | from datetime import datetime, timedelta 10 | # 配置日志 11 | 12 | 13 | class WeChatBot: 14 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 15 | def __init__(self, file_name,contact_name): 16 | """ 17 | 初始化 WeChatBot 类,指定的联系人名称。 18 | """ 19 | self.contact_name = contact_name 20 | self.wx = self.find_wechat_window() 21 | self.last_processed_msg = None 22 | self.file_name = file_name 23 | # 判断文件是否存在 24 | if os.path.isfile(self.file_name): 25 | logging.info(f"文件 '{self.file_name}' 已存在。") 26 | else: 27 | self.create_excel_file() 28 | 29 | def generate_date_range(self): 30 | """ 31 | 生成当前月份的日期范围 32 | """ 33 | now = datetime.now() 34 | year = now.year 35 | month = now.month 36 | if month == 12: 37 | next_month = datetime(year + 1, 1, 1) 38 | else: 39 | next_month = datetime(year, month + 1, 1) 40 | last_day_of_month = next_month - timedelta(days=1) 41 | start_date = datetime(year, month, 1).strftime('%m月%d号') 42 | end_date = last_day_of_month.strftime('%m月%d号') 43 | return f"来客/视频会议信息({start_date}-{end_date})" 44 | 45 | def setup_worksheet(self,ws, title): 46 | """ 47 | 设置工作表的标题和表头 48 | """ 49 | # 设置标题 50 | ws.merge_cells('A1:H1') # 合并A1到H1单元格 51 | ws['A1'] = title # 设置标题内容 52 | ws['A1'].font = Font(size=20) 53 | ws['A1'].alignment = Alignment(horizontal='center', vertical='center') 54 | 55 | # 设置表头 56 | headers = ["日期时间", "客户", "来客/出席人数", "客户职位", "目的", "对应级别", "对应人员", "会议室"] 57 | for col, header in enumerate(headers, start=1): 58 | ws.cell(row=2, column=col, value=header) 59 | ws.cell(row=2, column=col).font = Font(size=14) 60 | ws.cell(row=2, column=col).alignment = Alignment(horizontal='center', vertical='center') 61 | 62 | def set_column_widths(self,ws): 63 | """ 64 | 设置列宽 65 | """ 66 | for col in range(1, 9): # A到H列 67 | ws.column_dimensions[chr(64 + col)].width = 20 68 | 69 | def set_cell_styles(self, ws): 70 | """ 71 | 设置单元格样式 72 | """ 73 | max_row = ws.max_row # 动态获取最大行 74 | for row in ws.iter_rows(min_row=2, max_row=max_row, min_col=1, max_col=8): 75 | for cell in row: 76 | cell.font = Font(size=14) 77 | cell.alignment = Alignment(horizontal='center', vertical='center') 78 | 79 | def create_excel_file(self): 80 | """ 81 | 创建Excel文件 82 | """ 83 | # 创建一个新的工作簿 84 | wb = Workbook() 85 | ws = wb.active 86 | 87 | # 生成标题 88 | title = self.generate_date_range() 89 | 90 | # 设置工作表 91 | self.setup_worksheet(ws, title) 92 | self.set_column_widths(ws) 93 | self.set_cell_styles(ws) 94 | 95 | # 保存文件 96 | wb.save(self.file_name) 97 | logging.info(f"Excel 文件 '{self.file_name}' 创建成功!") 98 | 99 | def find_wechat_window(self): 100 | """ 101 | 查找微信窗口并切换到该窗口。 102 | """ 103 | try: 104 | wx_window = auto.WindowControl(searchDepth=3, Name='微信') 105 | if wx_window.Exists(0): 106 | wx_window.SwitchToThisWindow() 107 | return wx_window 108 | else: 109 | logging.warning("未找到微信窗口") 110 | return None 111 | except Exception as e: 112 | logging.error(f"查找微信窗口出错: {e}") 113 | return None 114 | 115 | def select_conversation(self): 116 | """ 117 | 选择指定的联系人对话。 118 | """ 119 | conversations = self.wx.ListControl() 120 | for conversation in conversations.GetChildren(): 121 | if conversation.Name == self.contact_name: 122 | conversation.Click(simulateMove=False) 123 | break 124 | 125 | def get_last_message(self): 126 | """ 127 | 获取对话中的最后一条消息。 128 | """ 129 | try: 130 | message_list = self.wx.ListControl(Name='消息').GetChildren() 131 | if message_list: 132 | last_msg = message_list[-1].Name 133 | logging.info(f"获取到最后一条消息: {last_msg}") 134 | return last_msg 135 | else: 136 | logging.info("消息列表为空") 137 | return None 138 | except Exception as e: 139 | logging.error(f"获取最后一条消息出错: {e}") 140 | return None 141 | 142 | 143 | 144 | 145 | def process_messages(self): 146 | """ 147 | 处理新消息并保存到 Excel 文件。 148 | """ 149 | while True: 150 | time.sleep(3) 151 | last_msg = self.get_last_message() 152 | if last_msg and last_msg != self.last_processed_msg: 153 | if "会议信息" in last_msg: 154 | # 解析信息 155 | message = last_msg 156 | message = message.strip() 157 | lines = message.split('\n') 158 | meeting_info_list = [] 159 | for line in lines: 160 | if ':' in line: 161 | _, value = line.split(':', 1) 162 | meeting_info_list.append(value.strip()) 163 | data = meeting_info_list 164 | # 将数据写入 Excel 文件 165 | file_path = self.file_name 166 | workbook = openpyxl.load_workbook(file_path) 167 | sheet = workbook.active 168 | # 查找最后一行的有效数据 169 | next_row = sheet.max_row + 1 170 | if next_row == 1 and not sheet.cell(row=1, column=1).value: 171 | next_row = 1 # 如果第一行是空的,设置为1 172 | for col, value in enumerate(data, start=1): 173 | sheet.cell(row=next_row, column=col, value=value) 174 | try: 175 | workbook.save(file_path) 176 | logging.info(f"数据已成功写入到 {file_path}") 177 | except Exception as e: 178 | logging.info(f"保存文件时出错: {e}") 179 | self.last_processed_msg = last_msg 180 | logging.info(f"消息已保存至{self.file_name}") 181 | else: 182 | logging.info("消息不包含会议信息关键字,跳过处理") 183 | else: 184 | logging.info("没有新消息或消息已处理") 185 | 186 | # 示例调用-需要创建的文件名,联系人名称 187 | bot = WeChatBot('InfoData.xlsx', '测试群2') 188 | if bot.wx: 189 | bot.select_conversation() 190 | bot.process_messages() 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /examples/dev/收集群消息.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | @作者 :B站/抖音/微博/小红书/公众号,都叫:程序员晚枫,微信:CoderWanFeng 4 | @读者群 :http://www.python4office.cn/wechat-group/ 5 | @学习网站 :https://www.python-office.com 6 | @代码日期 :2023/8/9 23:05 7 | @本段代码的视频说明 : 8 | ''' 9 | import PyOfficeRobot as pr 10 | 11 | pr.chat.receive_message(who='程序员晚枫', txt='userMessage.txt', output_path='/') 12 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | python-office 2 | pandas==2.2.2 3 | poai==0.0.11 4 | porobot==0.0.3 5 | pyscreenshot==3.1 6 | PySide6==6.7.0 7 | PySide6==6.7.0 8 | PySide6_Addons==6.7.0 9 | PySide6_Essentials==6.7.0 10 | pywin32==306 11 | pywinauto==0.6.8 12 | Requests==2.32.2 13 | schedule==1.2.1 14 | setuptools==69.0.2 15 | uiautomation==2.0.18 16 | xlrd==1.2.0 17 | xlwt==1.3.0 18 | -------------------------------------------------------------------------------- /script/clean.sh: -------------------------------------------------------------------------------- 1 | 2 | ../venv/Scripts/activate 3 | pip freeze > requirements.txt 4 | pip uninstall -r requirements.txt -y 5 | # pip install --upgrade python-office -------------------------------------------------------------------------------- /script/upload.sh: -------------------------------------------------------------------------------- 1 | rm -rf ./dist/* ./build/* 2 | python setup.py sdist 3 | python setup.py bdist_wheel 4 | twine upload dist/* 5 | 6 | 7 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = PyOfficeRobot 3 | version = 0.1.25 4 | description = pip install PyOfficeRobot 5 | long_description = file: README.md 6 | long_description_content_type = text/markdown 7 | url = https://www.python-office.com/office/robot.html 8 | author = CoderWanFeng 9 | author_email = 1957875073@qq.com 10 | license = MIT 11 | license_file = LICENSE 12 | platforms = any 13 | 14 | project_urls = 15 | Bug Tracker = https://github.com/CoderWanFeng/PyOfficeRobot/issues 16 | Documentation = https://github.com/CoderWanFeng/PyOfficeRobot/blob/main/README.md 17 | Source Code = https://github.com/CoderWanFeng/PyOfficeRobot 18 | 19 | [options] 20 | packages = find: 21 | install_requires = 22 | uiautomation;platform_system=='Windows' 23 | pywin32;platform_system=='Windows' 24 | pywinauto;platform_system=='Windows' 25 | schedule 26 | pandas 27 | poai 28 | xlwt 29 | xlrd==1.2.0 30 | PySide6 31 | porobot 32 | loguru 33 | pofile 34 | 35 | python_requires = >=3.6 36 | include_package_data = True 37 | zip_safe = False 38 | 39 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | ############################################# 5 | # File Name: setup.py 6 | # 公众号/B站/小红书/抖音: 程序员晚枫 7 | # Mail: 1957875073@qq.com 8 | # Created Time: 2022-4-19 10:17:34 9 | # Description: https://mp.weixin.qq.com/s/zzD4pxNMFd0ZuWqXlVFdAg 10 | ############################################# 11 | 12 | from setuptools import setup 13 | 14 | setup() -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # pip3.10 install PyOfficeRobot -i https://pypi.python.org/simple -U 2 | 3 | # 1、pip freeze > allpackages.txt 4 | # 2、pip uninstall -r allpackages.txt -y 5 | # 3、pip install --upgrade python-office -------------------------------------------------------------------------------- /tests/test_code/test_file.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from PyOfficeRobot.api import file, group 4 | from PyOfficeRobot.api.chat import * 5 | from PyOfficeRobot.api.file import * 6 | from PyOfficeRobot.api.group import * 7 | 8 | keywords = { 9 | '你好': "在干嘛?" 10 | } 11 | 12 | 13 | class TestFile(unittest.TestCase): 14 | def test_send_file(self): 15 | send_file(who='文件传输助手', file=r'../test_files/0816.jpg') 16 | 17 | def test_chat_by_keyword(self): 18 | chat_by_keywords(who='程序员晚枫', keywords=keywords) 19 | 20 | def test_receive_message(self): 21 | receive_message(who='程序员晚枫') 22 | 23 | def test_sm_by_time(self): 24 | send_message_by_time(who='程序员晚枫', message='你好', time='17:38') 25 | 26 | def test_send_message(self): 27 | send_message(who='晚枫', message='你好') 28 | 29 | def test_chat_by_gpt(self): 30 | chat_by_gpt(who='程序员晚枫') 31 | 32 | def test_weixin_file(self): 33 | who = '程序员晚枫' 34 | file_path = r'./dfasd.py' 35 | # file_path = r'D:\workplace\code\github\PyOfficeRobot\tests\chat.py' 36 | # PyOfficeRobot.file.send_file(who, file) 37 | file.send_file(who, file_path) 38 | # file.send_file(who='程序员晚枫', file=r'D:\workplace\code\github\PyOfficeRobot\dev\contributor\gen\自动加好友\Excel_File\【企查查】查企业-高级搜索“涂料”(202302030683).xls') 39 | 40 | def test_group_send(self): 41 | group.send() 42 | 43 | def test_chat_ali(self): 44 | chat_ali(who='程序员晚枫', key=os.getenv('TY_KEY')) 45 | 46 | def test_chat_ds(self): 47 | chat_by_deepseek(who='晚枫', api_key="sk-pRdhASKn0wm5i7DjkdDfj5ENbRcpsqGrtV7hdFZZ6laV5aMk") 48 | 49 | def test_chat_zhipu(self): 50 | chat_by_zhipu(who='绋嬪簭鍛樻櫄鏋?', key='') 51 | 52 | def test_group_chat_by_keywords(self): 53 | who = '测试群' 54 | keywords = { 55 | "报名": "你好,这是报名链接:www.python-office.com", 56 | "学习": "你好,这是学习链接:www.python-office.com", 57 | "课程": "你好,这是课程链接:www.python-office.com" 58 | } 59 | match_type = 'contains' # 关键字匹配类型 包含:contains 精确:exact 60 | chat_by_keywords(who=who, keywords=keywords, match_type=match_type) 61 | 62 | def test_collect_msg(self): 63 | who = '✨python-office开源小组' 64 | output_excel_path = 'userMessage.xlsx' 65 | output_path = './' 66 | names = ['程序员晚枫'] 67 | scroll_num = 6 68 | collect_msg(who=who, output_excel_path=output_excel_path, output_path=output_path, names=names, scroll_num=scroll_num) 69 | -------------------------------------------------------------------------------- /tests/test_files/0816.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderWanFeng/PyOfficeRobot/c92ba08f35efe41613ef052a0f043b35d77f8b5c/tests/test_files/0816.jpg --------------------------------------------------------------------------------