如何从Cisco Umbrella Top 100万域名列表中移除子域名?
移除域名列表中子域名的高效方案(Bash + 优化后的Python)
针对你处理Cisco Umbrella Top 100万域名列表的需求,我提供两种高效方案:一种是用Bash命令行工具快速处理,另一种是优化你的Python代码,彻底解决耗时问题。
一、Bash命令实现思路与代码
核心思路是通过反转域名排序,让主域名(比如google.com)排在其子域名(比如play.google.com)前面,然后遍历过程中记录已保留的主域名,遇到子域名直接跳过。
步骤1:提取域名列(原文件是CSV,第二列为域名)
cut -d',' -f2 top-1m.csv > raw_domains.txt
步骤2:移除子域名并保留主域名
用awk处理,实现反转排序+子域名过滤:
awk -F. '{ # 反转域名(如 play.google.com → com.google.play),便于排序后主域名在前 reversed = "" for (i = NF; i > 0; i--) { reversed = reversed $i (i > 1 ? "." : "") } reversed_dom[NR] = reversed original_dom[NR] = $0 } END { # 按反转后的域名排序 asort(reversed_dom, sorted_reversed) seen = {} for (i = 1; i <= length(sorted_reversed); i++) { # 找到对应的原始域名并标记已处理 for (j = 1; j <= NR; j++) { if (reversed_dom[j] == sorted_reversed[i] && original_dom[j] != "") { curr_dom = original_dom[j] original_dom[j] = "" break } } # 检查当前域名是否是已保留主域名的子域 is_sub = 0 split(sorted_reversed[i], parts, ".") prefix = parts[1] for (k = 2; k <= length(parts); k++) { prefix = prefix "." parts[k] if (prefix in seen) { is_sub = 1 break } } if (!is_sub) { print curr_dom seen[sorted_reversed[i]] = 1 } } }' raw_domains.txt > cleaned_main_domains.txt
步骤3:统计剩余域名数量
wc -l cleaned_main_domains.txt
二、Python代码优化方案
你原来的代码问题在于O(n²)的时间复杂度——每个域名都要和100万条数据比对,这相当于1e12次操作,完全不现实。优化思路是利用集合的O(1)查找特性,将比对复杂度降到线性。
优化后的代码
import csv def get_parent_domains(domain): """生成当前域名的所有可能父域(排除顶级域)""" parts = domain.split('.') parents = [] # 生成从二级域开始的父域,比如 play.google.com → [google.com] for i in range(1, len(parts)-1): parent = '.'.join(parts[i:]) parents.append(parent) return parents def main(): # 读取所有域名,存入集合用于快速查找 domain_set = set() domain_list = [] with open("top-1m.csv", "r") as f: reader = csv.reader(f, delimiter=',') for row in reader: domain = row[1].strip() domain_list.append(domain) domain_set.add(domain) # 筛选主域名:没有任何父域在原列表中的域名 main_domains = [] for domain in domain_list: is_subdomain = False for parent in get_parent_domains(domain): if parent in domain_set: is_subdomain = True break if not is_subdomain: main_domains.append(domain) # 保存结果并统计数量 with open("cleaned_main_domains.txt", "w") as f: for dom in main_domains: f.write(f"{dom}\n") print(f"处理完成!剩余主域名数量:{len(main_domains)}") if __name__ == "__main__": main()
优化说明
- 时间复杂度从O(n²)降到了O(n*k),其中k是域名的平均段数(一般为2-3),100万条数据几分钟就能处理完。
- 利用集合的快速查找特性,避免了嵌套循环的暴力比对。
- 额外处理了域名的空白字符,避免格式问题。
如果需要排除顶级域(比如com、net这类单独出现的域名),可以在筛选时加个判断:
if len(domain.split('.')) < 2: continue
内容的提问来源于stack exchange,提问作者Programmer99
相关产品推荐
相关产品推荐

