去重合并Mihomo的去广告规则
本教程旨在提供最详尽的指导,帮助没有任何编程基础的你也能使用 monitor.bat
脚本和 Python 脚本来自动化更新 Mihomo 广告拦截规则。
重要提示: 在开始之前,请确保你已经下载或创建了以下文件:
process_rules.py
(可以自动添加和修改文件名后缀)。monitor.bat
(你需要按照教程中的说明创建)。- Mihomo 的 Windows 可执行文件 (
mihomo-windows-amd64.exe
或类似名称)。
第一步:准备所需的 Python 脚本
process_rules.py
(可以自动添加和修改文件名后缀)打开一个纯文本编辑器,例如 Windows 自带的“记事本”(Notepad)。
复制粘贴下面的代码到这个空白的文本文件中:
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]")按照之前的说明,将这段代码保存为
process_rules.py
。
运行
process_rules.py
之前,你需要确保你的计算机上安装了 Python,并且安装了PyYAML
和requests
这两个第三方库。- 安装方法:
- 按下 Windows 键,在搜索框中输入
cmd
,然后按回车键打开“命令提示符”窗口。 - 在命令提示符窗口中,输入
python --version
,然后按回车键。如果看到 Python 的版本信息,说明 Python 已安装。如果提示找不到命令,请按照以下步骤安装 Python。 - 打开你的网页浏览器,访问 Python 的官方网站:https://www.python.org/downloads/
- 下载最新的 Python 3 版本。
- 运行安装程序,务必勾选 “Add Python to PATH“ 选项,然后点击 “Install Now“。
- 安装完成后,重新打开“命令提示符”窗口,再次输入
python --version
检查是否安装成功。 - 在“命令提示符”窗口中,输入以下命令并按回车键安装
PyYAML
:pip install pyyaml
- 等待安装完成后,输入以下命令并按回车键安装
requests
:pip install requests
- 按下 Windows 键,在搜索框中输入
- 安装方法:
第二步:创建 monitor.bat
(批处理脚本)
打开一个纯文本编辑器,例如 Windows 自带的“记事本”(Notepad)。
复制粘贴下面的代码到这个空白的文本文件中。请仔细阅读代码中的注释,并根据你的实际情况修改变量。
@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 操作完成。在“记事本”中,点击“文件” -> “保存”。
在弹出的“另存为”窗口中:
- 选择一个你容易找到的保存位置,例如你保存
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
文件后,你可以尝试手动运行它,看看是否一切正常:
- 找到你保存
monitor.bat
文件的位置。 - 双击
monitor.bat
文件。 - 一个黑色的“命令提示符”窗口会弹出,显示脚本正在执行的步骤。
- 仔细观察窗口中显示的信息。如果一切顺利,你应该会看到下载文件成功、合并去重成功、删除规则成功(如果设置了)、转换为
.mrs
文件成功、删除临时 YAML 文件成功的提示,最后会显示“操作完成。”并等待你按下任意键关闭窗口。 - 如果脚本运行过程中出现错误,请仔细阅读命令提示符窗口中显示的错误信息。这通常会告诉你问题出在哪里(例如找不到文件、网络连接失败等)。根据错误信息检查你的文件路径和网络连接,然后再次尝试运行
monitor.bat
。 - 运行成功后,请检查你在
output_mrs_domain
变量中设置的路径,看看是否生成了.mrs
文件。
第六步:配置 Mihomo 使用新的规则
你需要告诉 Mihomo 使用你刚刚生成的 .mrs
文件。具体的操作方法会根据你使用的 Mihomo 版本和配置方式有所不同。通常你需要在 Mihomo 的设置中找到“规则集”或类似的选项,然后指定你生成的 .mrs
文件的路径。请参考 Mihomo 的官方文档或相关教程来完成这一步。
第七步:自动化运行 monitor.bat
脚本 (计划任务)
如果你希望 monitor.bat
脚本能够按照你设定的时间自动运行(例如每天凌晨自动更新规则),你需要使用 Windows 的 任务计划程序。
打开任务计划程序:
- 点击 Windows 任务栏上的“开始”按钮。
- 在搜索框中输入“任务计划程序”,然后点击搜索结果中的“任务计划程序”。
创建基本任务:
- 在任务计划程序窗口的右侧面板中,找到并点击“创建基本任务…”。
- 在“名称”框中,为你的自动化任务输入一个易于识别的名称,例如“自动更新 Mihomo 规则”。点击“下一步”。
设置触发器 (计划运行时间):
- 选择你希望脚本运行的频率(例如“每天”、“每周”)。点击“下一步”。
- 根据你选择的频率,设置具体的开始时间(例如每天凌晨 3:00)。点击“下一步”。
设置操作 (要运行的程序):
- 选择“启动程序”,然后点击“下一步”。
- 在“程序或脚本”框中,点击“浏览…”按钮,找到并选择你保存的
monitor.bat
文件,然后点击“打开”。 - “添加参数(可选)” 和 “起始于(可选)” 框通常可以留空。点击“下一步”。
完成:
- 检查任务摘要,确认设置无误后点击“完成”。
高级设置 (可选但推荐):
为了让自动化任务更稳定可靠,你可以进行一些高级设置:
- 在任务计划程序中,找到你创建的任务(通常在“任务计划程序库”中)。
- 右键点击该任务,选择“属性”。
- 在“常规”选项卡中:
- 勾选 “不管用户是否登录都要运行“。
- 你可能需要配置“配置用户帐户”为你的当前用户。
- 勾选 “使用最高权限运行“ (如果你的脚本需要管理员权限,但通常这个脚本不需要)。
- 在“触发器”选项卡中,你可以更详细地配置运行时间。
- 在“操作”选项卡中,确认显示的是你选择的
monitor.bat
文件。 - 在“条件”选项卡中,你可以设置一些条件,例如只有在计算机空闲时才运行。
- 在“设置”选项卡中,你可以配置任务失败时的重试次数、允许任务运行的最长时间等。建议勾选 “如果任务失败,则在…分钟后重新启动“,并设置合理的重试次数和间隔。
完成这些设置后,monitor.bat
脚本就会按照你设定的计划自动运行,下载并更新你的 Mihomo 规则。你可以在任务计划程序中随时查看、编辑或禁用这个任务。
常见问题解答:
- 运行
monitor.bat
时提示找不到文件?- 请仔细检查
monitor.bat
脚本中所有文件路径的设置 (output_file
,output_mrs_domain
,python_script
,mihomo_path
) 是否指向你电脑上的实际位置。
- 请仔细检查
- Python 脚本报错?
- 请确保你已经正确安装了 Python,并且安装了
PyYAML
和requests
这两个库。检查命令提示符窗口中的错误信息,这会告诉你具体的错误原因。
- 请确保你已经正确安装了 Python,并且安装了
- 下载规则列表失败?
- 请检查你提供的规则列表 URL 是否正确,并且你的电脑可以正常访问这些网址。
.mrs
文件没有更新?- 请检查
monitor.bat
脚本是否成功执行到转换.mrs
文件的步骤,并且 Mihomo 的路径设置正确。
- 请检查
- 自动化任务没有按计划运行?
- 请打开任务计划程序,检查你创建的任务的状态是否为“准备就绪”或“正在运行”。查看“上次运行结果”列是否有错误代码。检查任务的“触发器”设置是否正确。