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

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

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

概述

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

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

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

uiautomation實(shí)現(xiàn)Windows UI自動(dòng)化

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

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

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

功能全景

1. 核心功能模塊

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

2. 特色功能

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

效果展示

1. 主界面概覽

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

3. 操作日志演示

實(shí)現(xiàn)步驟詳解

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

pip install pyqt5 psutil uiautomation

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

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

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

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

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

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

UI自動(dòng)化控制:uiautomation操作微信窗口

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

代碼深度解析

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

class WorkerThread(QThread):
    finished = pyqtSignal(str, bool)  # 信號(hào)參數(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"錯(cuò)誤: {str(e)}", False)

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

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

2. 微信窗口控制核心

def wechat_active():
    # 超時(shí)設(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)超時(shí)
    uiautomation.uiautomation.TIME_OUT_SECOND = 20  
    wechatWindow = uiautomation.WindowControl(
        searchDepth=1, 
        className='WeChatMainWndForPC', 
        Name='微信'
    )

優(yōu)化策略:

動(dòng)態(tài)調(diào)整UI查找超時(shí)時(shí)間

多方案組合提高成功率

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

3. 定時(shí)任務(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):

低精度定時(shí)檢查(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"錯(cuò)誤: {str(e)}", False)

class WeChatAutomationApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("微信自動(dòng)化發(fā)送工具---BY 白澤")
        self.setGeometry(100, 100, 787, 639)
        self.setWindowIcon(QIcon("wechat.ico"))  # 替換為你的圖標(biāo)文件
        
        # 定時(shí)任務(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)簽頁(yè)
        self.tabs = QTabWidget()
        self.main_layout.addWidget(self.tabs)
        
        # 創(chuàng)建各個(gè)標(biāo)簽頁(yè)
        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)簽頁(yè)"""
        self.send_tab = QWidget()
        self.tabs.addTab(self.send_tab, "?? 即時(shí)發(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)建定時(shí)發(fā)送標(biāo)簽頁(yè)"""
        self.schedule_tab = QWidget()
        self.tabs.addTab(self.schedule_tab, "? 定時(shí)發(fā)送")
        
        layout = QVBoxLayout(self.schedule_tab)
        layout.setSpacing(15)
        
        # 定時(shí)任務(wù)設(shè)置組
        schedule_group = QGroupBox("新建定時(shí)任務(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í)設(shè)置
        time_layout = QHBoxLayout()
        time_layout.addWidget(QLabel("? 發(fā)送時(shí)間:"))
        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("? 添加定時(shí)任務(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("定時(shí)任務(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)簽頁(yè)"""
        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("?? 啟動(dòng)微信")
        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, "警告", "請(qǐng)輸入收件人")
            return False
        
        if not message and not file_path:
            QMessageBox.warning(self, "警告", "請(qǐng)輸入消息內(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:
                    # 確保文件路徑是絕對(duì)路徑
                    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"定時(shí)發(fā)送失敗: {str(e)}")
                return False
    
    def add_scheduled_task(self):
        """添加定時(shí)任務(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, "警告", "請(qǐng)輸入收件人")
            return
        
        if not message and not file_path:
            QMessageBox.warning(self, "警告", "請(qǐng)輸入消息內(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, "成功", "定時(shí)任務(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)}小時(shí){int((time_left%3600)//60)}分鐘"
            else:
                time_str = "已到時(shí)間"
            
            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 '無(wú)'}\n"
                f"發(fā)送時(shí)間: {task['send_time'].strftime('%Y-%m-%d %H:%M:%S')}\n"
                "─" * 50
            )
    
    def check_scheduled_tasks(self):
        """檢查并執(zhí)行定時(shí)任務(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"定時(shí)任務(wù)執(zhí)行成功: 發(fā)送給 {task['recipient']}")
                    
                    # 如果是重復(fù)任務(wù),重新設(shè)置下次執(zhí)行時(shí)間
                    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, "警告", "微信路徑無(wú)效,請(qǐng)重新選擇")
            return
        
        self.start_button.setEnabled(False)
        self.status_bar.showMessage("?? 正在啟動(dòng)微信...")
        
        def start():
            try:
                wechat_start(wechat_path)
                return "微信啟動(dòng)成功"
            except Exception as e:
                raise Exception(f"啟動(dòng)失敗: {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, "錯(cuò)誤", 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)  # 增加等待時(shí)間確保聊天窗口加載
    
    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"查找輸入框時(shí)出錯(cuò): {str(e)}")
            time.sleep(1)
        
        if not chat_input or not chat_input.Exists():
            raise Exception("找不到消息輸入框,請(qǐng)確保已打開正確的聊天窗口")
        
        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ā)送按鈕時(shí)出錯(cuò): {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ā)送按鈕時(shí)出錯(cuò): {str(e)}")
            time.sleep(1)
        
        if not file_button or not file_button.Exists():
            raise Exception("找不到文件發(fā)送按鈕")
        
        file_button.Click()
        
        # 等待文件選擇對(duì)話框出現(xiàn)
        time.sleep(2)
        file_dialog = uiautomation.WindowControl(Name="打開")
        if not file_dialog.Exists():
            raise Exception("文件選擇對(duì)話框未出現(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ā)送按鈕時(shí)出錯(cuò): {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. 窗口控件定位問(wèn)題

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

解決方案:

# 多重定位策略
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. 定時(shí)任務(wù)精度問(wèn)題

對(duì)比方案:

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

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

擴(kuò)展知識(shí)

1. UI自動(dòng)化技術(shù)對(duì)比

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

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

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

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

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

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

總結(jié)

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

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

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

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

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

相關(guān)文章

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

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

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

    Python序列之list和tuple常用方法以及注意事項(xiàng)

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

    Python解決C盤卡頓問(wèn)題及操作腳本示例

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

    Python單元測(cè)試unittest模塊使用終極指南

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

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

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

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

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

    Python操作HDF5文件示例

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

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

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

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

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

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

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

最新評(píng)論