py实现win自动化自动登陆qq

系列文章目录

py实现win自动化自动登陆qq



前言

之前都是网页自动化感觉太容易了,就来尝尝win自动化,就先写了一个qq登陆的,这个是拿到className 然后进行点击等。


一、上代码?

示例:

import psutil
import time
import os
from pywinauto import Application
from pywinauto.findwindows import find_window
from pywinauto.timings import WaitUntil
from pywinauto import mouse


class QQAutomator:
    def __init__(self):
        self.app = None
        self.main_window = None
        self.qq_path = r'D:\itveteranISTool\itveteranExe\qq\QQ.exe'

    def kill_qq_process(self):
        """终止QQ相关进程"""
        for proc in psutil.process_iter(['pid', 'name']):
            if proc.info['name'] and proc.info['name'].lower() in ('qq.exe', 'qqschat.exe'):
                try:
                    proc.kill()
                    time.sleep(1)
                    print(f"已终止进程:{proc.info['name']}")
                except Exception as e:
                    print(f"终止失败:{e}")

    def find_qq_window(self, timeout=30):
        """定位QQ窗口并打印详细信息"""
        start_time = time.time()
        while time.time() - start_time < timeout:
            try:
                window = self.app.window(
                    class_name="Chrome_WidgetWin_1",
                    control_type="Pane",
                    title_re=".*QQ.*"
                )
                if window.exists():
                    self._print_window_details(window)
                    return window
            except Exception as e:
                print(f"窗口定位尝试失败:{str(e)}")
                time.sleep(1)
        return None

    def _print_window_details(self, window):
        """打印窗口详细信息"""
        print("=" * 60)
        print(f"窗口句柄: {window.handle}")
        print(f"窗口标题: {window.window_text()}")
        print(f"类名: {window.class_name()}")
        print(f"坐标范围: {window.rectangle()}")
        print("控件层次结构:")
        self._print_control_tree(window, level=0)
        print("=" * 60)

    def _print_control_tree(self, control, level=0, max_depth=3):
        """递归打印控件树结构"""
        if level > max_depth:
            return

        prefix = "  " * level + "└─ "
        try:
            info = f"{prefix}[{control.friendly_class_name()}] {control.element_info.name}"
            print(info)

            for child in control.children():
                self._print_control_tree(child, level + 1, max_depth)
        except:
            pass

    def click_button(self, button_title, retry=3):
        """优化后的点击方法"""
        for attempt in range(retry):
            try:
                # 更精准的定位方式
                btn = self.main_window.child_window(
                    title=button_title,
                    control_type="Button",
                    found_index=0
                ).wait('ready', timeout=5)

                if btn.is_visible() and btn.is_enabled():
                    print(f"点击按钮 [{button_title}] (第{attempt+1}次尝试)")
                    btn.click_input()
                    return True

                # 新增调试信息
                print(f"按钮状态:visible={btn.is_visible()}, enabled={btn.is_enabled()}")

            except Exception as e:
                print(f"按钮定位失败: {str(e)}")
            time.sleep(2)
        return False

    def run(self):
        """修复后的主流程"""
        self.kill_qq_process()

        if not os.path.exists(self.qq_path):
            print("路径无效!")
            return

        try:
            # 增加启动等待
            self.app = Application(backend='uia').start(self.qq_path)
            time.sleep(1)  # 等待主进程初始化

            # 增强窗口定位
            self.main_window = self.find_qq_window(timeout=40)
            if not self.main_window:
                print("窗口定位失败,尝试备用方案...")
                qq_procs = [p for p in psutil.process_iter() if 'qq' in p.name().lower()]
                if qq_procs:
                    hwnd = find_window(process=qq_procs[0].pid)
                    self.main_window = self.app.window(handle=hwnd)

            if not self.main_window:
                print("❌ 无法定位窗口,退出程序")
                return

            # 打印调试信息
            print("="*40)
            self.main_window.print_control_identifiers()
            print("="*40)

            # 保存控件树
            self.main_window.print_control_identifiers(filename='control_tree.txt')

            # 执行点击操作
            # if self.click_button("添加账号"):
            #     print("已触发添加账号操作")
            #     time.sleep(3)  # 等待弹窗

            if self.click_button("登录"):
                print("登录请求已发送")
                self._verify_login()

        except Exception as e:
            print(f"主流程异常: {str(e)}")
            import traceback
            traceback.print_exc()

    def _verify_login(self):
        """修复后的登录验证"""
        try:
            print("正在验证登录状态...")
            WaitUntil(30, 2, lambda: any(
                p.info['name'] and p.info['name'].lower() in ('qq.exe', 'qqlite.exe')
                for p in psutil.process_iter(['name'])
            ))
            print("✅ 检测到QQ主进程,登录成功!")

            # 附加验证:检测主窗口变化
            main_window = self.app.window(class_name="Chrome_WidgetWin_0")
            if main_window.exists():
                print("✅ 检测到QQ主界面窗口")

        except TimeoutError:
            print("❌ 登录验证超时,可能原因:")
            print("1. 账号密码错误")
            print("2. 需要处理验证码")
            print("3. 网络连接异常")
            current_procs = [p.name() for p in psutil.process_iter()]
            print(f"当前运行进程:{current_procs}")


if __name__ == "__main__":
    automator = QQAutomator()
    automator.run()


总结

携知云~ 携手创造知识~ 科技是第一生产力,卷起来

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杰哥力挽狂澜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值