2026-04-02 14:54:45 +08:00
|
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
"""
|
|
|
|
|
|
窗口钓鱼自动化脚本
|
|
|
|
|
|
功能:识别指定窗口,循环发送钓鱼和收杆消息,时间间隔相等
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
import time
|
|
|
|
|
|
import logging
|
|
|
|
|
|
import sys
|
|
|
|
|
|
from typing import Optional
|
|
|
|
|
|
|
|
|
|
|
|
# 尝试导入自动化库,如果缺失则提示安装
|
|
|
|
|
|
try:
|
|
|
|
|
|
import pyautogui
|
|
|
|
|
|
import pygetwindow as gw
|
|
|
|
|
|
except ImportError as e:
|
|
|
|
|
|
print(f"缺少依赖库: {e}")
|
|
|
|
|
|
print("请使用 pip install pyautogui pygetwindow 安装")
|
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
# 配置日志
|
|
|
|
|
|
logging.basicConfig(
|
|
|
|
|
|
level=logging.INFO,
|
|
|
|
|
|
format='%(asctime)s - %(levelname)s - %(message)s',
|
|
|
|
|
|
handlers=[
|
|
|
|
|
|
logging.FileHandler('fishing_bot.log', encoding='utf-8'),
|
|
|
|
|
|
logging.StreamHandler()
|
|
|
|
|
|
]
|
|
|
|
|
|
)
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
class FishingBot:
|
|
|
|
|
|
def __init__(self, window_title: str, interval: float = 5.0):
|
|
|
|
|
|
"""
|
|
|
|
|
|
初始化钓鱼机器人
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
window_title: 窗口标题(支持部分匹配)
|
|
|
|
|
|
interval: 钓鱼和收杆之间的时间间隔(秒)
|
|
|
|
|
|
"""
|
|
|
|
|
|
self.window_title = window_title
|
|
|
|
|
|
self.interval = interval
|
|
|
|
|
|
self.running = False
|
|
|
|
|
|
|
|
|
|
|
|
def find_window(self) -> Optional[gw.Window]:
|
|
|
|
|
|
"""
|
|
|
|
|
|
查找包含指定标题的窗口
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
找到的窗口对象,如果未找到则返回None
|
|
|
|
|
|
"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
windows = gw.getWindowsWithTitle(self.window_title)
|
|
|
|
|
|
if windows:
|
|
|
|
|
|
logger.info(f"找到窗口: {windows[0].title}")
|
|
|
|
|
|
return windows[0]
|
|
|
|
|
|
else:
|
|
|
|
|
|
logger.warning(f"未找到包含标题 '{self.window_title}' 的窗口")
|
|
|
|
|
|
return None
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"查找窗口时出错: {e}")
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
def activate_window(self, window: gw.Window) -> bool:
|
|
|
|
|
|
"""
|
|
|
|
|
|
激活指定窗口
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
window: 窗口对象
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
是否成功激活
|
|
|
|
|
|
"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
window.activate()
|
|
|
|
|
|
time.sleep(0.5) # 等待窗口激活
|
|
|
|
|
|
logger.info(f"已激活窗口: {window.title}")
|
|
|
|
|
|
return True
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"激活窗口时出错: {e}")
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def send_fishing_message(self) -> bool:
|
|
|
|
|
|
"""
|
|
|
|
|
|
发送钓鱼消息
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
是否成功发送
|
|
|
|
|
|
"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
# 这里根据实际需要修改发送方式
|
2026-04-02 15:12:06 +08:00
|
|
|
|
# 示例:输入"钓鱼"文字
|
|
|
|
|
|
pyautogui.typewrite('钓鱼')
|
|
|
|
|
|
time.sleep(0.1)
|
2026-04-02 14:54:45 +08:00
|
|
|
|
logger.info("发送钓鱼消息")
|
|
|
|
|
|
return True
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"发送钓鱼消息时出错: {e}")
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def send_reel_message(self) -> bool:
|
|
|
|
|
|
"""
|
|
|
|
|
|
发送收杆消息
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
是否成功发送
|
|
|
|
|
|
"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
# 这里根据实际需要修改发送方式
|
2026-04-02 15:12:06 +08:00
|
|
|
|
# 示例:输入"收杆"文字
|
|
|
|
|
|
pyautogui.typewrite('收杆')
|
|
|
|
|
|
time.sleep(0.1)
|
2026-04-02 14:54:45 +08:00
|
|
|
|
logger.info("发送收杆消息")
|
|
|
|
|
|
return True
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"发送收杆消息时出错: {e}")
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def run_cycle(self) -> bool:
|
|
|
|
|
|
"""
|
|
|
|
|
|
运行一个完整的钓鱼周期
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
周期是否成功完成
|
|
|
|
|
|
"""
|
|
|
|
|
|
# 查找窗口
|
|
|
|
|
|
window = self.find_window()
|
|
|
|
|
|
if not window:
|
|
|
|
|
|
logger.error("无法找到目标窗口,跳过本次周期")
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
# 激活窗口
|
|
|
|
|
|
if not self.activate_window(window):
|
|
|
|
|
|
logger.error("无法激活窗口,跳过本次周期")
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
# 发送钓鱼消息
|
|
|
|
|
|
if not self.send_fishing_message():
|
|
|
|
|
|
logger.error("发送钓鱼消息失败,跳过本次周期")
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
# 等待间隔
|
|
|
|
|
|
logger.info(f"等待 {self.interval} 秒...")
|
|
|
|
|
|
time.sleep(self.interval)
|
|
|
|
|
|
|
|
|
|
|
|
# 发送收杆消息
|
|
|
|
|
|
if not self.send_reel_message():
|
|
|
|
|
|
logger.error("发送收杆消息失败")
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
def start(self, cycles: int = 0):
|
|
|
|
|
|
"""
|
|
|
|
|
|
启动钓鱼机器人
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
cycles: 循环次数,0表示无限循环
|
|
|
|
|
|
"""
|
|
|
|
|
|
self.running = True
|
|
|
|
|
|
cycle_count = 0
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"开始钓鱼机器人,窗口标题: '{self.window_title}', 间隔: {self.interval}秒")
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
while self.running:
|
|
|
|
|
|
cycle_count += 1
|
|
|
|
|
|
logger.info(f"开始第 {cycle_count} 个周期")
|
|
|
|
|
|
|
|
|
|
|
|
success = self.run_cycle()
|
|
|
|
|
|
|
|
|
|
|
|
if success:
|
|
|
|
|
|
logger.info(f"第 {cycle_count} 个周期完成")
|
|
|
|
|
|
else:
|
|
|
|
|
|
logger.warning(f"第 {cycle_count} 个周期失败")
|
|
|
|
|
|
|
|
|
|
|
|
# 如果指定了循环次数且已达到,则停止
|
|
|
|
|
|
if cycles > 0 and cycle_count >= cycles:
|
|
|
|
|
|
logger.info(f"已完成指定的 {cycles} 个周期")
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
# 周期之间的短暂暂停,避免CPU占用过高
|
|
|
|
|
|
time.sleep(1)
|
|
|
|
|
|
|
|
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
|
|
logger.info("用户中断执行")
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"运行时发生未预期错误: {e}")
|
|
|
|
|
|
finally:
|
|
|
|
|
|
self.running = False
|
|
|
|
|
|
logger.info("钓鱼机器人已停止")
|
|
|
|
|
|
|
|
|
|
|
|
def stop(self):
|
|
|
|
|
|
"""停止钓鱼机器人"""
|
|
|
|
|
|
self.running = False
|
|
|
|
|
|
logger.info("停止信号已发送")
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
|
"""主函数"""
|
|
|
|
|
|
import argparse
|
|
|
|
|
|
|
2026-04-02 15:12:06 +08:00
|
|
|
|
parser = argparse.ArgumentParser(description='窗口钓鱼自动化脚本')
|
|
|
|
|
|
parser.add_argument('--window', '-w', default='一念成仙',
|
2026-04-02 14:54:45 +08:00
|
|
|
|
help='目标窗口标题(支持部分匹配)')
|
|
|
|
|
|
parser.add_argument('--interval', '-i', type=float, default=5.0,
|
|
|
|
|
|
help='钓鱼和收杆之间的时间间隔(秒)')
|
|
|
|
|
|
parser.add_argument('--cycles', '-c', type=int, default=0,
|
|
|
|
|
|
help='循环次数(0表示无限循环)')
|
|
|
|
|
|
parser.add_argument('--test', '-t', action='store_true',
|
|
|
|
|
|
help='测试模式:只运行一个周期并显示详细信息')
|
|
|
|
|
|
|
|
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
|
|
|
|
# 创建机器人实例
|
|
|
|
|
|
bot = FishingBot(args.window, args.interval)
|
|
|
|
|
|
|
|
|
|
|
|
if args.test:
|
|
|
|
|
|
logger.info("=== 测试模式 ===")
|
|
|
|
|
|
logger.info(f"窗口标题: {args.window}")
|
|
|
|
|
|
logger.info(f"间隔: {args.interval}秒")
|
|
|
|
|
|
|
|
|
|
|
|
# 测试窗口查找
|
|
|
|
|
|
window = bot.find_window()
|
|
|
|
|
|
if window:
|
|
|
|
|
|
logger.info(f"✓ 找到窗口: {window.title}")
|
|
|
|
|
|
else:
|
|
|
|
|
|
logger.error("✗ 未找到窗口")
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
# 测试激活
|
|
|
|
|
|
if bot.activate_window(window):
|
|
|
|
|
|
logger.info("✓ 窗口激活成功")
|
|
|
|
|
|
else:
|
|
|
|
|
|
logger.error("✗ 窗口激活失败")
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
logger.info("测试完成,请检查日志确认功能正常")
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
# 启动机器人
|
|
|
|
|
|
try:
|
|
|
|
|
|
bot.start(args.cycles)
|
|
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
|
|
logger.info("脚本被用户中断")
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"脚本执行出错: {e}")
|
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
sys.exit(main())
|