已经可以实现,大致包括如下过程:
1、用KeymouseGo录制按键,播放录制的按键输入零信任客户端用户名,密码,点击发送短信。
2、在手机上安装Android 短信转发器 SmsForwarder,定义转发规则,转发指定内容的验证码到一个邮箱,假设转发包含有【零信任】的短信到一个邮箱,标题设置为Smsforwarder
3、编写程序get_mail.py,获取指定邮箱中的邮件,找出标题是Smsforwarder的邮件,分析出正文中的验证码,取出验证码,复制到剪贴板,把收到的验证码写入一个KeymouseGo的键盘录制文件中,取代指定的验证码按键,注意转码为ASCII编码。删除邮箱中的验证码邮件。
4、调用KeymouseGo播放短信按键,完成登录。
具体的代码有空再整理上来。
2025-1-24
上面的第3和第4点,都可以用get_mail.py程序解决。
程序要求的前提条件是:转发的短信的邮件的标题是:Smsforwarder,程序用于过滤邮箱中的这种标题的邮件。以下程序可以用Visual Studio Code打开,修改程序最后的用户名和密码,也就是说:
在这里插入代码片
if __name__ == '__main__':
# 替换下面的用户名和密码为你的邮箱信息
my_username = '13312345678@189.cn'
my_password = 'Zv@1Zu$5r)8Qh#9I'
完整的程序如下:
import re
import imaplib
import email
from email.header import decode_header
from email.utils import parsedate_to_datetime
import pytz
from datetime import datetime # 导入 datetime 类
import pyperclip #将文本复制到剪贴板
# python -m site 查看python解释器的安装位置
# 家里安装环境老是不会安装到
# 安装后老是找不到,手工拷贝如下的2个目录到c:\Program Files\Python37\Lib\site-packages\
# c:\users\asus\appdata\local\packages\pythonsoftwarefoundation.python.3.12_qbz5n2kfra8p0\localcache\local-packages\python312\site-packages\pyperclip\
# c:\users\asus\appdata\local\packages\pythonsoftwarefoundation.python.3.12_qbz5n2kfra8p0\localcache\local-packages\python312\site-packages\pyperclip-1.9.0.dist-info\
# __________________________________________________________________________________________________________
#
# 本程序的功能:读取邮件,获取验证码,写入模拟按键序列文件。另外也复制到剪贴板,可直接Ctrl+V复制验证码使用
#___________________________________________________________________________________________________________
#region 定义一个函数来解析邮件中的日期,并与当前时间比较
def compare_dates(date_str):
# 解析邮件中的日期字符串为 datetime 对象
# 注意:邮件中的日期通常为 GMT 时间
email_date = email.utils.parsedate_to_datetime(date_str)
#email_date = email_date.replace(tzinfo=pytz.utc).astimezone(pytz.timezone('Asia/Shanghai')) #不用转换时区,原始就是 GMT+8
# 获取当前时间,并转换为相同的时区以便比较
current_time = datetime.now(pytz.timezone('Asia/Shanghai'))
# 计算两个时间之间的差异
delta = current_time - email_date
# 输出差异,以分钟为单位
minutes_difference = int(delta.total_seconds() / 60)
return minutes_difference
#endregion
#region 转换GMT时间格式为'yyyy-mm-dd HH:MM:SS'格式
def format_date(gmt_date):
formatted_date="0000-00-00 00:00:00"
# 解析邮件日期字符串为 datetime 对象
try:
dt = parsedate_to_datetime(gmt_date)
except Exception as e:
print(f"Error parsing date: {e}")
dt = None
# 转换为'yyyy-mm-dd HH:MM:SS'格式
if dt:
# 格式化为指定的格式 'yyyy-mm-dd HH:MM:SS'
formatted_date = dt.strftime('%Y-%m-%d %H:%M:%S')
else:
print("Could not parse the date.")
return formatted_date
#region 写入验证码到键盘操作文件
def write_sms_code(sms_code):
# 定义源文件路径和目标文件路径
source_file_path = r'd:\bat\keymouse\scripts\sms_code.template'
target_file_path = r'd:\bat\keymouse\scripts\sms_code.txt'
# 验证码需要转化为ASCII码
str_ascii= ["ASCII1","ASCII2","ASCII3","ASCII4","ASCII5"]
try:
# 打开源文件
with open(source_file_path, 'r', encoding='utf-8') as file:
content = file.read()
new_content = content
# 替换内容
for i in range(5):
new_content = new_content.replace(str_ascii[i], str(ord(sms_code[i])) ) # 使用ord()函数来获取一个字符的ASCII码值,数字键0-9对应的ASCII码值48-57
print(f"{str_ascii[i]} ----> {sms_code[i]}" )
# 写入新文件
with open(target_file_path, 'w', encoding='utf-8') as file:
file.write(new_content)
print("文件处理完成!")
except FileNotFoundError:
print("源文件未找到,请检查路径是否正确。")
except Exception as e:
print(f"处理文件时发生错误:{e}")
#endregion
#region 获取电子邮件
#——————————————————————————————————————————————————————————————————————————————
# 获取电子邮件
#——————————————————————————————————————————————————————————————————————————————
def get_mail(username, password, imap_server='imap.189.cn', folder='inbox'):
minutes_diff=999
latest_code="0"
is_zero_trust=False
# 连接到IMAP服务器
mail = imaplib.IMAP4_SSL(imap_server)
mail.login(username, password)
# 选择邮件夹,默认为收件箱
mail.select(folder)
# 搜索所有邮件
_, search_data = mail.search(None, 'ALL')
mail_ids = search_data[0].split()
# 获取最新的5封邮件
mail_ids = mail_ids[-5:]
# 遍历邮件ID,打印邮件信息
for num in mail_ids:
_, data = mail.fetch(num, '(RFC822)')
raw_email = data[0][1]
msg = email.message_from_bytes(raw_email)
# 解码邮件主题
subject, encoding = decode_header(msg["Subject"])[0]
if isinstance(subject, bytes):
# 如果主题是字节类型,则解码为字符串
subject = subject.decode(encoding)
# 解析并解码发件人信息
decoded_from = decode_header(msg.get("From"))
from_parts = []
for part in decoded_from:
if isinstance(part[0], bytes):
# 解码每一部分为字符串
from_parts.append(part[0].decode(part[1] or 'utf-8'))
else:
from_parts.append(part[0])
from_ = ''.join(from_parts)
# 获取邮件收到时间
date = msg.get('Date') # 类似这样的格式:Wed, 15 Jan 2025 15:28:52 +0800 (GMT+08:00)
formatted_date=format_date(date) #转化为容易阅读的格式 2025-01-15 15:28:52
# 获取邮件正文
body = None
if msg.is_multipart():
for part in msg.walk():
content_type = part.get_content_type()
if content_type == 'text/plain' or content_type == 'text/html':
body = part.get_payload(decode=True).decode(part.get_content_charset() or 'utf-8')
break
else:
body = msg.get_payload(decode=True).decode(msg.get_content_charset() or 'utf-8')
# 打印邮件接收时间与当前时间相差多少分钟
minutes_diff = compare_dates(date)
if ("SMS" in from_ and minutes_diff<=60 ):
print(f"Subject: {subject}")
print(f"From: {from_}")
print(f"Received Date: {formatted_date}")
print(f"Time difference from now: {minutes_diff} minutes")
print(f"Body:\n{body}")
# 给定的字符串
s = body
# 使用正则表达式匹配所有数字序列
verification_code = re.findall(r'\d+', s[s.find("<br>") + len("<br>"):s.find("随机短信密码")]) #查找<br>xxxxx随机短信密码之间的数字
#正则表达式解释 \d+ 匹配一个或多个数字字符。 re.findall(r'\d+', ...) 查找给定范围内的所有数字序列。
is_zero_trust = True
if ( "【天翼账号】" in s ):
verification_code = re.findall(r'\d+', s[s.find("【天翼账号】您的验证码为:") + len("【天翼账号】您的验证码为:"):s.find("尊敬的客户")]) #查找<br>xxxxx。尊敬的客户之间的数字
is_zero_trust = False
if ( "【云电脑】" in s or "【云认证】" in s or "【通义】" or s in "【天翼云】" or s in "【深度求索】" ) :
verification_code = re.findall(r'\d+', s[s.find("验证码") + len("验证码"):s.find("有效")]) #验证码:xxxxxx,5分钟内有效之间的数字
is_zero_trust = False
if ( "随机短信验证码" in s ) :
verification_code = re.findall(r'\d+', s[s.find("随机短信验证码")-5:s.find("随机短信验证码")+6]) #21692随机短信验证码,尊敬的鲁智深,欢迎登录
if "零信任" in s:
is_zero_trust = True
else:
is_zero_trust = False
print(f"number:{verification_code[0]}")
latest_code=verification_code[0]
print("_" * 100) # 画一条线
# 注销
mail.logout()
if minutes_diff<=60:
if latest_code!='0':
print(f"{latest_code}")
pyperclip.copy(latest_code)
print("验证码已经复制到剪裁板。")
else:
print("最近60分钟没有收到短信验证码。")
is_zero_trust = False
# 写入验证码到键盘文件
if ( is_zero_trust ): #是零信任的验证码才写入模拟按键文件
write_sms_code(latest_code)
print(f"写入键盘文件中的验证码{latest_code}")
#endregion 获取电子邮件
#region 删除电子邮件
#——————————————————————————————————————————————————————————————————————————————
# 删除电子邮件
#——————————————————————————————————————————————————————————————————————————————
def delete_mails_by_subject(username, password, subject_to_delete, imap_server='imap.189.cn', folder='inbox'):
# 连接到IMAP服务器
mail = imaplib.IMAP4_SSL(imap_server)
mail.login(username, password)
try:
# 选择邮件夹,默认为收件箱
mail.select(folder)
# 搜索包含指定主题的邮件
status, messages = mail.search(None, 'ALL')
if status != 'OK':
print("未找到相关邮件")
return
# 获取匹配的邮件ID列表
mail_ids = messages[0].split()
if not mail_ids:
print("找不到指定主题的邮件")
return
i=0
# 遍历邮件ID,打印邮件信息
for num in mail_ids:
_, data = mail.fetch(num, '(RFC822)') # 返回的结果是一个元组,其中第一个元素通常是状态信息(这里用下划线_忽略,因为我们不关心这个值),第二个元素data是实际的邮件数据。
raw_email = data[0][1]
msg = email.message_from_bytes(raw_email)
# 解码邮件主题
subject, encoding = decode_header(msg["Subject"])[0]
if isinstance(subject, bytes):
# 如果主题是字节类型,则解码为字符串
subject = subject.decode(encoding)
# 解析并解码发件人信息
decoded_from = decode_header(msg.get("From"))
from_parts = []
for part in decoded_from:
if isinstance(part[0], bytes):
# 解码每一部分为字符串
from_parts.append(part[0].decode(part[1] or 'utf-8'))
else:
from_parts.append(part[0])
from_ = ''.join(from_parts)
# 获取邮件收到时间
date = msg.get('Date') # 类似这样的格式:Wed, 15 Jan 2025 15:28:52 +0800 (GMT+08:00)
formatted_date = format_date(date) # 转化为容易阅读的格式 2025-01-15 15:28:52
# 打印邮件接收时间与当前时间相差多少分钟
minutes_diff = compare_dates(date)
# 测试需要特别小心,避免错误删除邮件,删除10分钟前指定主题的邮件
if (minutes_diff>10 ) and (subject_to_delete in subject):
i = i + 1
print(i)
print(f"Subject: {subject}")
# print(f"From: {from_}")
print(f"Received Date: {formatted_date}")
# print(f"Received Date: {date}")
# print("删除此邮件")
# print("\n")
# 标记邮件为删除
mail.store(num, '+FLAGS', '\\Deleted')
#最多删除10封邮件,怕错误删除太多了
if (i>10):
break
#for循环结束
if i>0:
#永久删除被标记的邮件
mail.expunge()
print(f"主题为'{subject_to_delete}'的邮件已删除,删除的邮件数量是{i}。")
else:
print(f"没有删除任何主题为'{subject_to_delete}'的邮件。")
finally:
# 注销并关闭连接
mail.logout()
#endregion 删除电子邮件
# —————————————————————————————— 主程序开始 ——————————————————————————————————
if __name__ == '__main__':
# 替换下面的用户名和密码为你的邮箱信息
my_username = '13312345678@189.cn'
my_password = 'Zv@1Zu$5r)8Qh#9I'
# 获取电子邮件
get_mail(my_username, my_password)
# 删除电子邮件
# delete_mails_by_subject(my_username, my_password, 'Smsforwarder')
执行程序是:python get_mail.py
其实在零信任拨号客户端登录时,是被KeymouseGo使用,读取键盘按键文件中新接收到的验证码,在输入验证码的界面中输入验证码。验证码一般是每次都不一样的,是动态变化的,通用的鼠标键盘按键序列记录文件是固定的,只需替换掉里面的验证码就可以了。
如果不是全程自动化按键的话,那么可以拿到这个验证码,粘贴使用,不用看手机,也不用录入,直接粘贴使用,因为这个程序已经把验证码复制到windows的剪贴板中去了。为了好看一些,用C#做个windows桌面程序去调用这个python程序,拿到的验证码可直接Ctrl+V使用。
程序在189邮箱测试使用了一段时间,删除电子邮件是只删除超过10分钟的验证码邮件,删除邮件的代码,如果要修改,请特别注意删除条件的设置,代码中是直接清空要删除的邮件,如不需要可去掉。在测试时不小心删除很多邮件,幸亏已经都存入本地的foxmail邮箱中了。再次说一下,删除邮件的代码请特别留意删除条件,不错误删除了。这里的主程序入口,先注解掉删除邮件的功能。
如有的地方不明白的话,可以直接复制代码到通义千问,或者深度求索中去,请他给出解释。删除邮件前本来是不用遍历去查找特定主题的邮件的,可以用mail.search去处理的,不知道为何不起作用,只好遍历去查找特定主题了。
# status, messages = mail.search(None, f'SUBJECT "{encoded_subject}"') #不起作用,很奇怪
status, messages = mail.search(None, 'before "1-Jan-2025"' ) #能够起作用
2025-1-26
6万+

被折叠的 条评论
为什么被折叠?



