├── Fission.py ├── Fission_domain.txt ├── Fission_ip.txt ├── README.md └── requirements.txt /Fission.py: -------------------------------------------------------------------------------- 1 | # 标准库 2 | import os 3 | import re 4 | import random 5 | import ipaddress 6 | import subprocess 7 | import concurrent.futures 8 | 9 | # 第三方库 10 | import requests 11 | from lxml import etree 12 | from fake_useragent import UserAgent 13 | from requests.adapters import HTTPAdapter 14 | from urllib3.util.retry import Retry 15 | 16 | # 文件配置 17 | ips = "Fission_ip.txt" 18 | domains = "Fission_domain.txt" 19 | dns_result = "dns_result.txt" 20 | 21 | 22 | # 并发数配置 23 | max_workers_request = 20 # 并发请求数量 24 | max_workers_dns = 50 # 并发DNS查询数量 25 | 26 | # 生成随机User-Agent 27 | ua = UserAgent() 28 | 29 | # 网站配置 30 | sites_config = { 31 | "site_ip138": { 32 | "url": "https://site.ip138.com/", 33 | "xpath": '//ul[@id="list"]/li/a' 34 | }, 35 | "dnsdblookup": { 36 | "url": "https://dnsdblookup.com/", 37 | "xpath": '//ul[@id="list"]/li/a' 38 | }, 39 | "ipchaxun": { 40 | "url": "https://ipchaxun.com/", 41 | "xpath": '//div[@id="J_domain"]/p/a' 42 | } 43 | } 44 | 45 | # 设置会话 46 | def setup_session(): 47 | session = requests.Session() 48 | retries = Retry(total=5, backoff_factor=0.3, status_forcelist=[500, 502, 503, 504]) 49 | adapter = HTTPAdapter(max_retries=retries) 50 | session.mount('http://', adapter) 51 | session.mount('https://', adapter) 52 | return session 53 | 54 | # 生成请求头 55 | def get_headers(): 56 | return { 57 | 'User-Agent': ua.random, 58 | 'Accept': '*/*', 59 | 'Connection': 'keep-alive', 60 | } 61 | 62 | # 查询域名的函数,自动重试和切换网站 63 | def fetch_domains_for_ip(ip_address, session, attempts=0, used_sites=None): 64 | print(f"Fetching domains for {ip_address}...") 65 | if used_sites is None: 66 | used_sites = [] 67 | if attempts >= 3: # 如果已经尝试了3次,终止重试 68 | return [] 69 | 70 | # 选择一个未使用的网站进行查询 71 | available_sites = {key: value for key, value in sites_config.items() if key not in used_sites} 72 | if not available_sites: 73 | return [] # 如果所有网站都尝试过,返回空结果 74 | 75 | site_key = random.choice(list(available_sites.keys())) 76 | site_info = available_sites[site_key] 77 | used_sites.append(site_key) 78 | 79 | try: 80 | url = f"{site_info['url']}{ip_address}/" 81 | headers = get_headers() 82 | response = session.get(url, headers=headers, timeout=10) 83 | response.raise_for_status() 84 | html_content = response.text 85 | 86 | parser = etree.HTMLParser() 87 | tree = etree.fromstring(html_content, parser) 88 | a_elements = tree.xpath(site_info['xpath']) 89 | domains = [a.text for a in a_elements if a.text] 90 | 91 | if domains: 92 | print(f"succeed to fetch domains for {ip_address} from {site_info['url']}") 93 | return domains 94 | else: 95 | raise Exception("No domains found") 96 | 97 | except Exception as e: 98 | print(f"Error fetching domains for {ip_address} from {site_info['url']}: {e}") 99 | return fetch_domains_for_ip(ip_address, session, attempts + 1, used_sites) 100 | 101 | # 并发处理所有IP地址 102 | def fetch_domains_concurrently(ip_addresses): 103 | session = setup_session() 104 | domains = [] 105 | 106 | with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers_request) as executor: 107 | future_to_ip = {executor.submit(fetch_domains_for_ip, ip, session): ip for ip in ip_addresses} 108 | for future in concurrent.futures.as_completed(future_to_ip): 109 | domains.extend(future.result()) 110 | 111 | return list(set(domains)) 112 | 113 | # DNS查询函数 114 | def dns_lookup(domain): 115 | print(f"Performing DNS lookup for {domain}...") 116 | result = subprocess.run(["nslookup", domain], capture_output=True, text=True) 117 | return domain, result.stdout 118 | 119 | # 通过域名列表获取绑定过的所有ip 120 | def perform_dns_lookups(domain_filename, result_filename, unique_ipv4_filename): 121 | try: 122 | # 读取域名列表 123 | with open(domain_filename, 'r') as file: 124 | domains = file.read().splitlines() 125 | 126 | # 创建一个线程池并执行DNS查询 127 | with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers_dns) as executor: 128 | results = list(executor.map(dns_lookup, domains)) 129 | 130 | # 写入查询结果到文件 131 | with open(result_filename, 'w') as output_file: 132 | for domain, output in results: 133 | output_file.write(output) 134 | 135 | # 从结果文件中提取所有IPv4地址 136 | ipv4_addresses = set() 137 | for _, output in results: 138 | ipv4_addresses.update(re.findall(r'\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b', output)) 139 | 140 | with open(unique_ipv4_filename, 'r') as file: 141 | exist_list = {ip.strip() for ip in file} 142 | 143 | # 检查IP地址是否为公网IP 144 | filtered_ipv4_addresses = set() 145 | for ip in ipv4_addresses: 146 | try: 147 | ip_obj = ipaddress.ip_address(ip) 148 | if ip_obj.is_global: 149 | filtered_ipv4_addresses.add(ip) 150 | except ValueError: 151 | # 忽略无效IP地址 152 | continue 153 | 154 | filtered_ipv4_addresses.update(exist_list) 155 | 156 | # 保存IPv4地址 157 | with open(unique_ipv4_filename, 'w') as output_file: 158 | for address in filtered_ipv4_addresses: 159 | output_file.write(address + '\n') 160 | 161 | except Exception as e: 162 | print(f"Error performing DNS lookups: {e}") 163 | 164 | # 主函数 165 | def main(): 166 | # 判断是否存在IP文件 167 | if not os.path.exists(ips): 168 | with open(ips, 'w') as file: 169 | file.write("") 170 | 171 | # 判断是否存在域名文件 172 | if not os.path.exists(domains): 173 | with open(domains, 'w') as file: 174 | file.write("") 175 | 176 | # IP反查域名 177 | with open(ips, 'r') as ips_txt: 178 | ip_list = [ip.strip() for ip in ips_txt] 179 | 180 | domain_list = fetch_domains_concurrently(ip_list) 181 | print("域名列表为") 182 | print(domain_list) 183 | with open("Fission_domain.txt", "r") as file: 184 | exist_list = [domain.strip() for domain in file] 185 | 186 | domain_list = list(set(domain_list + exist_list)) 187 | 188 | with open("Fission_domain.txt", "w") as output: 189 | for domain in domain_list: 190 | output.write(domain + "\n") 191 | print("IP -> 域名 已完成") 192 | 193 | # 域名解析IP 194 | perform_dns_lookups(domains, dns_result, ips) 195 | print("域名 -> IP 已完成") 196 | 197 | # 程序入口 198 | if __name__ == '__main__': 199 | main() 200 | -------------------------------------------------------------------------------- /Fission_domain.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Fission_ip.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 使用: 2 | 3 | 1. 克隆项目到本地。 4 | 2. 安装所需的第三方库: `pip install -r requirements.txt` 5 | 3. 在`Fission_ip.txt`中填入至少一个ip(可以是Cloudflare官方的IP,也可以是第三方优选IP),多个ip按行排列 6 | 4. 运行`Fission.py` 7 | 5. 多次运行`Fission.py`即可获取大量优选IP/域名 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | lxml 3 | fake_useragent 4 | --------------------------------------------------------------------------------