公网域名DNS解析、网站响应脚本
1.原因
因为需要梳理公网域名和DNS解析对应关系,因此制作此小脚本。
2.前期准备
在使用脚本前,确定已安装了requests
模块和dnspython
模块(在终端界面哦)
pip install requests dnspython
3.完整的请求代码
import os
from urllib.parse import urlparse
import csv
import dns.resolver
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Dnt': '1',
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'same-origin',
'Sec-Fetch-User': '?1',
'Upgrade-Insecure-Requests': '1',
'Sec-Ch-Ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"'
}
# 获取当前工作目录
base_path = os.getcwd()
print(fr'1、当前脚本的运行位置: {base_path} 文件将下载到此处')
print(fr'2、当前脚本需要用户完善 Domains.txt 内的文本数据')
# 拼接完整的文件路径
path = os.path.join(base_path, "Domains.txt")
text_to_write = """# 以下为所有案例,可以根据需求进行修改。
https://www.qq.com
https://www.qq.com:443
https://mail.qq.com:443
https://www.baidu.com:443
http://www.baidu.com:80
https://www.sina.com:443
https://www.abccdde.com:443"""
# 检查文件是否存在
if not os.path.exists(path):
# 如果文件不存在,则创建它并写入内容
with open(path, 'w', encoding='utf-8') as file:
file.write(text_to_write)
print(f"文件 {path} 已自动创建。")
zzz = input("请完善文本数据,程序退出")
exit()
else:
print(f"文件 {path} 存在。")
zzz = input("请回车,继续程序")
print(f"正在读取文件 {path} 并执行查询")
# 读取包含域名的文件
with open(os.path.join(base_path, 'Domains.txt'), 'r', encoding='utf-8') as file:
# 字符串方法:按照行分隔符(换行),装入列表urls里
# urls = file.read().splitlines()
urls = [line.strip() for line in file if not line.startswith('#')]
# urls 现在包含了文件中所有不是以#开头的行(去除了前后空白)
# print(urls)
# 打开文件以写入CSV输出
with open(os.path.join(base_path, '域名检查结果.csv'), 'w', newline='', encoding='gbk') as csv_file:
csv_writer = csv.writer(csv_file)
# 写入CSV的标题行
csv_writer.writerow(['URL', '域名', '公网DNS解析IP', '服务器响应'])
for url in urls:
print(url)
# 解析URL
parsed_url = urlparse(url)
# 获取域名,不能带端口去请求DNS,所以需要切割掉
domain = parsed_url.netloc.split(':')[0]
# 执行DNS解析以获取域名解析地址(A记录)
try:
answers = dns.resolver.resolve(domain, 'A')
ip_addresses = '、'.join(str(answer.address) for answer in answers) # 使用'、'连接所有IP地址
try:
# 设置超时时间为10秒的url请求
response = requests.get(url, headers=headers, timeout=10)
status_code = response.status_code
except requests.RequestException as e:
status_code = f"网站无响应:{e}" # 如果请求失败,写入错误e信息
# 写入CSV的一行数据
csv_writer.writerow([url, domain, ip_addresses, status_code])
except dns.resolver.NoAnswer:
csv_writer.writerow([url, domain, "DNS无响应", "N/A"]) # DNS无响应时写入N/A
except dns.resolver.NXDOMAIN:
csv_writer.writerow([url, domain, "A域名不存在", "N/A"]) # 域名不存在时写入N/A
except Exception as e:
csv_writer.writerow([url, domain, "异常", e]) # 其他错误时写入错误信息
print("已经生成文件: 域名检查结果.csv ")
zzz = input("请回车,程序退出")
4.脚本用法:
脚本会自动检测当前位置信息,并会自动创建 Domains.txt 文件到当前路径。
你需要修改 Domains.txt 文件,将其中每一行存放一个URL,像这样(注意格式,有没带端口都可以)
执行过程会有正确显示:
执行结果如下图:
生成的CSV内容如下:
5.异常
如果有异常也会在Excle中记录,抛异常
遇到这种是:超时
网站无响应: HTTPSConnectionPool(host='xxxxx.xxxxx.com', port=443): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<urllib3.connection.HTTPSConnection object at 0x0000012ABAF899D0>, 'Connection to xxxxx.xxxxx.com timed out. (connect timeout=10)'))
遇到这种是:你请求的格式不合要求,人家不跟你握手,但网站是存在。主动拒绝了你。
网站无响应: HTTPConnectionPool(host='localhost', port=80): Max retries exceeded with url: /h5/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x0000012ABAF775D0>: Failed to establish a new connection: [WinError 10061] 由于目标计算机积极拒绝,无法连接。'))
遇到这种是:证书错误,但网站是存在。有响应的。
网站无响应: HTTPSConnectionPool(host='xxxxx.xxxxx.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, "[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'xxxxx.xxxxx.com'. (_ssl.c:1002)")))
6、异步、协程代码(目前有点小问题)
首先,你需要安装aiohttp
库
pip install aiohttp
import asyncio
import os
from urllib.parse import urlparse
import csv
import dns.resolver
import aiohttp
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Dnt': '1',
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'same-origin',
'Sec-Fetch-User': '?1',
'Upgrade-Insecure-Requests': '1',
'Sec-Ch-Ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"'
}
# 获取当前工作目录
base_path = os.getcwd()
print(fr'1、当前脚本的运行位置: {base_path} 文件将下载到此处')
print(fr'2、当前脚本需要用户完善 Domains.txt 内的文本数据')
# 拼接完整的文件路径
path = os.path.join(base_path, "Domains.txt")
text_to_write = """# 以下为所有案例,可以根据需求进行修改。
https://www.qq.com
https://www.qq.com:443
https://mail.qq.com:443
https://www.baidu.com:443
http://www.baidu.com:80
https://www.sina.com:443
https://www.abccdde.com:443"""
# 检查文件是否存在
if not os.path.exists(path):
# 如果文件不存在,则创建它并写入内容
with open(path, 'w', encoding='utf-8') as file:
file.write(text_to_write)
print(f"文件 {path} 已自动创建。")
zzz = input("请完善文本数据,程序退出")
exit()
else:
print(f"文件 {path} 存在。")
zzz = input("请回车,继续程序")
print(f"正在读取文件 {path} 并执行查询")
# 定义一个异步函数用于执行HTTP请求
async def fetch(session, url):
try:
async with session.get(url, headers=headers, timeout=10) as response:
return response.status
except aiohttp.ClientError as e:
return f"网站无响应: {str(e)}"
# 主要的协程函数
async def main(urls):
# 创建一个异步会话
async with aiohttp.ClientSession() as session:
tasks = []
for url in urls:
print(url)
parsed_url = urlparse(url)
domain = parsed_url.netloc.split(':')[0]
try:
answers = dns.resolver.resolve(domain, 'A')
ip_addresses = ', '.join(str(answer.address) for answer in answers)
task = asyncio.ensure_future(fetch(session, url))
tasks.append((task, url, domain, ip_addresses))
except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN) as e:
tasks.append(((None, None), url, domain, str(e)))
# 等待所有任务完成
results = await asyncio.gather(*[t[0] for t in tasks], return_exceptions=True)
# 写入CSV文件
with open(os.path.join(base_path, '域名检查结果.csv'), 'w', newline='', encoding='gbk') as csv_file:
csv_writer = csv.writer(csv_file)
csv_writer.writerow(['URL', '域名', '公网DNS解析IP', '服务器响应'])
for result, url, domain, ip_addresses in zip(results, *zip(*tasks)):
if isinstance(result, Exception):
csv_writer.writerow([url, domain, ip_addresses, "异常"])
else:
csv_writer.writerow([url, domain, ip_addresses, result or "N/A"])
# 读取文件和处理
urls = [line.strip() for line in open(os.path.join(base_path, 'Domains.txt'), 'r', encoding='utf-8') if not line.startswith('#')]
# 运行异步函数
loop = asyncio.get_event_loop()
loop.run_until_complete(main(urls))
7、多线程请求
好使、好用!
import concurrent.futures
import os
from urllib.parse import urlparse
import csv
import dns.resolver
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Dnt': '1',
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'same-origin',
'Sec-Fetch-User': '?1',
'Upgrade-Insecure-Requests': '1',
'Sec-Ch-Ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"'
}
# ... 文件路径和读写逻辑 ...
# 获取当前工作目录
base_path = os.getcwd()
print(fr'1、当前脚本的运行位置: {base_path} 文件将下载到此处')
print(fr'2、当前脚本需要用户完善 Domains.txt 内的文本数据')
# 拼接完整的文件路径
path = os.path.join(base_path, "Domains.txt")
text_to_write = """# 以下为所有案例,可以根据需求进行修改。
https://www.qq.com
https://www.qq.com:443
https://mail.qq.com:443
https://www.baidu.com:443
http://www.baidu.com:80
https://www.sina.com:443
https://www.abccdde.com:443"""
# 检查文件是否存在
if not os.path.exists(path):
# 如果文件不存在,则创建它并写入内容
with open(path, 'w', encoding='utf-8') as file:
file.write(text_to_write)
print(f"文件 {path} 已自动创建。")
zzz = input("请完善文本数据,程序退出")
exit()
else:
print(f"文件 {path} 存在。")
zzz = input("请回车,继续程序")
print(f"正在读取文件 {path} 并执行查询")
def resolve_dns_and_fetch(url):
try:
parsed_url = urlparse(url)
domain = parsed_url.netloc.split(':')[0]
answers = dns.resolver.resolve(domain, 'A')
ip_addresses = ', '.join(str(answer.address) for answer in answers)
try:
response = requests.get(url, headers=headers, timeout=10)
status_code = response.status_code
except requests.RequestException as e:
status_code = f"网站无响应: {str(e)}"
return url, domain, ip_addresses, status_code
except dns.resolver.NoAnswer:
return url, domain, "DNS无响应", "N/A"
except dns.resolver.NXDOMAIN:
return url, domain, "A域名不存在", "N/A"
except Exception as e:
return url, domain, "异常", str(e)
# 主函数,使用多线程并发执行
def main(urls):
with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:
future_to_url = {executor.submit(resolve_dns_and_fetch, url): url for url in urls}
with open(os.path.join(base_path, '域名检查结果.csv'), 'w', newline='', encoding='gbk') as csv_file:
csv_writer = csv.writer(csv_file)
csv_writer.writerow(['URL', '域名', '公网DNS解析IP', '服务器响应'])
for future in concurrent.futures.as_completed(future_to_url):
url = future_to_url[future]
try:
url, domain, ip_addresses, status_code = future.result()
csv_writer.writerow([url, domain, ip_addresses, status_code])
except Exception as exc:
print(f'{url} generated an exception: {exc}')
# 读取文件和处理
urls = [line.strip() for line in open(os.path.join(base_path, 'Domains.txt'), 'r', encoding='utf-8') if not line.startswith('#')]
main(urls)