需求1:家里有一个小店,需要订烟,中秋节前夕订烟日期调整,业务经理提前3天通知了,但是忘记了,然后就错过了,所以我要获取订烟时间,然后通过腾讯的sms,发送到几部手机上
需求2:某丝丽企业微信群需要每天活跃,每天大量的 “111” 刷屏,业务经理虽然在群里通知了,但是很快就会被刷屏,我想这个也是漏掉订烟的间接原因吧,,所以每天输入1 在群里进行活跃
实现:我先后尝试了抓包等等的方式,奈何js技术有限,未看懂参数的加密机制,所以还是进行最直接的UI操作,选型 pywinauto
过程中遇到的问题与总结:
1、winSpy (backend='win32') 定位不到工作台web的元素,使用 inspect 阔以
2、企业微信的工作台里面的内容,尝试了一下 winSpy 与 inspect 都定位不到菜单入口,所以使用坐标的方式点击
3、下面的代码中有调用某云平台的sms sdk
期望:希望大家有好的建议可以反馈一下,谢谢拉
# -*- coding: utf-8 -*-
# @Time : 2022/9/14 11:10
# @Author : CY
# @FileName: company_wx.py
import datetime
from pywinauto import mouse
import keyboard
from pywinauto.application import *
import time
from psutil import process_iter
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.sms.v20210111 import sms_client, models
MSG_DATA = {
'app_id': '',
'sing_id': '',
'tem_id': '',
'msg_id': '',
'msg_key': ''
}
def send_msg(phone, date_value, time_value):
"""发送短信"""
try:
china_num = '+86'
phone = f'{china_num}{phone}'
msg_data = MSG_DATA
cred = credential.Credential(secret_id=msg_data.get('msg_id'), secret_key=msg_data.get('msg_key'))
client = sms_client.SmsClient(cred, "ap-guangzhou")
req = models.SendSmsRequest()
# 短信应用ID: 短信SdkAppId在 [短信控制台] 应用管理--应用列表 https://console.cloud.tencent.com/smsv2/app-manage
req.SmsSdkAppId = msg_data.get('app_id')
# 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名,签名信息可登录 [短信控制台] 查看
req.SignName = '我的是小程序的名字'
req.PhoneNumberSet = [phone]
# 模板 ID: 必须填写已审核通过的模板 ID。模板ID可登录 [短信控制台] 查看
req.TemplateId = msg_data.get('tem_id')
# 模板参数: 若无模板参数,则设置为空
req.TemplateParamSet = [date_value, time_value]
resp = client.SendSms(req)
# 输出json格式的字符串回包
# print(resp.to_json_string(indent=2))
return True
except TencentCloudSDKException as err:
print(err)
return False
def save_data(value, file_name, sx='pickle', read=False):
"""保存路径"""
use_path = os.sep.join([get_cur_path(), f'{file_name}.{sx}'])
if sx in ['pickle']:
with open(use_path, 'wb') as file: pickle.dump(value, file)
else: raise Exception('暂不支持的后缀名')
if read: print("{}\n写入完成".format(value))
def get_save_data(file_name, sx='pickle'):
"""
:param file_name: 文件名字
:param sx: 后缀 json excel 类型
:return:
"""
use_path = os.sep.join([get_cur_path(), f'{file_name}.{sx}'])
if not os.path.exists(use_path):
save_data(value={}, file_name=file_name, sx=sx)
return None
if sx == 'pickle':
with open(use_path, 'rb') as file_pickle:
data_info = pickle.load(file_pickle)
return data_info
else:
print('类型不支持')
def get_now(day=0, hours=0, minutes=0, time_type='%Y-%m-%d %H:%M:%S'):
"""
当前日期 时间
'%Y-%m-%d'
'%Y-%m-%d %H:%M:%S.%f'
"""
now_time = (datetime.datetime.now() + datetime.timedelta(days=+day, hours=+hours, minutes=+minutes)).strftime(time_type)
return now_time
def get_cur_path():
"""获取当前path
"""
cur_path = os.path.dirname(os.path.realpath(__file__))
return cur_path
class WXWork(object):
def __init__(self):
exe_path = r"C:\Program Files (x86)\WXWork\WXWork.exe"
self.app = Application(backend="uia").start(exe_path)
self.pid = self.get_pid
print(self.pid)
if not self.pid:
print("请登录企业微信!")
return
# 准备连接软件
for i, item in enumerate(self.pid):
print('正在连接软件...')
try:
self.app.connect(path=exe_path, process=item)
self.weixin_window = self.app.window(class_name="WeWorkWindow")
self.weixin_window.set_focus()
except Exception as e:
print('Error>>', e)
continue
else:
print('连接软件成功!')
break
self.weixin_window.draw_outline(colour='red') # 在窗口周围画一个轮廓。
self.main_position = self.weixin_window.rectangle()
@property
def get_pid(self):
pid = process_iter()
pid_list = []
for pid_temp in pid:
pid_dic = pid_temp.as_dict(attrs=['pid', 'name'])
if pid_dic['name'] == 'WXWork.exe':
pid_num = pid_dic['pid']
pid_list.append(pid_num)
if len(pid_list):
return pid_list
else:
return False
def print_main_elements_tree(self):
"""打印元素 这个元素是树状图,很实用
depth 打印等级 不填写 全部打印出来
filename 给一个文件路径,树状图信息 保存到你给的文件中去
"""
self.weixin_window.print_control_identifiers(depth=None, filename=None)
@classmethod
def get_element_position(cls, element):
"""
获取位置
return (left:66, top:61, right:1032, bottom:711)
"""
return element.rectangle()
def click_cd_news(self):
"""点击消息"""
left_num = 28 # 这个值 是使用qq截图测量的左右边距
top_num = 96
self.click_cd_by_percent(left_num=left_num, top_num=top_num)
def click_news_cd_first(self):
"""点击消息中的第一个"""
left_num = 168
top_num = 96
self.click_cd_by_percent(left_num=left_num, top_num=top_num)
def click_cd_workbench(self):
"""点击菜单中的工作台,因为获取不到菜单元素,所以使用相对坐标来解决点击问题"""
left_num = 28
top_num = 308
self.click_cd_by_percent(left_num=left_num, top_num=top_num)
def click_cd_by_percent(self, left_num, top_num, timeout=0.5, **kwargs):
"""根据元素位置点击"""
if 'position' in kwargs.keys(): main_position = kwargs.get('position')
else: main_position = self.weixin_window.rectangle()
min_high = main_position.top
min_wide = main_position.left
left = int(min_wide+left_num)
top = int(min_high+top_num)
mouse.click(button='left', coords=(left, top))
time.sleep(timeout)
def click_table_cd(self):
"""点击工作台中的菜单"""
left_num = 185
top_num = 308
self.click_cd_by_percent(left_num=left_num, top_num=top_num, timeout=5)
def click_table_windows_close(self):
left_num = 400
top_num = 24
self.click_cd_by_percent(left_num=left_num, top_num=top_num)
def click_news_input(self):
left_num = 512
top_num = 580
self.click_cd_by_percent(left_num=left_num, top_num=top_num)
def get_order_date(self):
"""获取时间"""
if self.assert_dialog_exists(): return None
else:
return self.weixin_window.child_window(title="企业微信-工作台", class_name="WXworkWindow - 企业微信-工作台").child_window(
best_match='订货时间Static').parent().children()[4].window_text()
def assert_dialog_exists(self):
return self.weixin_window.child_window(best_match='TitleBar').exists()
@classmethod
def send_operation_keyboard_text(cls, input_str):
"""键盘输入内容"""
keyboard.write(input_str)
time.sleep(0.5)
@classmethod
def send_operation_keyboard_exe(cls, input_str):
"""键盘输入执行命令"""
keyboard.send(input_str)
time.sleep(0.5)
def send_news_everyday_active(self):
"""微信群每天活跃发送信息1"""
self.click_cd_news()
self.click_news_cd_first()
self.click_news_input()
self.send_operation_keyboard_text('11')
self.send_operation_keyboard_exe('enter')
def get_order_time():
file_name = 'data'
cwx = WXWork()
cwx.send_news_everyday_active()
# cwx.print_main_elements_tree()
cwx.click_table_windows_close()
cwx.click_cd_workbench()
print(cwx.weixin_window.window_text())
cwx.click_table_cd()
order_data = cwx.get_order_date()
if order_data:
print(order_data)
format_text_list = order_data.replace('月', '-').split('~')
time_text_list = []
date_text = format_text_list[0].split('日')[0]
for time_data in format_text_list:
time_text_list.append(time_data.split('日')[-1])
time_text = '~'.join(time_text_list)
data_dict = {
'assert_data': date_text,
'date': date_text,
'time': time_text
}
save_data(data_dict, file_name=file_name)
cwx.click_table_windows_close()
cwx.click_cd_news()
cwx.send_operation_keyboard_exe('alt+tab')
get_now(time_type='%m-%d')
get_order_data = get_save_data(file_name)
if get_now(time_type='%m-%d') == get_order_data.get('assert_data'):
print('发送短信')
send_phone_list = ['手机号1', '手机号2']
for phone_num in send_phone_list:
send_msg(phone=phone_num, date_value=get_order_data.get('date'), time_value=get_order_data.get('time'))
else: print('不发送短信')
if __name__ == '__main__':
get_order_time()