├── .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 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
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 |
17 |
18 |
19 |
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 | [](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
--------------------------------------------------------------------------------