CloudFlare批量添加dns解析脚本

七月 23, 2025 / Ming / 12阅读 / 0评论/ 分类: 默认分类

最近在折腾EdgeOne的优选ip 写了个cf批量添加dns解析脚本
搭配https://www.itdog.cn/ping/ ping目标网站 拿到优选ip
再配合该脚本使用 会方便很多 这里ping eo.hw.072103.xyz 为例

---
使用说明
提前准备好CloudFlare API和CloudFlare Zone ID
CloudFlare API创建方式和CloudFlare Zone ID


---
运行时按脚本提示和个人需求输入 使用示例:

---
可能遇到的错误信息
缺少 resources 依赖库

手动 运行 pip install requests 安装依赖即可

开始添加DNS记录...

⛔ [1/2] 请求失败 [@]: (HTTP 400) {“result“:null,“success“:false,“errors“:[{“code“:81058,“message“:“An identical record already exists.“}],“messages“:[]}

⛔ [2/2] 请求失败 [@]: (HTTP 400) {“result“:null,“success“:false,“errors“:[{“code“:81058,“message“:“An identical record already exists.“}],“messages“:[]}

此错误提示 在cloudflare dns解析中已有相同内容的解析 可以无视

第五步输入ip(优选ip时)切记要用“,”或空格隔开

代码在这里 或去看https://github.com/ming2tap/Cloudflare-Bulk-DNS

import sys
import subprocess
import os
import time


def check_dependencies():
    """检查并安装必要的依赖库"""
    try:
        import pkg_resources
    except ImportError:
        subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'setuptools'])
        import pkg_resources

    required = {'requests'}
    installed = {pkg.key for pkg in pkg_resources.working_set}

    missing = required - installed

    if missing:
        print(f"⚠️ 缺少必要的库: {', '.join(missing)}")
        print("正在尝试安装...")
        try:
            python = sys.executable
            subprocess.check_call([python, '-m', 'pip', 'install', *missing], stdout=subprocess.DEVNULL)
            print("✅ 依赖安装完成")
            import importlib
            importlib.invalidate_caches()
            globals()['requests'] = importlib.import_module('requests')
        except Exception as e:
            print(f"❌ 安装失败: {str(e)}")
            print("请手动运行: pip install requests")
            sys.exit(1)


check_dependencies()

# 现在可以安全导入requests
import requests
import json


def get_input(prompt, required=True, default=None):
    """获取用户输入,支持默认值和必填校验"""
    while True:
        user_input = input(prompt).strip()
        if not user_input and required:
            print("⚠️ 此项为必填项,请重新输入")
            continue
        if not user_input and default is not None:
            return default
        if user_input:
            return user_input


def add_dns_records(api_token, zone_id, subdomains, ip_addresses, record_type="A", ttl=1, proxied=False):
    """批量添加DNS记录到Cloudflare"""
    headers = {
        "Authorization": f"Bearer {api_token}",
        "Content-Type": "application/json"
    }
    base_url = f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records"

    # 计算总记录数(子域名数 × 每个子域名的IP数)
    total_records = len(subdomains) * len(ip_addresses)
    current_count = 0
    success_count = 0

    for subdomain in subdomains:
        for ip in ip_addresses:
            current_count += 1
            record = {
                "type": record_type,
                "name": subdomain,
                "content": ip,
                "ttl": ttl,
                "proxied": proxied
            }

            try:
                response = requests.post(base_url, headers=headers, json=record, timeout=10)

                if response.status_code == 200:
                    result = response.json()
                    if result["success"]:
                        print(f"✅ [{current_count}/{total_records}] 成功添加: {subdomain} → {ip}")
                        success_count += 1
                    else:
                        error_msg = result["errors"][0]["message"] if result.get("errors") else "未知错误"
                        print(f"❌ [{current_count}/{total_records}] 添加失败 [{subdomain}]: {error_msg}")
                else:
                    print(
                        f"⛔ [{current_count}/{total_records}] 请求失败 [{subdomain}]: (HTTP {response.status_code}) {response.text}")

                # 避免触发Cloudflare的API速率限制(免费账户每分钟1200次)
                time.sleep(0.1)

            except requests.exceptions.RequestException as e:
                print(f"🚨 [{current_count}/{total_records}] 网络错误 [{subdomain}]: {str(e)}")

    print(f"\n操作完成: 成功 {success_count}/{total_records} 条记录")
    return success_count > 0


def main():
    print("=" * 50)
    print("Cloudflare DNS批量添加工具")
    print("=" * 50)

    # 从环境变量获取或用户输入API令牌
    api_token = os.getenv('CF_API_TOKEN')
    if not api_token:
        api_token = get_input("1. 请输入Cloudflare API令牌: ")

    # 获取Zone ID
    zone_id = get_input("2. 请输入Zone ID: ")

    # 记录类型选择 - 优化提示信息
    record_type = get_input("3. 记录类型 [默认A] (支持:A, AAAA, CNAME, MX, TXT, NS 等): ",
                            required=False, default="A").upper()

    # 子域名输入
    sub_input = get_input("4. 输入子域名(多个用逗号/空格分隔, @表示根域名):\n  例如: www,api,@\n> ")
    subdomains = [s.strip() for s in sub_input.replace(" ", ",").split(",") if s.strip()]

    # 替换@为根域名标识
    subdomains = ["@" if s == "" or s.lower() == "@" else s for s in subdomains]

    # IP地址输入
    ip_input = get_input("5. 输入IP地址(多个用逗号/空格分隔):\n  例如: 192.168.1.1 或 1.1.1.1,2.2.2.2\n> ")
    ip_addresses = [ip.strip() for ip in ip_input.replace(" ", ",").split(",") if ip.strip()]

    # TTL设置 - 修改默认值为自动(1)
    ttl_input = get_input("6. TTL设置 (1=自动, 默认自动): ", required=False, default="1")
    try:
        ttl = int(ttl_input)
        if ttl == 1:
            # 自动TTL,保留1
            pass
        elif ttl < 60 or ttl > 86400:
            print("⚠️ TTL值应在60-86400之间,已设置为自动(1)")
            ttl = 1
    except ValueError:
        print("⚠️ 无效的TTL值,已设置为自动(1)")
        ttl = 1

    # 代理设置 - 修改默认值为不开启(N)
    proxy_input = get_input("7. 启用Cloudflare代理? [默认N] (y/N): ", required=False, default="n")
    proxied = proxy_input.lower() in ["y", "yes"]

    # 计算总记录数(子域名数 × IP数)
    total_records = len(subdomains) * len(ip_addresses)

    print("\n" + "=" * 50)
    print("即将添加以下DNS记录:")
    print(f"子域名数量: {len(subdomains)}")
    print(f"IP地址数量: {len(ip_addresses)}")
    print(f"总记录数: {total_records}")
    print(f"子域名列表: {', '.join(subdomains)}")
    print(f"IP地址列表: {', '.join(ip_addresses)}")
    print(f"记录类型: {record_type}")
    print(f"TTL: {'自动' if ttl == 1 else f'{ttl}秒'}")
    print(f"代理: {'启用' if proxied else '禁用'}")
    print("=" * 50)

    confirm = input("确认添加? [Y/n]: ").strip().lower()
    if confirm not in ["", "y", "yes"]:
        print("操作已取消")
        return

    print("\n开始添加DNS记录...")
    add_dns_records(api_token, zone_id, subdomains, ip_addresses, record_type, ttl, proxied)


if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\n操作已取消")
    except Exception as e:
        print(f"❌ 发生未预期错误: {str(e)}")
        print("请检查网络连接或参数设置")

#小技巧(15)

评论