| | |
| | | import re |
| | | import threading |
| | | import time |
| | | |
| | |
| | | from selenium.webdriver.support.wait import WebDriverWait |
| | | from selenium.webdriver.support import expected_conditions as EC |
| | | |
| | | import comment_manager |
| | | import setting |
| | | from video_manager import VideoManger |
| | | |
| | | |
| | | class CommentManager: |
| | |
| | | # 等到左侧菜单出现后才能执行后续操作 |
| | | wait = WebDriverWait(self.driver, 100) # 最多等待10秒 |
| | | element = wait.until(EC.visibility_of_element_located((By.ID, "side-bar"))) |
| | | threading.Thread(target=lambda: self.click_like(self.driver), daemon=True).start() |
| | | threading.Thread(target=lambda: self.process_videos(self.driver), daemon=True).start() |
| | | |
| | | def __process_like(self, comment_content, comment_element): |
| | | def __process_like(self, video_name, video_date, comment_element): |
| | | """ |
| | | 处理单条评论的赞 |
| | | :param comment_content: |
| | | :param comment_element: |
| | | :return: |
| | | """ |
| | | comment_pattern = re.compile(r'[\u4e00-\u9fa5]+') |
| | | comment_content = re.sub("<img.*?>", "", comment_content) |
| | | if not comment_pattern.search(comment_content): |
| | | # 符合标准的评论 |
| | | user_name, comment_content, comment_time = self.__parse_comment_info(comment_element) |
| | | if not comment_manager.is_need_click_like(video_name, video_date, user_name, comment_content): |
| | | return |
| | | |
| | | comment_actions = comment_element.find_element(By.CLASS_NAME, "action-list").find_elements(By.CLASS_NAME, |
| | | "action-item") |
| | | classes: str = comment_actions[0].find_element(By.TAG_NAME, "svg").get_attribute("class") |
| | |
| | | return |
| | | like = comment_element.find_element(By.CLASS_NAME, "like-action") |
| | | like.click() |
| | | self.driver.implicitly_wait(2) |
| | | # self.driver.implicitly_wait(2) |
| | | time.sleep(2) |
| | | |
| | | def __process_reply(self, comment_content, comment_element): |
| | | def __parse_comment_info(self, comment_element): |
| | | """ |
| | | 处理单条评论的回复 |
| | | :param comment_content: |
| | | 解析评论信息 |
| | | :param comment_element: |
| | | :return: |
| | | :return:(评论人,评论内容,评论时间) |
| | | """ |
| | | 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") |
| | | return user_name, comment_content, comment_time |
| | | |
| | | def __parse_video_info(self, video_element): |
| | | """ |
| | | 解析视频信息 |
| | | :param comment_element: |
| | | :return:(视频名称,视频时间,评论数量) |
| | | """ |
| | | video_time = video_element.find_element(By.CLASS_NAME, "feed-time").get_attribute("innerHTML") |
| | | 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 |
| | | |
| | | def __process_reply(self, video_name, video_date, comment_element): |
| | | """ |
| | | 处理单条评论回复 |
| | | :param video_name: |
| | | :param video_date: |
| | | :param comment_element: |
| | | :return: 是否需要点赞 |
| | | """ |
| | | |
| | | def get_reply_comment(nick_name, content): |
| | | if not setting.is_reply_comment(): |
| | | return None |
| | | # 内容是否符合标准 |
| | | for t in self.comment_templates: |
| | | if re.match(t[0], content): |
| | | # 满足内容 |
| | | return t[1].replace("[昵称]", nick_name) |
| | | return comment_manager.get_replay_content(video_name, video_date, nick_name, content) |
| | | |
| | | comment_pattern = re.compile(r'[\u4e00-\u9fa5]+') |
| | | comment_content = re.sub("<img.*?>", "", comment_content) |
| | | if not comment_pattern.search(comment_content): |
| | | # 符合标准的评论 |
| | | return |
| | | comment_user_name, comment_content, comment_time = self.__parse_comment_info(comment_element) |
| | | |
| | | try: |
| | | comment_reply_list = comment_element.find_element(By.CLASS_NAME, "comment-reply-list") |
| | | if comment_reply_list.find_element(By.XPATH, ".//div[normalize-space()='作者']"): |
| | | print("已经回复。。。。") |
| | | return |
| | | return False |
| | | except: |
| | | print("还没回复。。。。") |
| | | |
| | | replay_content = get_reply_comment(comment_user_name, comment_element) |
| | | if not replay_content: |
| | | # 不需要评论 |
| | | print("不需要回复。。。。") |
| | | return True |
| | | |
| | | # 需要回复 |
| | | |
| | | comment_actions = comment_element.find_element(By.CLASS_NAME, "action-list").find_elements(By.CLASS_NAME, |
| | | "action-item") |
| | | # 点击评论 |
| | | comment_actions[1].click() |
| | | wait = WebDriverWait(self.driver, 5) # 最多等待10秒 |
| | | element = wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "comment-create-content"))) |
| | | # TODO 昵称 |
| | | replay_content = get_reply_comment("昵称", comment_element) |
| | | if not replay_content: |
| | | # 不需要评论 |
| | | return |
| | | |
| | | wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "comment-create-content"))) |
| | | time.sleep(1) |
| | | self.driver.find_element(By.CLASS_NAME, |
| | | "comment-create-content").find_element(By.TAG_NAME, |
| | | "textarea").send_keys(replay_content) |
| | |
| | | self.driver.find_element(By.CLASS_NAME, |
| | | "comment-create-content").find_element(By.XPATH, "div[3]/div[2]").click() |
| | | time.sleep(2) |
| | | return False |
| | | |
| | | def __click_like_all(self, driver, start_index=0): |
| | | def __process_comments(self, driver, start_index=0, video_info=None): |
| | | """ |
| | | |
| | | :param driver: |
| | | :param start_index: |
| | | :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") |
| | |
| | | for index in range(start_index, len(comments)): |
| | | comment = comments[index] |
| | | # 评论内容 |
| | | comment_content = comment.find_element(By.CLASS_NAME, "comment-content").get_attribute("innerHTML") |
| | | user_name, comment_content, comment_time = self.__parse_comment_info(comment) |
| | | if not comment_content: |
| | | continue |
| | | print("=======评论内容:", comment_content) |
| | | self.__process_reply(comment_content, comment) |
| | | self.__process_like(comment_content, comment) |
| | | need_like = self.__process_reply(video_info[0], video_info[1], comment) |
| | | if need_like: |
| | | print("需要点赞") |
| | | self.__process_like(video_info[0], video_info[1], comment) |
| | | else: |
| | | print("不需要点赞") |
| | | # 往下滑动 |
| | | if has_more: |
| | | driver.execute_script( |
| | | "var __comment_scroll = document.getElementsByClassName('feed-comment__wrp')[0]; __comment_scroll.scrollTop = __comment_scroll.scrollHeight;") |
| | | print("往下滚动") |
| | | time.sleep(3) |
| | | self.__click_like_all(driver, start_index=len(comments)) |
| | | self.__process_comments(driver, start_index=len(comments)) |
| | | else: |
| | | print("没有更多了") |
| | | print("没有更多评论了") |
| | | |
| | | def click_like(self, driver: webdriver.Chrome): |
| | | def process_videos(self, driver: webdriver.Chrome, start_index=0): |
| | | wait = WebDriverWait(driver, 100) # 最多等待10秒 |
| | | element = wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "feeds-container"))) |
| | | scroll_list = wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "feeds-container"))) |
| | | time.sleep(1) |
| | | # 查找视频列表 |
| | | videos_root = driver.find_element(By.CLASS_NAME, "feeds-container") |
| | | videos = videos_root.find_elements(By.CLASS_NAME, "comment-feed-wrap") |
| | | for video in videos: |
| | | for i in range(start_index, len(videos)): |
| | | # 选择视频 |
| | | video = videos[i] |
| | | # 解析视频内容 |
| | | video_name, video_time, comment_count = self.__parse_video_info(video) |
| | | # 判断是否要点击进去 |
| | | if not VideoManger().is_need_click(video_name, video_time, comment_count): |
| | | continue |
| | | video.click() |
| | | driver.implicitly_wait(2) |
| | | self.__click_like_all(driver) |
| | | self.__process_comments(driver, video_info=(video_name, video_time, comment_count)) |
| | | # 5s处理一个视频 |
| | | time.sleep(5) |
| | | |
| | | 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" |
| | | if has_more: |
| | | driver.execute_script( |
| | | "var __video_scroll = document.getElementsByClassName('feeds-container')[0]; __video_scroll.scrollTop = __video_scroll.scrollHeight;") |
| | | print("往下滚动") |
| | | time.sleep(3) |
| | | self.process_videos(driver, start_index=len(videos)) |
| | | else: |
| | | print("没有更多视频了") |
| | | VideoManger().add_video_infos([self.__parse_video_info(v) for v in videos]) |
| | | |
| | | def close(self): |
| | | if self.driver: |
New file |
| | |
| | | """ |
| | | 评论管理 |
| | | """ |
| | | # 保存回复视频评论的用户昵称 |
| | | # {"视频名称+发布日期":{"评论用户的昵称":{"评论内容集合"}}} |
| | | import comment_util |
| | | |
| | | __reply_video_comment_user_name_dict = {} |
| | | |
| | | |
| | | def add_reply_record(video_name, video_date, comment_nick_name, comment_content): |
| | | """ |
| | | 添加评论内容 |
| | | :param video_name: |
| | | :param video_date: |
| | | :param comment_nick_name: |
| | | :return: |
| | | """ |
| | | k = f"{video_name}{video_date}" |
| | | if k not in __reply_video_comment_user_name_dict: |
| | | __reply_video_comment_user_name_dict[k] = {} |
| | | if comment_nick_name not in __reply_video_comment_user_name_dict[k]: |
| | | __reply_video_comment_user_name_dict[k][comment_nick_name] = set() |
| | | __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): |
| | | """ |
| | | 获取回复内容 |
| | | :param video_name:视频名称 |
| | | :param video_date:视频日期 |
| | | :param comment_nick_name:评论昵称 |
| | | :param comment_content:评论内容 |
| | | :return: |
| | | """ |
| | | k = f"{video_name}{video_date}" |
| | | if k not in __reply_video_comment_user_name_dict: |
| | | __reply_video_comment_user_name_dict[k] = {} |
| | | if __reply_video_comment_user_name_dict[k].get(comment_nick_name): |
| | | # 评论过了就不评论了 |
| | | return None |
| | | # 获取评论的正则表达式 |
| | | comment_templates = comment_util.get_comment_templates() |
| | | if not comment_templates: |
| | | return None |
| | | |
| | | if not comment_content: |
| | | return None |
| | | |
| | | # 替换评论内容中的img |
| | | comment_content = comment_util.replace_img_with_alt(comment_content) |
| | | |
| | | for r in comment_templates: |
| | | if r.match(r[0], comment_content): |
| | | # 能够匹配到正则表达式 |
| | | result = comment_util.load_content(r[1], comment_nick_name, comment_content) |
| | | if result: |
| | | return result |
| | | return None |
| | | |
| | | |
| | | def is_need_click_like(video_name, video_date, comment_nick_name, comment_content): |
| | | """ |
| | | 是否需要点赞 |
| | | :param video_name: |
| | | :param video_date: |
| | | :param comment_nick_name: |
| | | :param comment_content: |
| | | :return: |
| | | """ |
| | | |
| | | like_conditions = comment_util.get_like_conditions() |
| | | if not like_conditions: |
| | | return False |
| | | # 替换评论内容中的img |
| | | comment_content = comment_util.replace_img_with_alt(comment_content) |
| | | for r in like_conditions: |
| | | if r.match(r, comment_content): |
| | | # 能够匹配到正则表达式 |
| | | return True |
| | | return False |
New file |
| | |
| | | import os |
| | | import random |
| | | import re |
| | | |
| | | import setting |
| | | |
| | | |
| | | def replace_img_with_alt(html_text): |
| | | """ |
| | | 将HTML中的所有<img>标签替换为其alt属性内容 |
| | | 如果没有alt属性,则替换为空字符串或指定默认值 |
| | | """ |
| | | pattern = r'<img\b[^>]*\balt=(["\'])(.*?)\1[^>]*>|<img\b[^>]*>' |
| | | |
| | | def replacement(match): |
| | | if match.group(2): # 如果匹配到alt属性 |
| | | return match.group(2) # 返回alt属性内容 |
| | | return '' # 没有alt属性则替换为空 |
| | | |
| | | return re.sub(pattern, replacement, html_text, flags=re.IGNORECASE).strip() |
| | | |
| | | |
| | | def get_like_conditions(): |
| | | """ |
| | | 获取点赞的条件 |
| | | :return:[正则表达式,...] |
| | | """ |
| | | condition_str = setting.get_like_conditions() |
| | | return [x.split("#")[0] for x in condition_str.split("\n") if x] |
| | | |
| | | |
| | | def get_comment_templates(): |
| | | """ |
| | | 获取评论模版 |
| | | :return:[(匹配的正则, 评论的内容)] |
| | | """ |
| | | condition_str = setting.get_comment_templates() |
| | | return [(x.split("#")[0], x.split("#")[1]) for x in condition_str.split("\n") if x] |
| | | |
| | | |
| | | def __get_common_emojis(): |
| | | comment_emojis = setting.get_common_emojis() |
| | | if comment_emojis: |
| | | return re.findall("\[.*?\]", comment_emojis) |
| | | return [] |
| | | |
| | | |
| | | def __load_content(content_template, nick_name, comment_content): |
| | | """ |
| | | 加载内容 |
| | | :param content_template: |
| | | :param nick_name: |
| | | :param comment_content: |
| | | :return: |
| | | """ |
| | | # 替换表情 |
| | | pattern = r'【([\d-]+)】' |
| | | |
| | | def replacement_emojis(match): |
| | | match_str = match.group(1) |
| | | if match_str: |
| | | start = 0 |
| | | end = 0 |
| | | if match_str.find("-") >= 0: |
| | | sts = match_str.split("-") |
| | | if sts[0]: |
| | | start = int(sts[0]) |
| | | if sts[1]: |
| | | end = int(sts[1]) |
| | | else: |
| | | start = int(match_str) |
| | | end = int(match_str) |
| | | if start == 0 and end == 0: |
| | | return "" |
| | | count = random.randint(start, end) |
| | | result_str = "" |
| | | common_emojis = __get_common_emojis() |
| | | for i in range(count): |
| | | result_str += common_emojis[random.randint(0, len(common_emojis) - 1)] |
| | | return result_str # 返回alt属性内容 |
| | | return '' # 没有alt属性则替换为空 |
| | | |
| | | result = re.sub(pattern, replacement_emojis, content_template, flags=re.IGNORECASE).strip() |
| | | |
| | | comment_emojis = re.findall(r"\[.*?\]", comment_content) |
| | | last_emoji = "" |
| | | if comment_emojis: |
| | | last_emoji = comment_emojis[-1] |
| | | # 替换昵称与原内容 |
| | | result = result.replace("【昵称】", nick_name).replace("【内容】", comment_content).replace("【最后一个表情】", last_emoji) |
| | | # 替换最后一个表情 |
| | | return result |
| | | |
| | | |
| | | def load_content(content_template, nick_name, comment_content): |
| | | """ |
| | | 加载内容 |
| | | :param content_template: |
| | | :param nick_name: |
| | | :param comment_content: |
| | | :return: |
| | | """ |
| | | # 替换表情 |
| | | pattern = r'\{(.*?)\}' |
| | | |
| | | def replacement_express(match): |
| | | match_str = match.group(1) |
| | | if match_str: |
| | | # 替换或者表达式 |
| | | if match_str.find("|") >= 0: |
| | | sts = match_str.split("|") |
| | | return sts[random.randint(0, len(sts)-1)] |
| | | return match_str |
| | | return '' |
| | | |
| | | result = re.sub(pattern, replacement_express, content_template, flags=re.IGNORECASE).strip() |
| | | # 替换最后一个表情 |
| | | return __load_content(result, nick_name, comment_content) |
| | | |
| | | |
| | | if __name__ == "__main__": |
| | | print(os.getcwd()) |
| | | st = "{是的,你的观点很赞|好吧[爱心]|谢谢[抱拳]|是的[强]|确实可能有些不对[裂开]}" |
| | | comment_emojis = load_content(st,"昵称","评论内容本身") |
| | | print(comment_emojis) |
| | |
| | | import re |
| | | import threading |
| | | |
| | | import wx |
| | | |
| | | import setting |
| | | from comment import CommentManager |
| | | |
| | | |
| | | def show_warning(content, click=None): |
| | | toastone = wx.MessageDialog(None, content, "提示", wx.YES_DEFAULT | wx.ICON_WARNING) |
| | |
| | | if toastone.ShowModal() == wx.ID_YES: # 如果点击了提示框的确定按钮 |
| | | click() |
| | | toastone.Destroy() |
| | | |
| | | |
| | | class MainFrame(wx.Frame): |
| | | def __bind_event(self): |
| | |
| | | setting.set_chromedriver_path(chromedriver_path) |
| | | setting.set_comment_templates(comment_templates) |
| | | setting.set_reply_comment(comment) |
| | | setting.set_common_emojis(self.text_emojis.GetValue()) |
| | | setting.set_like_conditions(self.text_like_conditions.GetValue()) |
| | | show_info("保存成功") |
| | | |
| | | self.Bind(wx.EVT_CLOSE, self.OnFrameClose) |
| | | self.btn_start_comment.Bind(wx.EVT_BUTTON, start_comment) |
| | | self.btn_chrome_path.Bind(wx.EVT_BUTTON, on_select_chrome_file) |
| | |
| | | self.btn_save.Bind(wx.EVT_BUTTON, on_save) |
| | | |
| | | def __init(self): |
| | | self.comment_manager = None |
| | | self.cb_like.SetValue(setting.is_click_like()) |
| | | self.cb_comment.SetValue(setting.is_reply_comment()) |
| | | self.text_comments.SetValue(setting.get_comment_templates()) |
| | | self.text_chrome_path.SetValue(setting.get_chrome_path()) |
| | | self.text_chromedriver_path.SetValue(setting.get_chromedriver_path()) |
| | | self.text_emojis.SetValue(setting.get_common_emojis()) |
| | | self.text_like_conditions.SetValue(setting.get_like_conditions()) |
| | | |
| | | |
| | | |
| | | def __init__(self): |
| | | def __create_setting_view(self, panel): |
| | | def create_label(text): |
| | | return wx.StaticText(self, wx.ID_ANY, text, size=wx.Size(150, -1), style=wx.ALIGN_RIGHT) |
| | | return wx.StaticText(panel, wx.ID_ANY, text, size=wx.Size(150, -1), style=wx.ALIGN_RIGHT) |
| | | |
| | | wx.Frame.__init__(self, None, -1, "视频号助手", |
| | | size=(600, 500)) |
| | | self.SetBackgroundColour(wx.Colour(224, 224, 224)) |
| | | boxsier = wx.BoxSizer(wx.VERTICAL) |
| | | # 浏览器地址 |
| | | ss = wx.BoxSizer(wx.HORIZONTAL) |
| | | ss.Add(create_label("Chrome浏览器路径:"), 0, wx.ALIGN_CENTER_VERTICAL) |
| | | self.text_chrome_path = wx.TextCtrl(self, wx.ID_ANY, size=wx.Size(-1, -1)) |
| | | self.text_chrome_path = wx.TextCtrl(panel, wx.ID_ANY, size=wx.Size(-1, -1)) |
| | | ss.Add(self.text_chrome_path, 1, wx.RIGHT, 10) |
| | | self.btn_chrome_path = wx.Button(self, wx.ID_ANY, "选择文件") |
| | | self.btn_chrome_path = wx.Button(panel, wx.ID_ANY, "选择文件") |
| | | ss.Add(self.btn_chrome_path, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10) |
| | | boxsier.Add(ss, 0, wx.EXPAND | wx.TOP, 10) |
| | | # 浏览器驱动地址 |
| | | ss = wx.BoxSizer(wx.HORIZONTAL) |
| | | ss.Add(create_label("Chrome浏览器驱动路径:"), 0, wx.ALIGN_CENTER_VERTICAL) |
| | | self.text_chromedriver_path = wx.TextCtrl(self, wx.ID_ANY, size=wx.Size(-1, -1)) |
| | | self.text_chromedriver_path = wx.TextCtrl(panel, wx.ID_ANY, size=wx.Size(-1, -1)) |
| | | ss.Add(self.text_chromedriver_path, 1, wx.RIGHT, 10) |
| | | self.btn_chromedriver_path = wx.Button(self, wx.ID_ANY, "选择文件") |
| | | self.btn_chromedriver_path = wx.Button(panel, wx.ID_ANY, "选择文件") |
| | | ss.Add(self.btn_chromedriver_path, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10) |
| | | boxsier.Add(ss, 0, wx.EXPAND | wx.TOP, 10) |
| | | |
| | | # 是否点赞 |
| | | ss = wx.BoxSizer(wx.HORIZONTAL) |
| | | ss.Add(create_label("是否点赞:"), 0, wx.ALIGN_CENTER_VERTICAL) |
| | | self.cb_like = wx.CheckBox(self, wx.ID_ANY, "") |
| | | self.cb_like = wx.CheckBox(panel, wx.ID_ANY, "") |
| | | ss.Add(self.cb_like, 0, wx.ALIGN_CENTER_VERTICAL) |
| | | boxsier.Add(ss, 0, wx.EXPAND | wx.TOP, 10) |
| | | |
| | | # 是否评论 |
| | | ss = wx.BoxSizer(wx.HORIZONTAL) |
| | | ss.Add(create_label("是否评论:"), 0, wx.ALIGN_CENTER_VERTICAL) |
| | | self.cb_comment = wx.CheckBox(self, wx.ID_ANY, "") |
| | | self.cb_comment = wx.CheckBox(panel, wx.ID_ANY, "") |
| | | ss.Add(self.cb_comment, 0, wx.ALIGN_CENTER_VERTICAL) |
| | | boxsier.Add(ss, 0, wx.EXPAND | wx.TOP, 10) |
| | | |
| | | # 常用表情 |
| | | ss = wx.BoxSizer(wx.HORIZONTAL) |
| | | ss.Add(create_label("常用表情:"), 0) |
| | | self.text_emojis = wx.TextCtrl(panel, wx.ID_ANY, size=wx.Size(-1, 50), style=wx.TE_MULTILINE) |
| | | ss.Add(self.text_emojis, 1, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10) |
| | | boxsier.Add(ss, 0, wx.EXPAND | wx.TOP, 10) |
| | | |
| | | # 评论内容 |
| | | ss = wx.BoxSizer(wx.HORIZONTAL) |
| | | ss.Add(create_label("评论模版:"), 0) |
| | | self.text_comments = wx.TextCtrl(self, wx.ID_ANY, size=wx.Size(-1, 150), style=wx.TE_MULTILINE) |
| | | self.text_comments = wx.TextCtrl(panel, wx.ID_ANY, size=wx.Size(-1, 150), style=wx.TE_MULTILINE) |
| | | ss.Add(self.text_comments, 1, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10) |
| | | boxsier.Add(ss, 0, wx.EXPAND | wx.TOP, 10) |
| | | boxsier.Add(wx.StaticText(self, wx.ID_ANY, "模版与内容之间采用#分隔,如: 谢谢$#[昵称]不客气\n变量:[昵称]\n备注:$-结尾 ^-开始"), 0, wx.LEFT, |
| | | boxsier.Add(wx.StaticText(panel, wx.ID_ANY, "模版与内容之间采用#分隔,如: 谢谢$#[昵称]不客气\n变量:【昵称】,【内容】,【最后一个表情】,【1-3】\n备注:$-结尾 ^-开始"), 0, wx.LEFT, |
| | | 150) |
| | | |
| | | self.btn_save = wx.Button(self, wx.ID_ANY, "保存") |
| | | boxsier.Add(create_label("")) |
| | | boxsier.Add(self.btn_save, 0, wx.LEFT, 150) |
| | | # 点赞条件 |
| | | ss = wx.BoxSizer(wx.HORIZONTAL) |
| | | ss.Add(create_label("点赞条件:"), 0) |
| | | self.text_like_conditions = wx.TextCtrl(panel, wx.ID_ANY, size=wx.Size(-1, 80), style=wx.TE_MULTILINE) |
| | | ss.Add(self.text_like_conditions, 1, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10) |
| | | boxsier.Add(ss, 0, wx.EXPAND | wx.TOP, 10) |
| | | |
| | | self.btn_start_comment = wx.Button(self, wx.ID_ANY, "开始") |
| | | boxsier.Add(self.btn_start_comment) |
| | | self.SetSizer(boxsier) |
| | | ss = wx.BoxSizer(wx.HORIZONTAL) |
| | | self.btn_save = wx.Button(panel, wx.ID_ANY, "保存") |
| | | ss.Add(self.btn_save, 0, wx.LEFT, 150) |
| | | boxsier.Add(ss, 0, wx.EXPAND | wx.TOP, 10) |
| | | |
| | | panel.SetSizer(boxsier) |
| | | |
| | | def __create_test_view(self, panel): |
| | | def create_label(text): |
| | | return wx.StaticText(panel, wx.ID_ANY, text, size=wx.Size(80, -1), style=wx.ALIGN_RIGHT) |
| | | |
| | | def on_excute(evt): |
| | | # pattern = self.test_regex.GetValue().encode('unicode_escape').decode("utf-8") |
| | | pattern = self.test_regex.GetValue() |
| | | |
| | | |
| | | |
| | | regex = re.compile(pattern) |
| | | content = self.test_text.GetValue() |
| | | result = regex.match(content) |
| | | result_list=[] |
| | | if result: |
| | | result_list.append("是否匹配:匹配") |
| | | else: |
| | | result_list.append("是否匹配:不匹配") |
| | | result = regex.findall(content) |
| | | result_list.append("匹配内容:" + ",".join(result)) |
| | | self.test_result.SetValue("\n".join(result_list)) |
| | | |
| | | |
| | | boxsier = wx.BoxSizer(wx.VERTICAL) |
| | | ss = wx.BoxSizer(wx.HORIZONTAL) |
| | | ss.Add(create_label("正则表达式:"), 0, wx.ALIGN_CENTER_VERTICAL) |
| | | self.test_regex = wx.TextCtrl(panel, wx.ID_ANY, size=wx.Size(-1, -1)) |
| | | ss.Add(self.test_regex, 1, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10) |
| | | boxsier.Add(ss, 0, wx.EXPAND | wx.TOP, 10) |
| | | |
| | | ss = wx.BoxSizer(wx.HORIZONTAL) |
| | | ss.Add(create_label("内容:"), 0) |
| | | self.test_text = wx.TextCtrl(panel, wx.ID_ANY, size=wx.Size(-1, 100),style=wx.TE_MULTILINE) |
| | | ss.Add(self.test_text, 1, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10) |
| | | boxsier.Add(ss, 0, wx.EXPAND | wx.TOP, 10) |
| | | |
| | | ss = wx.BoxSizer(wx.HORIZONTAL) |
| | | ss.Add(create_label("结果:"), 0) |
| | | self.test_result = wx.TextCtrl(panel, wx.ID_ANY, size=wx.Size(-1, 100), style=wx.TE_READONLY|wx.TE_MULTILINE) |
| | | ss.Add(self.test_result, 1, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10) |
| | | boxsier.Add(ss, 0, wx.EXPAND | wx.TOP, 10) |
| | | |
| | | ss = wx.BoxSizer(wx.HORIZONTAL) |
| | | ss.Add(create_label(""), 0, wx.ALIGN_CENTER_VERTICAL) |
| | | self.test_excute = wx.Button(panel, wx.ID_ANY, "执行测试") |
| | | ss.Add(self.test_excute, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10) |
| | | boxsier.Add(ss, 0, wx.EXPAND | wx.TOP, 10) |
| | | self.test_excute.Bind(wx.EVT_BUTTON, on_excute) |
| | | |
| | | panel.SetSizer(boxsier) |
| | | |
| | | def __init__(self): |
| | | |
| | | wx.Frame.__init__(self, None, -1, "视频号助手", |
| | | size=(900, 600)) |
| | | self.SetBackgroundColour(wx.Colour(224, 224, 224)) |
| | | |
| | | root_sizer = wx.FlexGridSizer(2, 2, 10, 10) |
| | | # ------设置页面------ |
| | | panel_setting = wx.Panel(self, wx.ID_ANY, size=wx.Size(500, -1)) |
| | | self.__create_setting_view(panel_setting) |
| | | root_sizer.Add(panel_setting) |
| | | |
| | | # ------测试界面------ |
| | | panel_test = wx.Panel(self, wx.ID_ANY, size=wx.Size(300, 400)) |
| | | self.__create_test_view(panel_test) |
| | | root_sizer.Add(panel_test) |
| | | |
| | | # ------执行页面------ |
| | | panel_action = wx.Panel(self, wx.ID_ANY, size=wx.Size(500, 100)) |
| | | self.btn_start_comment = wx.Button(panel_action, wx.ID_ANY, "开始") |
| | | root_sizer.Add(panel_action) |
| | | |
| | | self.SetSizer(root_sizer) |
| | | self.__init() |
| | | self.__bind_event() |
| | | |
New file |
| | |
| | | .*不对.*#{是的,你的观点很赞|好吧[爱心]|谢谢[抱拳]|是的[强]|确实可能有些不对[裂开]} |
| | | .*对.*|.*支持.*|.*没毛病.*|.*一样.*|.*没错.*|.*有道理.*#{感谢你的认同|感谢你的评价|谢谢你的认同|感恩你的认同|谢谢你的评论|感恩你的认可|是的,你说的没错|你的认同我很感激}{【1-3】} |
| | | .*太少了.*#{是的,确实不多}{【1-3】} |
| | | |
| | |
| | | [config] |
| | | comment_templates = 测试234234你好234234 |
| | | comment_templates = [*]$#[*] |
| | | 不对# |
| | | 对# |
| | | ^你#123123 |
| | | reply_comment = 1 |
| | | click_like = 1 |
| | | chromedriver_path = D:\workspace\python\wechat_helper\chromedriver.exe |
| | | chrome_path = D:\workspace\python\wechat_helper\chromedriver.exe |
| | | common_emojis = [爱心] [合十] [拥抱] [抱拳] [强] [玫瑰] [胜利] [666] [呲牙] [愉快] |
| | | like_conditions = [\u4e00-\u9fa5]{2,}#最少2个字中文 |
| | | |
| | |
| | | return cp.get("config", "comment_templates") |
| | | |
| | | |
| | | # -------------------------------常用表情-------------------------- |
| | | def set_common_emojis(content): |
| | | # 设置是否置顶 |
| | | cp = __read_setting() |
| | | cp.set("config", "common_emojis", content) |
| | | __write_setting(cp) |
| | | |
| | | |
| | | # 获取是否置顶 |
| | | def get_common_emojis(): |
| | | try: |
| | | cp = __read_setting() |
| | | return cp.get("config", "common_emojis") |
| | | except: |
| | | return "" |
| | | |
| | | |
| | | # -------------------------------点赞条件-------------------------- |
| | | def set_like_conditions(content): |
| | | # 设置是否置顶 |
| | | cp = __read_setting() |
| | | cp.set("config", "like_conditions", content) |
| | | __write_setting(cp) |
| | | |
| | | |
| | | # 获取是否置顶 |
| | | def get_like_conditions(): |
| | | try: |
| | | cp = __read_setting() |
| | | return cp.get("config", "like_conditions") |
| | | except: |
| | | return "" |
| | | |
| | | if __name__ == "__main__": |
| | | pass |
New file |
| | |
| | | |
| | | def singleton(cls): |
| | | """ |
| | | 单例装饰器 |
| | | @param cls: |
| | | @return: |
| | | """ |
| | | instances = {} |
| | | |
| | | def get_instance(*args, **kwargs): |
| | | if cls not in instances: |
| | | instances[cls] = cls(*args, **kwargs) |
| | | return instances[cls] |
| | | |
| | | return get_instance |
New file |
| | |
| | | import os |
| | | import time |
| | | |
| | | import tool |
| | | |
| | | |
| | | @tool.singleton |
| | | class VideoManger: |
| | | __video_cache_path = "datas/videos.json" |
| | | # {"视频内容+视频时间":(评论数量,更新时间)} |
| | | __video_data_cache_dict = {} |
| | | |
| | | def __init__(self): |
| | | |
| | | if os.path.exists(self.__video_cache_path): |
| | | with open(self.__video_cache_path, encoding="utf-8", mode='r') as f: |
| | | lines = f.readlines() |
| | | if lines: |
| | | self.__video_data_cache_dict = eval(lines[0]) |
| | | |
| | | def is_need_click(self, video_name, video_time, comment_count): |
| | | """ |
| | | 是否需要点击 |
| | | :param video_name: 视频名称 |
| | | :param video_time: 视频时间 |
| | | :param comment_count: 评论数量 |
| | | :return: |
| | | """ |
| | | 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: |
| | | return True |
| | | return False |
| | | |
| | | def add_video_infos(self, video_infos): |
| | | """ |
| | | 添加视频信息 |
| | | :param video_infos: |
| | | :return: |
| | | """ |
| | | print("保存所有视频内容") |
| | | self.__video_data_cache_dict = {f"{x[0]}{x[1]}": (x[2], time.time()) for x in video_infos} |
| | | # 保存到文件 |
| | | with open(self.__video_cache_path, encoding="utf-8", mode='w') as f: |
| | | f.write(f"{self.__video_data_cache_dict}") |
| | | |