去重合并Mihomo的去广告规则

本教程旨在提供最详尽的指导,帮助没有任何编程基础的你也能使用 monitor.bat 脚本和 Python 脚本来自动化更新 Mihomo 广告拦截规则。

重要提示: 在开始之前,请确保你已经下载或创建了以下文件:

  • process_rules.py (可以自动添加和修改文件名后缀)。
  • monitor.bat (你需要按照教程中的说明创建)。
  • Mihomo 的 Windows 可执行文件 (mihomo-windows-amd64.exe 或类似名称)。

第一步:准备所需的 Python 脚本

  • process_rules.py (可以自动添加和修改文件名后缀)

    1. 打开一个纯文本编辑器,例如 Windows 自带的“记事本”(Notepad)。

    2. 复制粘贴下面的代码到这个空白的文本文件中:

      import sys
      import yaml
      import requests
      import os
      from urllib.parse import urlparse

      def sanitize_filename(url):
      """从 URL 生成安全的文件名。"""
      parsed_url = urlparse(url)
      path = parsed_url.path.strip('/')
      name = os.path.basename(path)
      return name

      def download_file(url, save_path):
      """从 URL 下载文件并保存到指定路径。"""
      try:
      response = requests.get(url, stream=True)
      response.raise_for_status()
      with open(save_path, 'wb') as file:
      for chunk in response.iter_content(chunk_size=8192):
      file.write(chunk)
      print(f"成功下载文件到: {save_path}")
      return True
      except requests.exceptions.RequestException as e:
      print(f"下载文件失败: {e}")
      return False

      def load_yaml_data(filepath):
      """加载 YAML 文件数据。"""
      try:
      with open(filepath, 'r', encoding='utf-8') as f:
      data = yaml.safe_load(f) or {}
      # print(f"成功加载文件: {filepath}")
      # print(f"加载到的数据: {data}")
      return data
      except FileNotFoundError:
      print(f"错误:文件 {filepath} 未找到。")
      return None
      except yaml.YAMLError as e:
      print(f"错误:解析 YAML 文件 {filepath} 时发生错误:{e}")
      return None

      def merge_and_process_yaml(temp_files, output_file, custom_rules_str=None, custom_delimiter="|||"):
      """
      合并多个 YAML 文件中 'payload' 列表的内容,去除重复项(忽略通配符),
      确保最终规则都带有通配符 +. 前缀(如果适用),并添加自定义规则。
      """
      all_raw_payload = []

      for filepath in temp_files:
      data = load_yaml_data(filepath)
      if data and 'payload' in data and isinstance(data['payload'], list):
      all_raw_payload.extend(data['payload'])
      print(f"从 {filepath} 中提取到的 payload 数量: {len(data['payload'])}")
      else:
      print(f"在 {filepath} 中未找到 'payload' 键或文件加载失败。")

      if custom_rules_str:
      custom_rules = [rule.strip() for rule in custom_rules_str.split(custom_delimiter) if rule.strip()]
      all_raw_payload.extend(custom_rules)
      print(f"添加自定义规则数量: {len(custom_rules)}")

      normalized_payload = []
      original_format = {}

      for rule in all_raw_payload:
      if isinstance(rule, str):
      normalized_rule = rule.lstrip("+. ") # 去除可能的 +. 和空格
      normalized_payload.append(normalized_rule)
      original_format.setdefault(normalized_rule, []).append(rule)

      deduplicated_normalized = sorted(list(set(normalized_payload)))
      print(f"标准化后去重的 payload 数量: {len(deduplicated_normalized)}")

      final_payload = []
      for rule in deduplicated_normalized:
      if any(orig_rule.startswith("+.") for orig_rule in original_format.get(rule, [])):
      final_payload.append(f"+.{rule}")
      else:
      final_payload.append(f"+.{rule}") # 强制添加通配符

      print(f"最终处理后的 payload 数量: {len(final_payload)}")

      output_yaml_file = output_file
      output_data = {'payload': sorted(list(set(final_payload)))} # 再次去重以防万一
      with open(output_yaml_file, 'w', encoding='utf-8') as outfile:
      yaml.dump(output_data, outfile, sort_keys=False, allow_unicode=True)
      print(f"成功合并、去重、添加通配符并添加自定义规则,结果已保存到 {output_yaml_file}")

      def delete_rules_by_keyword_from_yaml(yaml_file, keywords_to_delete_str, delimiter="|||"):
      """
      从 YAML 文件中删除 payload 列表中包含指定关键字的整行规则。

      Args:
      yaml_file (str): YAML 文件的路径。
      keywords_to_delete_str (str): 要删除的关键字字符串,用 delimiter 分隔。
      delimiter (str): 分隔符,默认为 "|||".
      """
      keywords_to_delete = keywords_to_delete_str.split(delimiter)
      deleted_count = 0

      try:
      data = load_yaml_data(yaml_file)

      if data and 'payload' in data and isinstance(data['payload'], list):
      initial_rule_count = len(data['payload'])
      new_payload = []
      for rule in data['payload']:
      should_keep = True
      if isinstance(rule, str):
      for keyword in keywords_to_delete:
      if keyword in rule:
      should_keep = False
      print(f"找到包含关键字 '{keyword}' 的规则并准备删除: {rule}")
      deleted_count += 1
      break
      if should_keep:
      new_payload.append(rule)
      data['payload'] = new_payload

      with open(yaml_file, 'w', encoding='utf-8') as f:
      yaml.dump(data, f, sort_keys=False, allow_unicode=True)

      if deleted_count > 0:
      print(f"成功从 {yaml_file} 中删除了 {deleted_count} 条包含指定关键字的规则。")
      else:
      print(f"在 {yaml_file} 中未找到任何包含指定关键字的规则。")
      else:
      print(f"YAML 文件 {yaml_file} 结构不符合预期,无法找到规则列表。")

      except FileNotFoundError:
      print(f"错误:文件 {yaml_file} 未找到。")
      except yaml.YAMLError as e:
      print(f"错误:解析 YAML 文件 {yaml_file} 时发生错误:{e}")

      if __name__ == "__main__":
      if len(sys.argv) >= 4:
      operation = sys.argv[1].lower()
      output_file = sys.argv[2]

      if operation == "merge":
      num_urls = len(sys.argv) - 5
      if num_urls < 0:
      num_urls = 0
      urls = sys.argv[3 : 3 + num_urls]
      custom_rules = sys.argv[3 + num_urls] if len(sys.argv) > 3 + num_urls else None
      custom_delimiter = sys.argv[4 + num_urls] if len(sys.argv) > 4 + num_urls else "|||"

      print(f"下载 URLs: {urls}")
      print(f"自定义规则: {custom_rules}")
      print(f"自定义分隔符: {custom_delimiter}")

      temp_files = []
      download_successful = True
      for i, url in enumerate(urls):
      temp_file = f"temp_file_{i+1}_{sanitize_filename(url)}"
      temp_files.append(temp_file)
      if not download_file(url, temp_file):
      download_successful = False
      break

      if download_successful:
      merge_and_process_yaml(temp_files, output_file, custom_rules, custom_delimiter)
      for temp_file in temp_files:
      os.remove(temp_file)
      print("临时文件已删除。")
      else:
      print("部分文件下载失败,无法执行合并、去重、添加通配符和自定义规则。")

      elif operation == "delete_keyword":
      if len(sys.argv) >= 4:
      keywords_to_delete_str = sys.argv[3]
      delimiter = sys.argv[4] if len(sys.argv) > len(sys.argv) else "|||"
      delete_rules_by_keyword_from_yaml(output_file, keywords_to_delete_str, delimiter)
      else:
      print("用法: python process_rules.py delete_keyword <yaml_file> <keywords_to_delete_separated_by_delimiter> [delimiter]")

      else:
      print("用法: python process_rules.py [merge|delete_keyword] <output_file> <arguments...> [custom_rules] [custom_delimiter]")
      print(" merge <output_file>.yaml <url1> <url2> ... <custom_rules> [custom_delimiter]")
      print(" delete_keyword <yaml_file>.yaml <keywords_to_delete_separated_by_delimiter> [delimiter]")

      else:
      print("用法: python process_rules.py [merge|delete_keyword] <output_file> <arguments...> [custom_rules] [custom_delimiter]")
      print(" merge <output_file>.yaml <url1> <url2> ... <custom_rules> [custom_delimiter]")
      print(" delete_keyword <output_file>.yaml <keywords_to_delete_separated_by_delimiter> [delimiter]")
    3. 按照之前的说明,将这段代码保存为 process_rules.py

  • 运行 process_rules.py 之前,你需要确保你的计算机上安装了 Python,并且安装了 PyYAMLrequests 这两个第三方库。

    • 安装方法:
      1. 按下 Windows 键,在搜索框中输入 cmd,然后按回车键打开“命令提示符”窗口。
      2. 在命令提示符窗口中,输入 python --version,然后按回车键。如果看到 Python 的版本信息,说明 Python 已安装。如果提示找不到命令,请按照以下步骤安装 Python。
      3. 打开你的网页浏览器,访问 Python 的官方网站:https://www.python.org/downloads/
      4. 下载最新的 Python 3 版本。
      5. 运行安装程序,务必勾选 “Add Python to PATH“ 选项,然后点击 “Install Now“。
      6. 安装完成后,重新打开“命令提示符”窗口,再次输入 python --version 检查是否安装成功。
      7. 在“命令提示符”窗口中,输入以下命令并按回车键安装 PyYAML
        pip install pyyaml
      8. 等待安装完成后,输入以下命令并按回车键安装 requests
        pip install requests

第二步:创建 monitor.bat (批处理脚本)

  1. 打开一个纯文本编辑器,例如 Windows 自带的“记事本”(Notepad)。

  2. 复制粘贴下面的代码到这个空白的文本文件中。请仔细阅读代码中的注释,并根据你的实际情况修改变量。

    @echo off
    chcp 65001 > nul
    REM 设置输出的 YAML 文件路径和名称。你可以根据你的喜好修改。
    set "output_file=C:\MihomoRules\adblock.yaml"
    REM 设置输出的 Mihomo 规则文件 (.mrs) 路径和名称。建议与上面的 YAML 文件放在同一个目录下。
    set "output_mrs_domain=C:\MihomoRules\adblock.mrs"
    REM 设置你保存的 Python 脚本 (process_rules.py) 的完整路径。请根据你保存的实际位置修改。
    set "python_script=C:\MihomoTools\process_rules.py"
    REM 填写你要下载的广告拦截规则列表的网址。你可以添加更多行,例如 set "url4=..."
    set "url1=你的第一个规则列表URL"
    set "url2=你的第二个规则列表URL"
    set "url3=你的第三个规则列表URL"
    REM 设置 Mihomo 可执行文件的完整路径。请根据你 Mihomo 程序的实际位置修改。
    set "mihomo_path=C:\Mihomo\mihomo-windows-amd64.exe"
    REM 设置想要添加的自定义规则,多个规则之间用 ||| 分隔。
    REM 规则的格式通常是 "example.com"。
    REM 如果你不想增加任何规则,请将等号后面的内容留空
    set "custom_rules=domain1.com|||domain2.net"
    REM 设置增加规则时使用的分隔符,通常不需要修改。
    set "custom_delimiter=|||"
    REM 设置你想要从合并后的规则中删除的特定规则。多个规则之间用 ||| 分隔。
    REM 规则的格式通常是 "example.com"。
    REM 如果你不想删除任何规则,请将等号后面的内容留空。
    set "rules_to_remove=unwanted1.com|||unwanted2.net"
    REM 设置删除规则时使用的分隔符,通常不需要修改。
    set "delimiter=|||"

    echo 正在下载、合并、去重、添加通配符并添加自定义规则...
    REM 调用 Python 脚本执行合并操作,并将下载链接和输出文件名作为参数传递。
    python "%python_script%" merge "%output_file%" "%url1%" "%url2%" "%url3%" "%custom_rules%" "%custom_delimiter%"

    echo 正在删除 YAML 文件中包含指定关键字的规则...
    REM 检查是否设置了要删除的规则,如果设置了,则调用 Python 脚本执行删除操作。
    if not "%rules_to_remove%"=="" (
    python "%python_script%" delete_keyword "%output_file%" "%rules_to_remove%" "%delimiter%"
    ) else (
    echo 跳过删除规则,因为 rules_to_remove 为空。
    )

    echo 正在将 YAML 文件转换为 .mrs 文件...
    REM 调用 Mihomo 程序将 YAML 格式的规则文件转换为 .mrs 格式。
    "%mihomo_path%" convert-ruleset domain yaml "%output_file%" "%output_mrs_domain%"

    echo 正在删除临时 YAML 文件...
    REM 删除中间生成的 YAML 文件,只保留最终的 .mrs 文件。
    del "%output_file%"

    echo 操作完成。
  3. 在“记事本”中,点击“文件” -> “保存”。

  4. 在弹出的“另存为”窗口中:

    • 选择一个你容易找到的保存位置,例如你保存 process_rules.py 的文件夹(例如 C:\MihomoTools)。
    • 在“文件名”框中,输入 monitor.bat(请务必输入 .bat 后缀)。
    • 在“保存类型”下拉菜单中,选择“所有文件 (.)”。
    • 点击“保存”。

第三步:准备 Mihomo 可执行文件

  • 你需要下载 Mihomo 的 Windows 版本。通常文件名类似于 mihomo-windows-amd64.exe。你可以从 Mihomo 的官方渠道或者你信任的来源下载。
  • 将这个可执行文件放到你在 monitor.bat 脚本中 mihomo_path 变量设置的路径。例如,如果 mihomo_path 设置为 C:\Mihomo\mihomo-windows-amd64.exe,那么你需要将下载的 Mihomo 程序放到 C:\Mihomo 文件夹中。如果 C:\Mihomo 文件夹不存在,你需要先创建它。

第四步:配置 monitor.bat 脚本

现在,请再次打开你刚刚创建的 monitor.bat 文件,仔细检查并修改以下变量,确保它们指向你电脑上的正确位置和你想要使用的规则列表:

  • set "output_file=C:\MihomoRules\adblock.yaml": 确认这是你想要保存合并后 YAML 规则文件的路径。如果 C:\MihomoRules 文件夹不存在,你需要先创建它,或者修改为你电脑上已有的文件夹。
  • set "output_mrs_domain=C:\MihomoRules\adblock.mrs": 确认这是你想要保存最终 .mrs 规则文件的路径。
  • set "python_script=C:\MihomoTools\process_rules.py": 非常重要! 确保这个路径指向你实际保存的 process_rules.py 文件。如果你的 Python 脚本和 monitor.bat 在同一个文件夹,你可以只写文件名,例如 set "python_script=merge_rules.py"
  • set "url1=你的第一个规则列表URL"set "url2=你的第二个规则列表URL"set "url3=你的第三个规则列表URL":你的第一个规则列表URL 等替换为你想要使用的广告拦截规则的网络地址。这些地址通常以 http://https:// 开头。你可以添加更多 set "url4=新的URL" 这样的行来添加更多规则来源。
  • set "mihomo_path=C:\Mihomo\mihomo-windows-amd64.exe": 确认这个路径指向你下载的 Mihomo 可执行文件。
  • set "custom_rules=domain1.com|||domain2.net": 根据你的需要修改要增加的规则。如果你不确定要增加哪些规则,可以暂时保持默认或者将等号后面的内容清空 (set "custom_rules=")。
  • set "rules_to_remove=unwanted1.com|||unwanted2.net: 根据你的需要修改要删除的规则。如果你不确定要删除哪些规则,可以暂时保持默认或者将等号后面的内容清空 (set "rules_to_remove=")。

第五步:运行 monitor.bat 脚本 (手动执行)

当你仔细配置完 monitor.bat 文件后,你可以尝试手动运行它,看看是否一切正常:

  1. 找到你保存 monitor.bat 文件的位置。
  2. 双击 monitor.bat 文件。
  3. 一个黑色的“命令提示符”窗口会弹出,显示脚本正在执行的步骤。
  4. 仔细观察窗口中显示的信息。如果一切顺利,你应该会看到下载文件成功、合并去重成功、删除规则成功(如果设置了)、转换为 .mrs 文件成功、删除临时 YAML 文件成功的提示,最后会显示“操作完成。”并等待你按下任意键关闭窗口。
  5. 如果脚本运行过程中出现错误,请仔细阅读命令提示符窗口中显示的错误信息。这通常会告诉你问题出在哪里(例如找不到文件、网络连接失败等)。根据错误信息检查你的文件路径和网络连接,然后再次尝试运行 monitor.bat
  6. 运行成功后,请检查你在 output_mrs_domain 变量中设置的路径,看看是否生成了 .mrs 文件。

第六步:配置 Mihomo 使用新的规则

你需要告诉 Mihomo 使用你刚刚生成的 .mrs 文件。具体的操作方法会根据你使用的 Mihomo 版本和配置方式有所不同。通常你需要在 Mihomo 的设置中找到“规则集”或类似的选项,然后指定你生成的 .mrs 文件的路径。请参考 Mihomo 的官方文档或相关教程来完成这一步。

第七步:自动化运行 monitor.bat 脚本 (计划任务)

如果你希望 monitor.bat 脚本能够按照你设定的时间自动运行(例如每天凌晨自动更新规则),你需要使用 Windows 的 任务计划程序

  1. 打开任务计划程序:

    • 点击 Windows 任务栏上的“开始”按钮。
    • 在搜索框中输入“任务计划程序”,然后点击搜索结果中的“任务计划程序”。
  2. 创建基本任务:

    • 在任务计划程序窗口的右侧面板中,找到并点击“创建基本任务…”。
    • 在“名称”框中,为你的自动化任务输入一个易于识别的名称,例如“自动更新 Mihomo 规则”。点击“下一步”。
  3. 设置触发器 (计划运行时间):

    • 选择你希望脚本运行的频率(例如“每天”、“每周”)。点击“下一步”。
    • 根据你选择的频率,设置具体的开始时间(例如每天凌晨 3:00)。点击“下一步”。
  4. 设置操作 (要运行的程序):

    • 选择“启动程序”,然后点击“下一步”。
    • 在“程序或脚本”框中,点击“浏览…”按钮,找到并选择你保存的 monitor.bat 文件,然后点击“打开”。
    • “添加参数(可选)” 和 “起始于(可选)” 框通常可以留空。点击“下一步”。
  5. 完成:

    • 检查任务摘要,确认设置无误后点击“完成”。

高级设置 (可选但推荐):

为了让自动化任务更稳定可靠,你可以进行一些高级设置:

  1. 在任务计划程序中,找到你创建的任务(通常在“任务计划程序库”中)。
  2. 右键点击该任务,选择“属性”。
  3. 在“常规”选项卡中:
    • 勾选 “不管用户是否登录都要运行“。
    • 你可能需要配置“配置用户帐户”为你的当前用户。
    • 勾选 “使用最高权限运行“ (如果你的脚本需要管理员权限,但通常这个脚本不需要)。
  4. 在“触发器”选项卡中,你可以更详细地配置运行时间。
  5. 在“操作”选项卡中,确认显示的是你选择的 monitor.bat 文件。
  6. 在“条件”选项卡中,你可以设置一些条件,例如只有在计算机空闲时才运行。
  7. 在“设置”选项卡中,你可以配置任务失败时的重试次数、允许任务运行的最长时间等。建议勾选 “如果任务失败,则在…分钟后重新启动“,并设置合理的重试次数和间隔。

完成这些设置后,monitor.bat 脚本就会按照你设定的计划自动运行,下载并更新你的 Mihomo 规则。你可以在任务计划程序中随时查看、编辑或禁用这个任务。

常见问题解答:

  • 运行 monitor.bat 时提示找不到文件?
    • 请仔细检查 monitor.bat 脚本中所有文件路径的设置 (output_file, output_mrs_domain, python_script, mihomo_path) 是否指向你电脑上的实际位置。
  • Python 脚本报错?
    • 请确保你已经正确安装了 Python,并且安装了 PyYAMLrequests 这两个库。检查命令提示符窗口中的错误信息,这会告诉你具体的错误原因。
  • 下载规则列表失败?
    • 请检查你提供的规则列表 URL 是否正确,并且你的电脑可以正常访问这些网址。
  • .mrs 文件没有更新?
    • 请检查 monitor.bat 脚本是否成功执行到转换 .mrs 文件的步骤,并且 Mihomo 的路径设置正确。
  • 自动化任务没有按计划运行?
    • 请打开任务计划程序,检查你创建的任务的状态是否为“准备就绪”或“正在运行”。查看“上次运行结果”列是否有错误代码。检查任务的“触发器”设置是否正确。