公网域名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)

 

posted @ 2024-03-06 17:55  Magiclala  阅读(28)  评论(0编辑  收藏  举报