#Python 微信网页版信息自动回复(3.0)

功能简介:

这段代码实现了一个在网页版本微信上自动回复消息的工具。 首先这个工具会打开你的微信网页版。它能和一个外部的智能服务进行交互,当你在微信上收到新消息的时候,它会把这个消息传给外部服务,然后外部服务会给出一个回复。这个工具就会把这个回复发送到微信上,就好像有一个小助手在帮你自动回复消息一样。 如果在处理新消息的过程中出了问题,比如等得太久没反应,它会去点击文件传输助手,让微信保持活跃状态。要是遇到了错误,它还会尝试刷新页面或者重新启动浏览器驱动来解决问题。 你可以通过按特定的键来退出这个自动回复程序。总之,它能帮你在微信上自动回复消息,让你不用一直手动回复,省了不少事儿呢。 
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.youkuaiyun.com/m0_60781580/article/details/143671330

 这是3.0的版本

更新内容:

1、可选择预设文字回复和接入的AI回复!

2、在AI算力不足时,会以预设文字进行补充回复

下载链接:

https://download.youkuaiyun.com/download/m0_60781580/89986884?spm=1001.2014.3001.5503

视频演示:

微信网页版自动回复-优快云直播

import logging
from dataclasses import dataclass
from pathlib import Path
from typing import Optional, List, Dict, Union
import json
import sys
import msvcrt
import time
import random
import requests
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import (
    NoSuchElementException,
    TimeoutException,
    WebDriverException
)

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('wechat_auto_reply.log'),
        logging.StreamHandler()
    ]
)

@dataclass
class ReplyRule:
    """回复规则类"""
    keywords: List[str]  # 触发关键字列表
    response_type: str   # 回复类型: "text", "image", "file"
    content: str        # 回复内容: 文本消息/文件路径

@dataclass
class Config:
    """配置类,用于管理所有配置参数"""
    chromedriver_path: str
    extension_path: str
    api_url: str
    api_key: str
    wait_timeout: int = 30
    retry_interval: int = 1
    reply_mode: str = "api"  # "api" 或 "preset"
    preset_replies: List[str] = None  # 预设文本回复列表
    reply_rules: List[Dict] = None    # 关键字回复规则列表

    @classmethod
    def load_from_file(cls, config_path: str = 'config.json') -> 'Config':
        """从配置文件加载配置"""
        try:
            with open(config_path, 'r', encoding='utf-8') as f:
                config_data = json.load(f)
                
            # 确保preset_replies是列表类型
            if 'preset_replies' in config_data and not isinstance(config_data['preset_replies'], list):
                config_data['preset_replies'] = [config_data['preset_replies']]
            elif 'preset_replies' not in config_data:
                config_data['preset_replies'] = []
                
            # 处理reply_rules
            if 'reply_rules' not in config_data:
                config_data['reply_rules'] = []
                
            return cls(**config_data)
        except FileNotFoundError:
            logging.error(f"配置文件 {config_path} 不存在")
            raise
        except json.JSONDecodeError:
            logging.error(f"配置文件 {config_path} 格式错误")
            raise

class WeChatAutoReply:
    def __init__(self, config: Config):
        self.config = config
        self.driver = None
        self.wait = None
        self.reply_rules = [
            ReplyRule(**rule) for rule in config.reply_rules
        ] if config.reply_rules else []
        self.setup_driver()

    def setup_driver(self):
        """设置并初始化WebDriver"""
        try:
            service = Service(executable_path=self.config.chromedriver_path)
            options = webdriver.ChromeOptions()
            if Path(self.config.extension_path).exists():
                options.add_argument(f'--load-extension={self.config.extension_path}')

            self.driver = webdriver.Chrome(service=service, options=options)
            self.wait = WebDriverWait(self.driver, self.config.wait_timeout)
            self.driver.get('https://wx.qq.com/?target=t')
            logging.info("WebDriver初始化成功")
        except WebDriverException as e:
            logging.error(f"WebDriver初始化失败: {e}")
            raise

    def get_api_response(self, message: str) -> Optional[str]:
        """获取API响应"""
        try:
            url = f'{self.config.api_url}?key={self.config.api_key}&appid=0&msg={message}'
            response = requests.get(url, timeout=10)
            response.raise_for_status()
            content = response.json().get('content', '').replace('(br)', '')
            return content
        except requests.RequestException as e:
            logging.error(f"API请求失败: {e}")
            return None

    def get_preset_response(self) -> Optional[str]:
        """从预设回复列表中随机选择一条回复"""
        if self.config.preset_replies:
            return random.choice(self.config.preset_replies)
        return None

    def check_keyword_rules(self, message: str) -> Optional[ReplyRule]:
        """检查消息是否匹配关键字规则"""
        for rule in self.reply_rules:
            if any(keyword.lower() in message.lower() for keyword in rule.keywords):
                return rule
        return None

    def send_message(self, content: str):
        """发送文本消息"""
        try:
            message_input = self.wait.until(
                EC.presence_of_element_located((By.ID, 'editArea'))
            )
            message_input.clear()
            message_input.send_keys(content)

            send_button = self.wait.until(
                EC.element_to_be_clickable((By.CSS_SELECTOR, 'a.btn.btn_send'))
            )
            send_button.click()
            logging.info(f"成功发送消息: {content[:50]}...")
        except (TimeoutException, NoSuchElementException) as e:
            logging.error(f"发送消息失败: {e}")
            raise

    def send_file_or_image(self, file_path: str):
        """发送文件或图片"""
        try:
            # 点击文件上传按钮
            upload_button = self.wait.until(
                EC.presence_of_element_located((By.CSS_SELECTOR, '.web_wechat_upload'))
            )
            upload_button.click()

            # 等待文件输入元素出现
            file_input = self.wait.until(
                EC.presence_of_element_located((By.CSS_SELECTOR, 'input[type="file"]'))
            )
            
            # 发送文件路径到input元素
            file_input.send_keys(str(Path(file_path).absolute()))
            
            # 等待发送按钮可点击并点击
            send_button = self.wait.until(
                EC.element_to_be_clickable((By.CSS_SELECTOR, '.btn_send'))
            )
            send_button.click()
            
            logging.info(f"成功发送文件: {file_path}")
        except Exception as e:
            logging.error(f"发送文件失败: {e}")
            raise

    def handle_new_message(self):
        """处理新消息"""
        try:
            # 检查新消息提示
            new_message = self.wait.until(
                EC.presence_of_element_located(
                    (By.XPATH, "//i[contains(@class, 'icon web_wechat_reddot_middle ng-binding ng-scope')]")
                )
            )
            ActionChains(self.driver).move_to_element(new_message).click().perform()

            # 获取消息内容
            message_element = self.wait.until(
                EC.presence_of_element_located(
                    (By.XPATH, "//pre[contains(@class, 'js_message_plain ng-binding')]")
                )
            )
            message_content = message_element.text

            # 首先检查关键字规则
            rule = self.check_keyword_rules(message_content)
            if rule:
                if rule.response_type == "text":
                    self.send_message(rule.content)
                else:  # image or file
                    self.send_file_or_image(rule.content)
                return

            # 如果没有匹配的关键字规则,使用常规回复
            response = None
            if self.config.reply_mode == "preset":
                response = self.get_preset_response()
                if not response:
                    logging.warning("预设回复列表为空,尝试使用API回复")
                    response = self.get_api_response(message_content)
            else:  # api mode
                response = self.get_api_response(message_content)
                if not response and self.config.preset_replies:
                    logging.warning("API回复失败,使用预设回复作为备选")
                    response = self.get_preset_response()

            if response:
                self.send_message(response)
            else:
                logging.error("无法获取有效回复")

        except TimeoutException:
            self.click_file_helper()
        except Exception as e:
            logging.error(f"处理消息时出错: {e}")
            self.handle_error()

    def click_file_helper(self):
        """点击文件传输助手,保持会话活跃"""
        try:
            file_helper = self.wait.until(
                EC.presence_of_element_located(
                    (By.XPATH, "//span[contains(@class, 'nickname_text ng-binding') and contains(text(),'文件传输助手')]")
                )
            )
            file_helper.click()
        except (TimeoutException, NoSuchElementException) as e:
            logging.warning(f"点击文件传输助手失败: {e}")

    def handle_error(self):
        """错误处理"""
        try:
            self.driver.refresh()
            time.sleep(self.config.retry_interval)
        except WebDriverException as e:
            logging.error(f"页面刷新失败: {e}")
            self.restart_driver()

    def restart_driver(self):
        """重启WebDriver"""
        try:
            if self.driver:
                self.driver.quit()
            self.setup_driver()
        except WebDriverException as e:
            logging.error(f"重启WebDriver失败: {e}")
            raise

    def run(self):
        """运行主循环"""
        try:
            logging.info("自动回复程序启动")
            while True:
                if msvcrt.kbhit() and msvcrt.getch() == b'\x1b':
                    logging.info("收到退出信号,程序正在终止...")
                    break
                self.handle_new_message()
        except KeyboardInterrupt:
            logging.info("程序被手动中断")
        finally:
            if self.driver:
                self.driver.quit()
            logging.info("程序已终止")

def main():
    try:
        config = Config.load_from_file()
        auto_reply = WeChatAutoReply(config)
        auto_reply.run()
    except Exception as e:
        logging.critical(f"程序发生致命错误: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值