admin
2025-04-02 91b7ec2b67d74e4d2e41c857232414feb3cb7bfd
功能完善
6个文件已修改
2个文件已添加
176 ■■■■ 已修改文件
comment.py 113 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
comment_manager.py 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
constant.py 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
icon.ico 补丁 | 查看 | 原始文档 | blame | 历史
main.spec 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
res/comment.txt 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
res/setting.conf 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
video_manager.py 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
comment.py
@@ -1,3 +1,6 @@
import json
import os
import random
import threading
import time
@@ -9,6 +12,7 @@
from selenium.webdriver.support import expected_conditions as EC
import comment_manager
import constant
import setting
from video_manager import VideoManger
@@ -23,9 +27,9 @@
        # driver = webdriver.Chrome(options=options)
        # 另外一种方式
        # 谷歌浏览器位置
        chrome_location = r'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'
        chrome_location = setting.get_chrome_path()
        # 谷歌浏览器驱动地址
        chromedriver_path = r'chromedriver.exe'
        chromedriver_path = setting.get_chromedriver_path()
        self.options.binary_location = chrome_location  # 指定chrome的路径
        self.service = Service(chromedriver_path)
        # 获取正则表达式
@@ -35,23 +39,48 @@
        self.comment_templates = [(x.split("#")[0], x.split("#")[1]) for x in comment_template_str.split("\n") if
                                  x.find("#") >= 0]
        self.driver = None
        self.break_excute = False  # 中断执行
    def break_excute(self):
        """
        中断执行
        :return:
        """
        print("=====中断执行=====")
        self.break_excute = True
    def __init(self):
        self.break_excute = False
        if not self.driver:
            self.driver = webdriver.Chrome(service=self.service, options=self.options)
            self.driver.get(
                "https://channels.weixin.qq.com/platform/comment?isImageMode=0")
        else:
            self.driver.refresh()
    def start_process_comment(self):
        """
        开始处理评论
        :return:
        """
        while True:
            try:
                self.__start_excute_task()
            except:
                pass
            finally:
                time.sleep(constant.REFRESH_TIME_SPACE)
    def __start_excute_task(self):
        """
        开始执行任务
        :return:
        """
        self.__init()
        self.driver.get(
            "https://channels.weixin.qq.com/platform/comment?isImageMode=0")
        # 等到左侧菜单出现后才能执行后续操作
        wait = WebDriverWait(self.driver, 100)  # 最多等待10秒
        wait = WebDriverWait(self.driver, 1000000)  # 最多等待10秒
        element = wait.until(EC.visibility_of_element_located((By.ID, "side-bar")))
        threading.Thread(target=lambda: self.process_videos(self.driver), daemon=True).start()
        self.process_videos(self.driver)
    def __process_like(self, video_name, video_date, comment_element):
        """
@@ -83,7 +112,10 @@
        """
        user_name = comment_element.find_element(By.CLASS_NAME, "comment-user-name").get_attribute("innerHTML")
        comment_time = comment_element.find_element(By.CLASS_NAME, "comment-time").get_attribute("innerHTML")
        comment_content = comment_element.find_element(By.CLASS_NAME, "comment-content").get_attribute("innerHTML")
        try:
            comment_content = comment_element.find_element(By.CLASS_NAME, "comment-content").get_attribute("innerHTML")
        except:
            comment_content = ''
        return user_name, comment_content, comment_time
    def __parse_video_info(self, video_element):
@@ -96,14 +128,16 @@
        comment_count = video_element.find_element(By.CLASS_NAME, "feed-comment-total").find_element(By.XPATH,
                                                                                                     "./span[2]").get_attribute(
            "innerHTML")
        video_name = video_element.find_element(By.CLASS_NAME, "comment-content").get_attribute("innerHTML")
        return video_name, video_time, comment_count
        video_name = video_element.find_element(By.CLASS_NAME, "feed-title").get_attribute("innerHTML")
        video_title = video_name
        if video_title.find("#") >= 0:
            video_title = video_title[:video_title.find("#")]
        return video_name, video_time, comment_count, video_title
    def __process_reply(self, video_name, video_date, comment_element):
    def __process_reply(self, video_info, comment_element):
        """
        处理单条评论回复
        :param video_name:
        :param video_date:
        :param video_name:(video_name, video_date, comment_count, video_title)
        :param comment_element:
        :return: 是否需要点赞
        """
@@ -112,7 +146,7 @@
            if not setting.is_reply_comment():
                return None
            # 内容是否符合标准
            return comment_manager.get_replay_content(video_name, video_date, nick_name, content)
            return comment_manager.get_replay_content(video_info, nick_name, content)
        comment_user_name, comment_content, comment_time = self.__parse_comment_info(comment_element)
@@ -124,7 +158,7 @@
        except:
            print("还没回复。。。。")
        replay_content = get_reply_comment(comment_user_name, comment_element)
        replay_content = get_reply_comment(comment_user_name, comment_content)
        if not replay_content:
            # 不需要评论
            print("不需要回复。。。。")
@@ -136,7 +170,7 @@
                                                                                                   "action-item")
        # 点击评论
        comment_actions[1].click()
        wait = WebDriverWait(self.driver, 5)  # 最多等待10秒
        wait = WebDriverWait(self.driver, 10)  # 最多等待10秒
        wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "comment-create-content")))
        time.sleep(1)
        self.driver.find_element(By.CLASS_NAME,
@@ -146,6 +180,7 @@
        self.driver.find_element(By.CLASS_NAME,
                                 "comment-create-content").find_element(By.XPATH, "div[3]/div[2]").click()
        time.sleep(2)
        time.sleep(random.randint(constant.COMMENT_REPLY_SPACE_TIME_MIN, constant.COMMENT_REPLY_SPACE_TIME_MAX))
        return False
    def __process_comments(self, driver, start_index=0, video_info=None):
@@ -153,26 +188,30 @@
        :param driver:
        :param start_index:
        :param video_info:(视频内容, 视频日期, 评论次数)
        :param video_info:(视频内容, 视频日期, 评论次数, 视频标题)
        :return:
        """
        scroll_list = driver.find_element(By.CLASS_NAME, "feed-comment__wrp")
        loadmore = scroll_list.find_element(By.CLASS_NAME, "loadmore__dot")
        # 获取父控件
        loadmore = loadmore.find_element(By.XPATH, "./..")
        has_more = loadmore.value_of_css_property("display") == "none"
        try:
            loadmore = scroll_list.find_element(By.CLASS_NAME, "loadmore__dot")
            # 获取父控件
            loadmore = loadmore.find_element(By.XPATH, "./..")
            has_more = loadmore.value_of_css_property("display") == "none"
        except:
            has_more = False
        comments = scroll_list.find_elements(By.XPATH, "div[2]/div/div/div[contains(@class,'comment-item')]")
        print("评论条数", len(comments))
        for index in range(start_index, len(comments)):
            if self.break_excute:
                return
            comment = comments[index]
            # 评论内容
            user_name, comment_content, comment_time = self.__parse_comment_info(comment)
            if not comment_content:
                continue
                comment_content = ''
            print("=======评论内容:", comment_content)
            need_like = self.__process_reply(video_info[0], video_info[1], comment)
            need_like = self.__process_reply(video_info, comment)
            if need_like:
                print("需要点赞")
                self.__process_like(video_info[0], video_info[1], comment)
@@ -184,9 +223,9 @@
                "var __comment_scroll = document.getElementsByClassName('feed-comment__wrp')[0]; __comment_scroll.scrollTop = __comment_scroll.scrollHeight;")
            print("往下滚动")
            time.sleep(3)
            self.__process_comments(driver, start_index=len(comments))
            self.__process_comments(driver, start_index=len(comments), video_info=video_info)
        else:
            print("没有更多评论了")
            print("没有更多评论了, 评论数量:", len(comments))
    def process_videos(self, driver: webdriver.Chrome, start_index=0):
        wait = WebDriverWait(driver, 100)  # 最多等待10秒
@@ -196,18 +235,20 @@
        videos_root = driver.find_element(By.CLASS_NAME, "feeds-container")
        videos = videos_root.find_elements(By.CLASS_NAME, "comment-feed-wrap")
        for i in range(start_index, len(videos)):
            if self.break_excute:
                return
            # 选择视频
            video = videos[i]
            # 解析视频内容
            video_name, video_time, comment_count = self.__parse_video_info(video)
            video_info = self.__parse_video_info(video)
            # 判断是否要点击进去
            if not VideoManger().is_need_click(video_name, video_time, comment_count):
            if not VideoManger().is_need_click(video_info):
                continue
            video.click()
            driver.implicitly_wait(2)
            self.__process_comments(driver, video_info=(video_name, video_time, comment_count))
            # 5s处理一个视频
            time.sleep(5)
            self.__process_comments(driver, video_info=video_info)
            # 处理一个视频
            time.sleep(constant.VIDEO_CLICK_SPACE_TIME)
        loadmore = scroll_list.find_element(By.CLASS_NAME, "loadmore__dot")
        # 获取父控件
@@ -230,6 +271,18 @@
            except:
                pass
    def __save_cookie(self):
        cookies = self.driver.get_cookies()
        with open("datas/cookies.json", "w") as f:
            json.dump(cookies, f)
    def __fill_cookie(self):
        if os.path.exists("datas/cookies.json"):
            with open("datas/cookies.json", "r") as f:
                cookies = json.load(f)
                for cookie in cookies:
                    self.driver.add_cookie(cookie)
if __name__ == "__main__":
    # CommentManager().start_process_comment()
comment_manager.py
@@ -3,6 +3,8 @@
"""
# 保存回复视频评论的用户昵称
# {"视频名称+发布日期":{"评论用户的昵称":{"评论内容集合"}}}
import re
import comment_util
__reply_video_comment_user_name_dict = {}
@@ -24,15 +26,16 @@
    __reply_video_comment_user_name_dict[k][comment_nick_name].add(comment_content)
def get_replay_content(video_name, video_date, comment_nick_name, comment_content):
def get_replay_content(video_info, comment_nick_name, comment_content):
    """
    获取回复内容
    :param video_name:视频名称
    :param video_date:视频日期
    :param video_info:(视频名称, 日期, 评论次数, 视频标题)
    :param comment_nick_name:评论昵称
    :param comment_content:评论内容
    :return:
    """
    video_name, video_date, video_title = video_info[0], video_info[1], video_info[3]
    k = f"{video_name}{video_date}"
    if k not in __reply_video_comment_user_name_dict:
        __reply_video_comment_user_name_dict[k] = {}
@@ -51,7 +54,13 @@
    comment_content = comment_util.replace_img_with_alt(comment_content)
    for r in comment_templates:
        if r.match(r[0], comment_content):
        is_match = False
        if r[0].find("【视频标题】") >= 0:
            if comment_content.find(video_title)>=0:
                is_match = True
        elif re.match(r[0], comment_content):
            is_match = True
        if is_match:
            # 能够匹配到正则表达式
            result = comment_util.load_content(r[1], comment_nick_name, comment_content)
            if result:
@@ -75,7 +84,7 @@
    # 替换评论内容中的img
    comment_content = comment_util.replace_img_with_alt(comment_content)
    for r in like_conditions:
        if r.match(r, comment_content):
        if re.match(r, comment_content):
            # 能够匹配到正则表达式
            return True
    return False
constant.py
New file
@@ -0,0 +1,6 @@
REFRESH_TIME_SPACE = 30 * 60  # 刷新时间 30分钟
VIDEO_CLICK_SPACE_TIME = 20  # 视频切换时间间隔
COMMENT_REPLY_SPACE_TIME_MIN = 5  # 评论时间间隔最小值
COMMENT_REPLY_SPACE_TIME_MAX = 20  # 评论时间间隔最大值
icon.ico
main.spec
@@ -59,5 +59,5 @@
    strip=False,
    upx=True,
    upx_exclude=[],
    name='kp',
    name='视频号助手',
)
res/comment.txt
@@ -1,4 +1,10 @@
.*不对.*#{是的,你的观点很赞|好吧[爱心]|谢谢[抱拳]|是的[强]|确实可能有些不对[裂开]}
.*对.*|.*支持.*|.*没毛病.*|.*一样.*|.*没错.*|.*有道理.*#{感谢你的认同|感谢你的评价|谢谢你的认同|感恩你的认同|谢谢你的评论|感恩你的认可|是的,你说的没错|你的认同我很感激}{【1-3】}
.*太少了.*#{是的,确实不多}{【1-3】}
^(\[\w+\])+$#【最后一个表情】【1-3】#只有表情
.*【视频标题】.*#{感谢你的评论|感谢你的支持}【1-3】 #1:1复制文案
*喜欢*#{好吧|感谢喜欢|喜欢就好|能让你喜欢真开心}
^[^\[\]]*$|^(?!.*\[\w+\]).*$#【内容】【1-3】#不包含emoji表情,只有一段文字
.*\[.*?\].*#【最后一个表情】【1-3】#包含emoji
.*早安.*#{早上好|早安|早上好啊|早安咯|早啊|祝你早上好|祝你早上开心|祝你早安}【1-3】#
.*生日.*#【昵称】{[蛋糕]|[蛋糕][蛋糕]|[蛋糕][蛋糕][蛋糕]}#
res/setting.conf
@@ -1,12 +1,18 @@
[config]
comment_templates = [*]$#[*]
    不对#
    对#
    ^你#123123
comment_templates = .*生日.*#【昵称】{[蛋糕]|[蛋糕][蛋糕]|[蛋糕][蛋糕][蛋糕]}#
    .*不对.*#{是的,你的观点很赞|好吧[爱心]|谢谢[抱拳]|是的[强]|确实可能有些不对[裂开]}
    .*对.*|.*支持.*|.*没毛病.*|.*一样.*|.*没错.*|.*有道理.*#{感谢你的认同|感谢你的评价|谢谢你的认同|感恩你的认同|谢谢你的评论|感恩你的认可|是的,你说的没错|你的认同我很感激}{【1-3】}
    .*太少了.*#{是的,确实不多}{【1-3】}
    ^(\[\w+\])+$#【最后一个表情】【1-3】#只有表情
    .*【视频标题】.*#{感谢你的评论|感谢你的支持}【1-3】 #1:1复制文案
    *喜欢*#{好吧|感谢喜欢|喜欢就好|能让你喜欢真开心}
    ^[^\[\]]*$|^(?!.*\[\w+\]).*$#【内容】【1-3】#不包含emoji表情,只有一段文字
    .*\[.*?\].*#【最后一个表情】【1-3】#包含emoji
    .*早安.*#{早上好|早安|早上好啊|早安咯|早啊|祝你早上好|祝你早上开心|祝你早安}【1-3】#
reply_comment = 1
click_like = 1
chromedriver_path = D:\workspace\python\wechat_helper\chromedriver.exe
chrome_path = D:\workspace\python\wechat_helper\chromedriver.exe
chrome_path = C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
common_emojis = [爱心] [合十] [拥抱] [抱拳] [强] [玫瑰] [胜利] [666] [呲牙] [愉快]
like_conditions = [\u4e00-\u9fa5]{2,}#最少2个字中文
like_conditions = ^$#空白评论内容
video_manager.py
@@ -18,18 +18,17 @@
                if lines:
                    self.__video_data_cache_dict = eval(lines[0])
    def is_need_click(self, video_name, video_time, comment_count):
    def is_need_click(self, video_info):
        """
        是否需要点击
        :param video_name: 视频名称
        :param video_time: 视频时间
        :param comment_count: 评论数量
        :param video_info:
        :return:
        """
        video_name, video_time, comment_count = video_info[0], video_info[1], video_info[2]
        k = f"{video_name}{video_time}"
        if k not in self.__video_data_cache_dict:
            return True
        if comment_count - self.__video_data_cache_dict[k][0] > 0:
        if int(comment_count) - int(self.__video_data_cache_dict[k][0]) > 0:
            return True
        return False
@@ -44,4 +43,3 @@
        # 保存到文件
        with open(self.__video_cache_path, encoding="utf-8", mode='w') as f:
            f.write(f"{self.__video_data_cache_dict}")