欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何基于Python開發(fā)一個微信自動化工具

 更新時間:2025年05月27日 14:35:43   作者:創(chuàng)客白澤  
在當(dāng)今數(shù)字化辦公場景中,自動化工具已成為提升工作效率的利器,本文將深入剖析一個基于Python的微信自動化工具開發(fā)全過程,有需要的小伙伴可以了解下

概述

在當(dāng)今數(shù)字化辦公場景中,自動化工具已成為提升工作效率的利器。本文將深入剖析一個基于Python的微信自動化工具開發(fā)全過程,該工具集成了即時消息發(fā)送、定時任務(wù)管理和微信進(jìn)程控制三大核心功能模塊。

技術(shù)棧亮點(diǎn):

PyQt5構(gòu)建美觀的GUI界面

uiautomation實現(xiàn)Windows UI自動化

psutil進(jìn)行進(jìn)程管理

多線程處理保持UI響應(yīng)

完整的異常處理機(jī)制

功能全景

1. 核心功能模塊

模塊名稱功能描述
即時消息發(fā)送支持文本+文件混合發(fā)送,智能識別聯(lián)系人
定時任務(wù)管理精確到秒的定時發(fā)送,支持循環(huán)任務(wù)配置
微信進(jìn)程控制啟動/激活/退出微信的一鍵操作

2. 特色功能

  • 智能窗口激活:自動置頂微信窗口并居中顯示
  • 文件絕對路徑處理:自動轉(zhuǎn)換相對路徑為絕對路徑
  • 任務(wù)持久化:運(yùn)行時任務(wù)列表維護(hù)
  • 健壯性設(shè)計:多重異常處理+操作狀態(tài)反饋

效果展示

1. 主界面概覽

2. 定時任務(wù)配置

3. 操作日志演示

實現(xiàn)步驟詳解

1. 環(huán)境準(zhǔn)備

pip install pyqt5 psutil uiautomation

2. 工程結(jié)構(gòu)設(shè)計

WeChatAutomation/
├── main.py            # 主程序入口
├── wechat.ico         # 程序圖標(biāo)
└── README.md          # 使用說明

3. 核心實現(xiàn)流程

GUI框架搭建:采用QMainWindow+TabWidget布局

工作線程封裝:WorkerThread類繼承QThread

定時任務(wù)調(diào)度:QTimer秒級輪詢檢查

UI自動化控制:uiautomation操作微信窗口

異常處理體系:三級錯誤捕獲機(jī)制

代碼深度解析

1. 多線程任務(wù)處理

class WorkerThread(QThread):
    finished = pyqtSignal(str, bool)  # 信號參數(shù):消息內(nèi)容, 是否成功
    
    def run(self):
        try:
            result = self.func(*self.args, **self.kwargs)
            self.finished.emit(result or "操作成功", True)
        except Exception as e:
            self.finished.emit(f"錯誤: {str(e)}", False)

設(shè)計要點(diǎn):

  • 采用信號槽機(jī)制實現(xiàn)線程間通信
  • 統(tǒng)一錯誤處理接口
  • 支持任意函數(shù)的多線程執(zhí)行

2. 微信窗口控制核心

def wechat_active():
    # 超時設(shè)置優(yōu)化
    uiautomation.uiautomation.TIME_OUT_SECOND = 2  
    if ifProcessRunning():
        try:
            # 快捷鍵激活方案
            desktop = uiautomation.PaneControl(Name='任務(wù)欄')
            desktop.SendKeys('{Ctrl}{Alt}w')
        except:
            # 異常后備方案
            os.system('taskkill /F /im "WeChat.exe"')
            wechat_start()
    else:
        wechat_start()
    
    # 恢復(fù)默認(rèn)超時
    uiautomation.uiautomation.TIME_OUT_SECOND = 20  
    wechatWindow = uiautomation.WindowControl(
        searchDepth=1, 
        className='WeChatMainWndForPC', 
        Name='微信'
    )

優(yōu)化策略:

動態(tài)調(diào)整UI查找超時時間

多方案組合提高成功率

異常后的自動恢復(fù)機(jī)制

3. 定時任務(wù)調(diào)度系統(tǒng)

def check_scheduled_tasks(self):
    now = datetime.now()
    for task in self.scheduled_tasks:
        if not task["completed"] and now >= task["send_time"]:
            success = self.send_message(
                recipient=task["recipient"],
                message=task["message"],
                file_path=task["file_path"]
            )
            
            if success and task["repeat"]:  # 重復(fù)任務(wù)處理
                task["send_time"] = now + timedelta(
                    minutes=task["interval"]
                )
                task["completed"] = False
            else:
                task["completed"] = True

算法特點(diǎn):

低精度定時檢查(1秒間隔)

支持單次/循環(huán)任務(wù)模式

非阻塞式任務(wù)執(zhí)行

源碼獲取

# -*- coding:utf-8 -*-
import sys
import psutil
import uiautomation
import os
import time
from datetime import datetime, timedelta
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
                            QTabWidget, QLabel, QLineEdit, QTextEdit, QPushButton, 
                            QFileDialog, QMessageBox, QStatusBar, QGroupBox,
                            QDateTimeEdit, QCheckBox, QSpinBox)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer
from PyQt5.QtGui import QIcon, QFont

class WorkerThread(QThread):
    finished = pyqtSignal(str, bool)  # message, success
    
    def __init__(self, func, *args, **kwargs):
        super().__init__()
        self.func = func
        self.args = args
        self.kwargs = kwargs
    
    def run(self):
        try:
            result = self.func(*self.args, **self.kwargs)
            self.finished.emit(result or "操作成功", True)
        except Exception as e:
            self.finished.emit(f"錯誤: {str(e)}", False)

class WeChatAutomationApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("微信自動化發(fā)送工具---BY 白澤")
        self.setGeometry(100, 100, 787, 639)
        self.setWindowIcon(QIcon("wechat.ico"))  # 替換為你的圖標(biāo)文件
        
        # 定時任務(wù)列表
        self.scheduled_tasks = []
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.check_scheduled_tasks)
        self.timer.start(1000)  # 每秒檢查一次
        
        # 設(shè)置全局字體
        font = QFont("Microsoft YaHei", 10)
        QApplication.setFont(font)
        
        # 主控件
        self.main_widget = QWidget()
        self.setCentralWidget(self.main_widget)
        
        # 主布局
        self.main_layout = QVBoxLayout(self.main_widget)
        self.main_layout.setContentsMargins(15, 15, 15, 15)
        self.main_layout.setSpacing(15)
        
        # 創(chuàng)建標(biāo)簽頁
        self.tabs = QTabWidget()
        self.main_layout.addWidget(self.tabs)
        
        # 創(chuàng)建各個標(biāo)簽頁
        self.create_send_tab()
        self.create_schedule_tab()
        self.create_control_tab()
        
        # 狀態(tài)欄
        self.status_bar = QStatusBar()
        self.setStatusBar(self.status_bar)
        self.status_bar.showMessage("?? 就緒")
        
        # 樣式設(shè)置
        self.set_style()
    
    def set_style(self):
        self.setStyleSheet("""
            QMainWindow {
                background-color: #f5f5f5;
            }
            QTabWidget::pane {
                border: 1px solid #d3d3d3;
                border-radius: 5px;
                padding: 5px;
                background: white;
            }
            QTabBar::tab {
                padding: 8px 15px;
                border: 1px solid #d3d3d3;
                border-bottom: none;
                border-top-left-radius: 5px;
                border-top-right-radius: 5px;
                background: #e9e9e9;
                margin-right: 2px;
            }
            QTabBar::tab:selected {
                background: white;
                border-bottom: 1px solid white;
                margin-bottom: -1px;
            }
            QPushButton {
                background-color: #4CAF50;
                color: white;
                border: none;
                padding: 8px 15px;
                border-radius: 4px;
                min-width: 80px;
            }
            QPushButton:hover {
                background-color: #45a049;
            }
            QPushButton:pressed {
                background-color: #3d8b40;
            }
            QPushButton:disabled {
                background-color: #cccccc;
            }
            QLineEdit, QTextEdit {
                border: 1px solid #d3d3d3;
                border-radius: 4px;
                padding: 5px;
            }
            QLabel {
                color: #333333;
            }
            QStatusBar {
                background-color: #e9e9e9;
                color: #333333;
            }
            QGroupBox {
                border: 1px solid #d3d3d3;
                border-radius: 5px;
                margin-top: 10px;
                padding-top: 15px;
            }
            QGroupBox::title {
                subcontrol-origin: margin;
                left: 10px;
                padding: 0 3px;
            }
            QDateTimeEdit {
                padding: 5px;
            }
        """)
    
    def create_send_tab(self):
        """創(chuàng)建發(fā)送消息標(biāo)簽頁"""
        self.send_tab = QWidget()
        self.tabs.addTab(self.send_tab, "?? 即時發(fā)送")
        
        layout = QVBoxLayout(self.send_tab)
        layout.setSpacing(15)
        
        # 收件人
        recipient_layout = QHBoxLayout()
        recipient_layout.addWidget(QLabel("?? 收件人:"))
        self.recipient_input = QLineEdit()
        self.recipient_input.setPlaceholderText("輸入微信用戶名或備注名")
        recipient_layout.addWidget(self.recipient_input)
        layout.addLayout(recipient_layout)
        
        # 消息內(nèi)容
        layout.addWidget(QLabel("?? 消息內(nèi)容:"))
        self.message_input = QTextEdit()
        self.message_input.setPlaceholderText("輸入要發(fā)送的消息...")
        layout.addWidget(self.message_input)
        
        # 文件附件
        file_layout = QHBoxLayout()
        file_layout.addWidget(QLabel("?? 附件文件:"))
        self.file_input = QLineEdit()
        self.file_input.setReadOnly(True)
        file_layout.addWidget(self.file_input)
        
        self.browse_button = QPushButton("瀏覽...")
        self.browse_button.clicked.connect(self.browse_file)
        file_layout.addWidget(self.browse_button)
        layout.addLayout(file_layout)
        
        # 發(fā)送按鈕
        self.send_button = QPushButton("?? 發(fā)送消息")
        self.send_button.clicked.connect(lambda: self.send_message(immediate=True))
        layout.addWidget(self.send_button, alignment=Qt.AlignRight)
    
    def create_schedule_tab(self):
        """創(chuàng)建定時發(fā)送標(biāo)簽頁"""
        self.schedule_tab = QWidget()
        self.tabs.addTab(self.schedule_tab, "? 定時發(fā)送")
        
        layout = QVBoxLayout(self.schedule_tab)
        layout.setSpacing(15)
        
        # 定時任務(wù)設(shè)置組
        schedule_group = QGroupBox("新建定時任務(wù)")
        schedule_layout = QVBoxLayout()
        
        # 收件人
        recipient_layout = QHBoxLayout()
        recipient_layout.addWidget(QLabel("?? 收件人:"))
        self.schedule_recipient_input = QLineEdit()
        self.schedule_recipient_input.setPlaceholderText("輸入微信用戶名或備注名")
        recipient_layout.addWidget(self.schedule_recipient_input)
        schedule_layout.addLayout(recipient_layout)
        
        # 消息內(nèi)容
        schedule_layout.addWidget(QLabel("?? 消息內(nèi)容:"))
        self.schedule_message_input = QTextEdit()
        self.schedule_message_input.setPlaceholderText("輸入要發(fā)送的消息...")
        schedule_layout.addWidget(self.schedule_message_input)
        
        # 文件附件
        file_layout = QHBoxLayout()
        file_layout.addWidget(QLabel("?? 附件文件:"))
        self.schedule_file_input = QLineEdit()
        self.schedule_file_input.setReadOnly(True)
        file_layout.addWidget(self.schedule_file_input)
        
        self.schedule_browse_button = QPushButton("瀏覽...")
        self.schedule_browse_button.clicked.connect(self.browse_schedule_file)
        file_layout.addWidget(self.schedule_browse_button)
        schedule_layout.addLayout(file_layout)
        
        # 定時設(shè)置
        time_layout = QHBoxLayout()
        time_layout.addWidget(QLabel("? 發(fā)送時間:"))
        self.datetime_input = QDateTimeEdit()
        self.datetime_input.setDisplayFormat("yyyy-MM-dd HH:mm:ss")
        self.datetime_input.setDateTime(datetime.now())
        time_layout.addWidget(self.datetime_input)
        
        self.repeat_checkbox = QCheckBox("重復(fù)發(fā)送")
        time_layout.addWidget(self.repeat_checkbox)
        
        self.repeat_interval = QSpinBox()
        self.repeat_interval.setRange(1, 1440)
        self.repeat_interval.setValue(60)
        self.repeat_interval.setSuffix("分鐘")
        time_layout.addWidget(self.repeat_interval)
        schedule_layout.addLayout(time_layout)
        
        # 添加任務(wù)按鈕
        self.add_task_button = QPushButton("? 添加定時任務(wù)")
        self.add_task_button.clicked.connect(self.add_scheduled_task)
        schedule_layout.addWidget(self.add_task_button)
        
        schedule_group.setLayout(schedule_layout)
        layout.addWidget(schedule_group)
        
        # 任務(wù)列表組
        tasks_group = QGroupBox("定時任務(wù)列表")
        tasks_layout = QVBoxLayout()
        
        self.tasks_list = QTextEdit()
        self.tasks_list.setReadOnly(True)
        tasks_layout.addWidget(self.tasks_list)
        
        self.clear_tasks_button = QPushButton("??? 清除已完成任務(wù)")
        self.clear_tasks_button.clicked.connect(self.clear_completed_tasks)
        tasks_layout.addWidget(self.clear_tasks_button)
        
        tasks_group.setLayout(tasks_layout)
        layout.addWidget(tasks_group)
    
    def create_control_tab(self):
        """創(chuàng)建控制標(biāo)簽頁"""
        self.control_tab = QWidget()
        self.tabs.addTab(self.control_tab, "?? 微信控制")
        
        layout = QVBoxLayout(self.control_tab)
        layout.setSpacing(15)
        
        # 微信路徑
        path_layout = QHBoxLayout()
        path_layout.addWidget(QLabel("?? 微信路徑:"))
        self.wechat_path_input = QLineEdit(r'C:\Program Files (x86)\Tencent\WeChat\WeChat.exe')
        path_layout.addWidget(self.wechat_path_input)
        
        self.path_browse_button = QPushButton("瀏覽...")
        self.path_browse_button.clicked.connect(self.browse_wechat_path)
        path_layout.addWidget(self.path_browse_button)
        layout.addLayout(path_layout)
        
        # 控制按鈕
        button_layout = QHBoxLayout()
        self.start_button = QPushButton("?? 啟動微信")
        self.start_button.clicked.connect(self.start_wechat)
        button_layout.addWidget(self.start_button)
        
        self.active_button = QPushButton("?? 激活窗口")
        self.active_button.clicked.connect(self.active_wechat)
        button_layout.addWidget(self.active_button)
        
        self.quit_button = QPushButton("? 退出微信")
        self.quit_button.clicked.connect(self.quit_wechat)
        button_layout.addWidget(self.quit_button)
        layout.addLayout(button_layout)
        
        # 日志區(qū)域
        layout.addWidget(QLabel("?? 操作日志:"))
        self.log_output = QTextEdit()
        self.log_output.setReadOnly(True)
        layout.addWidget(self.log_output)
    
    def browse_file(self):
        file_path, _ = QFileDialog.getOpenFileName(self, "選擇文件", "", "所有文件 (*.*)")
        if file_path:
            self.file_input.setText(file_path)
    
    def browse_schedule_file(self):
        file_path, _ = QFileDialog.getOpenFileName(self, "選擇文件", "", "所有文件 (*.*)")
        if file_path:
            self.schedule_file_input.setText(file_path)
    
    def browse_wechat_path(self):
        file_path, _ = QFileDialog.getOpenFileName(
            self, "選擇微信程序", "", "可執(zhí)行文件 (*.exe)")
        if file_path:
            self.wechat_path_input.setText(file_path)
    
    def log_message(self, message):
        """添加日志消息"""
        self.log_output.append(f"[{datetime.now().strftime('%H:%M:%S')}] {message}")
    
    def update_status(self, message, is_success=True):
        """更新狀態(tài)欄"""
        emoji = "??" if is_success else "??"
        self.status_bar.showMessage(f"{emoji} {message}")
    
    def send_message(self, recipient=None, message=None, file_path=None, immediate=False):
        """發(fā)送消息的核心方法"""
        if immediate:
            recipient = self.recipient_input.text().strip()
            message = self.message_input.toPlainText().strip()
            file_path = self.file_input.text().strip()
        
        if not recipient:
            QMessageBox.warning(self, "警告", "請輸入收件人")
            return False
        
        if not message and not file_path:
            QMessageBox.warning(self, "警告", "請輸入消息內(nèi)容或選擇文件")
            return False
        
        # 檢查文件是否存在
        if file_path and not os.path.exists(file_path):
            QMessageBox.warning(self, "警告", f"文件不存在: {file_path}")
            return False
        
        if immediate:
            self.send_button.setEnabled(False)
            self.status_bar.showMessage("?? 正在發(fā)送消息...")
        
        def send():
            try:
                if message:
                    wechat_send_msg(recipient, message)
                    self.log_message(f"文本消息已發(fā)送給: {recipient}")
                
                if file_path:
                    # 確保文件路徑是絕對路徑
                    abs_file_path = os.path.abspath(file_path)
                    if not os.path.exists(abs_file_path):
                        raise Exception(f"文件不存在: {abs_file_path}")
                    
                    msg = f"全路徑文件名:{abs_file_path}"
                    wechat_send_msg(recipient, msg)
                    self.log_message(f"文件已發(fā)送: {abs_file_path}")
                
                return "消息發(fā)送成功"
            except Exception as e:
                raise Exception(f"發(fā)送失敗: {str(e)}")
        
        if immediate:
            self.worker = WorkerThread(send)
            self.worker.finished.connect(lambda msg, success: self.on_operation_finished(msg, success, "send"))
            self.worker.start()
        else:
            try:
                send()
                return True
            except Exception as e:
                self.log_message(f"定時發(fā)送失敗: {str(e)}")
                return False
    
    def add_scheduled_task(self):
        """添加定時任務(wù)"""
        recipient = self.schedule_recipient_input.text().strip()
        message = self.schedule_message_input.toPlainText().strip()
        file_path = self.schedule_file_input.text().strip()
        send_time = self.datetime_input.dateTime().toPyDateTime()
        repeat = self.repeat_checkbox.isChecked()
        interval = self.repeat_interval.value()
        
        if not recipient:
            QMessageBox.warning(self, "警告", "請輸入收件人")
            return
        
        if not message and not file_path:
            QMessageBox.warning(self, "警告", "請輸入消息內(nèi)容或選擇文件")
            return
        
        # 檢查文件是否存在
        if file_path and not os.path.exists(file_path):
            QMessageBox.warning(self, "警告", f"文件不存在: {file_path}")
            return
        
        task = {
            "recipient": recipient,
            "message": message,
            "file_path": os.path.abspath(file_path) if file_path else "",
            "send_time": send_time,
            "repeat": repeat,
            "interval": interval,
            "completed": False
        }
        
        self.scheduled_tasks.append(task)
        self.update_tasks_list()
        QMessageBox.information(self, "成功", "定時任務(wù)已添加")
    
    def update_tasks_list(self):
        """更新任務(wù)列表顯示"""
        self.tasks_list.clear()
        now = datetime.now()
        
        for i, task in enumerate(self.scheduled_tasks, 1):
            status = "? 已完成" if task["completed"] else "? 等待中"
            time_left = (task["send_time"] - now).total_seconds()
            
            if time_left > 0:
                time_str = f"剩余: {int(time_left//3600)}小時{int((time_left%3600)//60)}分鐘"
            else:
                time_str = "已到時間"
            
            repeat_str = f", 每{task['interval']}分鐘重復(fù)" if task["repeat"] else ""
            
            self.tasks_list.append(
                f"{i}. {status} | {time_str}{repeat_str}\n"
                f"收件人: {task['recipient']}\n"
                f"內(nèi)容: {task['message'][:30]}{'...' if len(task['message'])>30 else ''}\n"
                f"附件: {task['file_path'] if task['file_path'] else '無'}\n"
                f"發(fā)送時間: {task['send_time'].strftime('%Y-%m-%d %H:%M:%S')}\n"
                "─" * 50
            )
    
    def check_scheduled_tasks(self):
        """檢查并執(zhí)行定時任務(wù)"""
        now = datetime.now()
        any_task_executed = False
        
        for task in self.scheduled_tasks:
            if not task["completed"] and now >= task["send_time"]:
                # 執(zhí)行任務(wù)
                success = self.send_message(
                    recipient=task["recipient"],
                    message=task["message"],
                    file_path=task["file_path"]
                )
                
                if success:
                    task["completed"] = True
                    self.log_message(f"定時任務(wù)執(zhí)行成功: 發(fā)送給 {task['recipient']}")
                    
                    # 如果是重復(fù)任務(wù),重新設(shè)置下次執(zhí)行時間
                    if task["repeat"]:
                        task["send_time"] = now + timedelta(minutes=task["interval"])
                        task["completed"] = False
                
                any_task_executed = True
        
        if any_task_executed:
            self.update_tasks_list()
    
    def clear_completed_tasks(self):
        """清除已完成的任務(wù)"""
        self.scheduled_tasks = [task for task in self.scheduled_tasks if not task["completed"]]
        self.update_tasks_list()
        QMessageBox.information(self, "提示", "已清除所有已完成任務(wù)")
    
    def start_wechat(self):
        wechat_path = self.wechat_path_input.text().strip()
        
        if not os.path.exists(wechat_path):
            QMessageBox.warning(self, "警告", "微信路徑無效,請重新選擇")
            return
        
        self.start_button.setEnabled(False)
        self.status_bar.showMessage("?? 正在啟動微信...")
        
        def start():
            try:
                wechat_start(wechat_path)
                return "微信啟動成功"
            except Exception as e:
                raise Exception(f"啟動失敗: {str(e)}")
        
        self.worker = WorkerThread(start)
        self.worker.finished.connect(lambda msg, success: self.on_operation_finished(msg, success, "start"))
        self.worker.start()
    
    def active_wechat(self):
        self.active_button.setEnabled(False)
        self.status_bar.showMessage("?? 正在激活微信窗口...")
        
        def active():
            try:
                wechat_active()
                return "微信窗口已激活"
            except Exception as e:
                raise Exception(f"激活失敗: {str(e)}")
        
        self.worker = WorkerThread(active)
        self.worker.finished.connect(lambda msg, success: self.on_operation_finished(msg, success, "active"))
        self.worker.start()
    
    def quit_wechat(self):
        self.quit_button.setEnabled(False)
        self.status_bar.showMessage("?? 正在退出微信...")
        
        def quit():
            try:
                wechat_quit()
                return "微信已退出"
            except Exception as e:
                raise Exception(f"退出失敗: {str(e)}")
        
        self.worker = WorkerThread(quit)
        self.worker.finished.connect(lambda msg, success: self.on_operation_finished(msg, success, "quit"))
        self.worker.start()
    
    def on_operation_finished(self, message, success, operation_type):
        """操作完成后的回調(diào)"""
        self.update_status(message, success)
        self.log_message(message)
        
        if not success:
            QMessageBox.critical(self, "錯誤", message)
        
        # 重新啟用按鈕
        if operation_type == "send":
            self.send_button.setEnabled(True)
        elif operation_type == "start":
            self.start_button.setEnabled(True)
        elif operation_type == "active":
            self.active_button.setEnabled(True)
        elif operation_type == "quit":
            self.quit_button.setEnabled(True)

def ifProcessRunning(process_name='WeChat.exe'):
    pl = psutil.pids()
    result = "PROCESS_IS_NOT_RUNNING"
    for pid in pl:
        try:
            if psutil.Process(pid).name() == process_name:
                if isinstance(pid, int):
                    result = "PROCESS_IS_RUNNING"
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            continue
    return result

def wechat_start(wechat_path):
    os.startfile(wechat_path)
    loginwin = uiautomation.PaneControl(searchDepth=1, ClassName='WeChatLoginWndForPC', Name='微信')
    try:
        loginwin.ButtonControl(Name='進(jìn)入微信').Click()
    except:
        loginwin.ButtonControl(Name='登錄').Click()

def wechat_active():
    uiautomation.uiautomation.TIME_OUT_SECOND = 2
    if ifProcessRunning() == "PROCESS_IS_RUNNING":
        try:
            desktop = uiautomation.PaneControl(Name='任務(wù)欄')
            desktop.SendKeys('{Ctrl}{Alt}w')
        except:
            os.system('taskkill /F /im "WeChat.exe" >nul')
            wechat_start(r'C:\Program Files (x86)\Tencent\WeChat\WeChat.exe')
    else:
        wechat_start(r'C:\Program Files (x86)\Tencent\WeChat\WeChat.exe')
    uiautomation.uiautomation.TIME_OUT_SECOND = 20
    wechatWindow = uiautomation.WindowControl(searchDepth=1, className='WeChatMainWndForPC', Name='微信')
    try:
        wechatWindow.Restore()
        wechatWindow.MoveToCenter()
        wechatWindow.SetTopmost(True)
    except:
        print('未能成功激活微信窗口')

def wechat_send_msg(send_to='微信用戶名', msg='要發(fā)送的消息'):
    wechat_active()
    wechatWindow = uiautomation.WindowControl(searchDepth=1, className='WeChatMainWndForPC', Name='微信')
    
    # 搜索聯(lián)系人
    search_edit = wechatWindow.EditControl(Name="搜索")
    search_edit.Click()
    search_edit.SendKeys(send_to, 0.5)
    time.sleep(1)  # 等待搜索結(jié)果
    
    # 按回車鍵選擇聯(lián)系人
    search_edit.SendKeys('{enter}')
    time.sleep(2)  # 增加等待時間確保聊天窗口加載
    
    if msg[:7] != '全路徑文件名:':
        # 查找消息輸入框 - 使用更可靠的方法
        chat_input = None
        for _ in range(5):  # 增加重試次數(shù)
            try:
                # 嘗試多種方式查找輸入框
                chat_input = wechatWindow.EditControl(Name="輸入")
                if not chat_input.Exists():
                    chat_input = wechatWindow.EditControl(automationId="editArea")
                if not chat_input.Exists():
                    chat_input = wechatWindow.EditControl(ClassName="Edit")
                
                if chat_input and chat_input.Exists():
                    break
            except Exception as e:
                print(f"查找輸入框時出錯: {str(e)}")
            time.sleep(1)
        
        if not chat_input or not chat_input.Exists():
            raise Exception("找不到消息輸入框,請確保已打開正確的聊天窗口")
        
        chat_input.SendKeys(msg, 0.03)
        
        # 查找發(fā)送按鈕 - 使用更可靠的方法
        send_button = None
        for _ in range(5):  # 增加重試次數(shù)
            try:
                send_button = wechatWindow.ButtonControl(Name="發(fā)送(S)")
                if not send_button.Exists():
                    send_button = wechatWindow.ButtonControl(automationId="sendBtn")
                if not send_button.Exists():
                    send_button = wechatWindow.ButtonControl(ClassName="Button", foundIndex=1)
                
                if send_button and send_button.Exists():
                    break
            except Exception as e:
                print(f"查找發(fā)送按鈕時出錯: {str(e)}")
            time.sleep(1)
        
        if not send_button or not send_button.Exists():
            raise Exception("找不到發(fā)送按鈕")
        
        send_button.Click()
    else:
        file_path = msg[7:]
        if not os.path.exists(file_path):
            raise Exception(f"文件不存在: {file_path}")
            
        # 查找文件發(fā)送按鈕 - 使用更可靠的方法
        file_button = None
        for _ in range(5):  # 增加重試次數(shù)
            try:
                file_button = wechatWindow.ButtonControl(Name="發(fā)送文件")
                if not file_button.Exists():
                    file_button = wechatWindow.ButtonControl(automationId="fileBtn")
                
                if file_button and file_button.Exists():
                    break
            except Exception as e:
                print(f"查找文件發(fā)送按鈕時出錯: {str(e)}")
            time.sleep(1)
        
        if not file_button or not file_button.Exists():
            raise Exception("找不到文件發(fā)送按鈕")
        
        file_button.Click()
        
        # 等待文件選擇對話框出現(xiàn)
        time.sleep(2)
        file_dialog = uiautomation.WindowControl(Name="打開")
        if not file_dialog.Exists():
            raise Exception("文件選擇對話框未出現(xiàn)")
            
        # 輸入文件路徑
        filename_edit = file_dialog.EditControl(Name="文件名(N):")
        filename_edit.SendKeys(file_path)
        time.sleep(0.5)
        filename_edit.SendKeys('{enter}')
        
        # 等待文件上傳
        time.sleep(3)
        
        # 查找最終發(fā)送按鈕 - 使用更可靠的方法
        final_send_button = None
        for _ in range(5):  # 增加重試次數(shù)
            try:
                final_send_button = wechatWindow.ButtonControl(Name="發(fā)送(1)")
                if not final_send_button.Exists():
                    final_send_button = wechatWindow.ButtonControl(automationId="sendBtn")
                
                if final_send_button and final_send_button.Exists():
                    break
            except Exception as e:
                print(f"查找最終發(fā)送按鈕時出錯: {str(e)}")
            time.sleep(1)
        
        if not final_send_button or not final_send_button.Exists():
            raise Exception("找不到最終發(fā)送按鈕")
        
        final_send_button.Click()
    
    wechatWindow.SetTopmost(False)
    wechatWindow.Minimize()

def wechat_quit():
    if ifProcessRunning() == "PROCESS_IS_RUNNING":
        os.system('taskkill /F /im "WeChat.exe" >nul')

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = WeChatAutomationApp()
    window.show()
    sys.exit(app.exec_())

技術(shù)難點(diǎn)與解決方案

1. 窗口控件定位問題

問題現(xiàn)象:微信版本更新導(dǎo)致自動化失效

解決方案:

# 多重定位策略
chat_input = None
for control_type in [("Name","輸入"), ("automationId","editArea"), ("ClassName","Edit")]:
    chat_input = wechatWindow.EditControl(**{control_type[0]: control_type[1]})
    if chat_input.Exists():
        break

2. 定時任務(wù)精度問題

對比方案:

方案精度CPU占用可靠性
QTimer輪詢1秒
Python threading0.1秒
Windows定時器毫秒級

選擇依據(jù):綜合業(yè)務(wù)需求選擇QTimer方案

擴(kuò)展知識

1. UI自動化技術(shù)對比

技術(shù)方案優(yōu)點(diǎn)缺點(diǎn)
uiautomation微軟官方,支持Win32文檔較少
PyAutoGUI跨平臺,簡單易用無法處理復(fù)雜控件
Selenium支持Web自動化不適用桌面應(yīng)用

2. 企業(yè)級優(yōu)化建議

加入配置文件:使用config.ini保存常用設(shè)置

增加日志系統(tǒng):采用logging模塊實現(xiàn)分級日志

打包發(fā)布:使用PyInstaller生成exe

添加單元測試:確保核心功能穩(wěn)定性

總結(jié)

本文詳細(xì)剖析了一個功能完備的微信自動化工具的開發(fā)全過程,關(guān)鍵技術(shù)要點(diǎn)包括:

  • PyQt5的MVC架構(gòu)實踐:實現(xiàn)界面與邏輯分離
  • 防御式編程思想:完善的異常處理體系
  • 自動化測試思維:控件查找的重試機(jī)制
  • 用戶體驗優(yōu)化:狀態(tài)反饋+日志系統(tǒng)

未來優(yōu)化方向:

  • 增加聯(lián)系人自動補(bǔ)全功能
  • 實現(xiàn)消息模板管理
  • 加入多賬號支持
  • 開發(fā)插件系統(tǒng)

到此這篇關(guān)于如何基于Python開發(fā)一個微信自動化工具的文章就介紹到這了,更多相關(guān)Python微信自動化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python操作word實現(xiàn)添加文字或圖片水印

    Python操作word實現(xiàn)添加文字或圖片水印

    這篇文章主要為大家詳細(xì)介紹了如何使用Spire.Doc for Python在程序中的輕松添加文字和圖像水印到Word文檔,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-10-10
  • Python序列之list和tuple常用方法以及注意事項

    Python序列之list和tuple常用方法以及注意事項

    這篇文章主要介紹了Python序列之list和tuple常用方法以及注意事項,sequence(序列)是一組有順序的對象的集合,序列可以包含一個或多個元素,也可以沒有任何元素,序列有兩種:list (表) 和 tuple(元組),需要的朋友可以參考下
    2015-01-01
  • Python解決C盤卡頓問題及操作腳本示例

    Python解決C盤卡頓問題及操作腳本示例

    這篇文章主要為大家介紹了Python解決C盤卡頓問題腳本示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • Python單元測試unittest模塊使用終極指南

    Python單元測試unittest模塊使用終極指南

    本文將詳細(xì)介紹unittest模塊的各個方面,包括測試用例、斷言、測試套件、setUp和tearDown方法、跳過和期望異常、測試覆蓋率、持續(xù)集成等內(nèi)容,我們將提供豐富的示例代碼,以便讀者更好地理解如何使用unittest進(jìn)行單元測試
    2023-12-12
  • Django中從mysql數(shù)據(jù)庫中獲取數(shù)據(jù)傳到echarts方式

    Django中從mysql數(shù)據(jù)庫中獲取數(shù)據(jù)傳到echarts方式

    這篇文章主要介紹了Django中從mysql數(shù)據(jù)庫中獲取數(shù)據(jù)傳到echarts方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-04-04
  • python hash每次調(diào)用結(jié)果不同的原因

    python hash每次調(diào)用結(jié)果不同的原因

    這篇文章主要介紹了python hash每次調(diào)用結(jié)果不同的原因,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11
  • Python操作HDF5文件示例

    Python操作HDF5文件示例

    這篇文章主要為大家介紹了Python操作HDF5文件示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • 12個Python程序員面試必備問題與答案(小結(jié))

    12個Python程序員面試必備問題與答案(小結(jié))

    這篇文章主要介紹了12個Python程序員面試必備問題與答案,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-06-06
  • Python調(diào)用API接口實現(xiàn)人臉識別

    Python調(diào)用API接口實現(xiàn)人臉識別

    本文主要介紹了Python調(diào)用API接口實現(xiàn)人臉識別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • 詳解Python的Django框架中的通用視圖

    詳解Python的Django框架中的通用視圖

    這篇文章主要介紹了詳解Python的Django框架中的通用視圖,是為MVC架構(gòu)的Django框架下的基礎(chǔ)知識,需要的朋友可以參考下
    2015-05-05

最新評論