利用Python+阿里云实现DDNS(动态域名解析)

利用Python+阿里云实现DDNS(动态域名解析)

因需求公司路由器公网ip不是动态的,需要及时的修改阿里云的域名解析

前期准备

二、准备

1、公网IP(向运营商申请的动态IP)

2、域名(通过阿里云购买的域名)

3、可以运行python程序的服务器(路由器/电脑/树莓派)

4、安装两个Python-SDK库
# 核心库
pip install aliyun-python-sdk-core
# 域名库
pip install aliyun-python-sdk-alidns

aliyunsdkcore.acs_exception.exceptions.ClientException

如果出现该报错:aliyunsdkcore.acs_exception.exceptions.ClientException: SDK.HttpError (‘Connection aborted.’, ConnectionResetError(104, ‘Connection reset by peer’))

安装另一个核心库即可,安装代码如下:

pip install aliyun-python-sdk-core-v3

python安装

aliyun-python-sdk-core-v3
aliyun-python-sdk-alidns==2.0.6   #版本自定义

image-20220907105028906

阿里云获取 AccessKey

通过阿里云控制台进入RAM访问控制页面新建子用户,获取 AccessKey ID 和 AccessKey Secret

image-20220907105426396

创建用户

image-20220907105455328

image-20220907105535627

创建成功

image-20220907105556958

实现逻辑

1、获取当前IP

2、存储获取到的IP

3、比对IP(因为阿里云不允许修改相同的解析,所以需要比对IP是否有变化)

4、获取解析记录列表

 # 获取公网IP并进行修改
    def Get_IPv4(self):

        # 获取IP方法一
        ipv4 = json.load(urlopen('http://jsonip.com'))['ip']
        print("获取到IPv4地址:%s" % ipv4)

        # 获取IP方法二,爬取IP地址
        # ipv4 = getip()

        request = DescribeSubDomainRecordsRequest()
        request.set_accept_format('json')
        request.set_DomainName(self.domain)

完整代码如下

from aliyunsdkcore.client import AcsClient
from aliyunsdkalidns.request.v20150109.DescribeSubDomainRecordsRequest import DescribeSubDomainRecordsRequest
from aliyunsdkalidns.request.v20150109.DeleteSubDomainRecordsRequest import DeleteSubDomainRecordsRequest
from urllib.request import urlopen
import json

class Dnscontroller:

    access_key_id = ""
    #阿里云的新建账户id
    access_key_secret = ""
    
    region = ""
    #时区
    record_type = "A"

    domain = ""
    #上面是你的一级域名
    name_ipv4 = ["二级域名1","二级域名2","二级域名3","二级域名4","二级域名5"]
    #上面是你要修改的域名,我们的比较多,然后呢就以数组的方式去挨个修改

    def __init__(self):
        self.client = AcsClient(
            self.access_key_id,
            self.access_key_secret,
            self.region
        )

    # 添加新的域名解析记录
    def add(self, DomainName, RR, Type, Value):
        from aliyunsdkalidns.request.v20150109.AddDomainRecordRequest import AddDomainRecordRequest
        request = AddDomainRecordRequest()
        request.set_accept_format('json')
        request.set_DomainName(DomainName)
        request.set_RR(RR)
        request.set_Type(Type)
        request.set_Value(Value)
        response = self.client.do_action_with_exception(request)

    # 修改域名解析记录
    def update(self, RecordId, RR, Type, Value):
        from aliyunsdkalidns.request.v20150109.UpdateDomainRecordRequest import UpdateDomainRecordRequest
        request = UpdateDomainRecordRequest()
        request.set_accept_format('json')
        request.set_RecordId(RecordId)
        request.set_RR(RR)
        request.set_Type(Type)
        request.set_Value(Value)
        response = self.client.do_action_with_exception(request)

    # 获取公网IP并进行修改
    def Get_IPv4(self):

        # 获取IP方法一
        ipv4 = json.load(urlopen('http://jsonip.com'))['ip']
        print("获取到IPv4地址:%s" % ipv4)

        # 获取IP方法二,爬取IP地址
        # ipv4 = getip()

        request = DescribeSubDomainRecordsRequest()
        request.set_accept_format('json')
        request.set_DomainName(self.domain)

        for item in self.name_ipv4:
            request.set_SubDomain(item + '.' + self.domain)
            response = self.client.do_action_with_exception(request)
            domain_list = json.loads(response)

            if domain_list['TotalCount'] == 0:
                self.add(self.domain, item, self.record_type, ipv4)
                print("新建域名:" + item + ",解析成功")

            elif domain_list['TotalCount'] == 1:
                if domain_list['DomainRecords']['Record'][0]['Value'].strip() != ipv4.strip():
                    self.update(domain_list['DomainRecords']['Record'][0]['RecordId'], item, self.record_type, ipv4)
                    print("修改域名:" + item + ",解析成功")
                else:
                    print("IPv4地址没变")

            elif domain_list['TotalCount'] > 1:
                # 删除所有解析过的记录,并重新添加新的解析记录
                request = DeleteSubDomainRecordsRequest()
                request.set_accept_format('json')
                request.set_DomainName(self.domain)
                request.set_RR(item)
                response = self.client.do_action_with_exception(request)
                self.add(self.domain, item, self.record_type, ipv4)
                print("修改域名解析成功")

if __name__ == "__main__":
    Dnscontroller().Get_IPv4()

image-20220907111254788

最终运行

image-20220907111334955
2023年12月14日修改代码
增加功能
1添加用户代理信息来模拟浏览器请求
2尝试在每次请求之间添加延迟,以减缓请求速度
3添加没有 set_DomainName 方法

#!/usr/bin/env python3
from aliyunsdkcore.client import AcsClient
from aliyunsdkalidns.request.v20150109.DescribeSubDomainRecordsRequest import DescribeSubDomainRecordsRequest
from aliyunsdkalidns.request.v20150109.DeleteSubDomainRecordsRequest import DeleteSubDomainRecordsRequest
from aliyunsdkalidns.request.v20150109.AddDomainRecordRequest import AddDomainRecordRequest
from aliyunsdkalidns.request.v20150109.UpdateDomainRecordRequest import UpdateDomainRecordRequest
from urllib.request import Request, urlopen
import json
import time

class DnsController:
    # 阿里云账户信息
    access_key_id = ""
    access_key_secret = ""
    region = "cn-shanghai"  # 阿里云区域
    record_type = "A"  # 解析记录类型
    domain = ""  # 一级域名
    name_ipv4 = [""]  # 待修改的子域名列表

    def __init__(self):
        # 初始化阿里云客户端
        self.client = AcsClient(
            self.access_key_id,
            self.access_key_secret,
            self.region
        )

    def add(self, RR, Type, Value):
        # 创建添加域名解析记录的请求
        request = AddDomainRecordRequest(DomainName=self.domain, RR=RR, Type=Type, Value=Value)
        request.set_accept_format('json')
        response = self.client.do_action_with_exception(request)

    def update(self, RecordId, RR, Type, Value):
        # 创建更新域名解析记录的请求
        request = UpdateDomainRecordRequest(RecordId=RecordId, RR=RR, Type=Type, Value=Value)
        request.set_accept_format('json')
        response = self.client.do_action_with_exception(request)

    def Get_IPv4(self):
        # 添加延迟
        time.sleep(1)

        # 获取公网IPv4地址
        url = 'http://jsonip.com'
        headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'}
        req = Request(url, headers=headers)
        ipv4 = json.load(urlopen(req))['ip']
        print("获取到IPv4地址:%s" % ipv4)

        for item in self.name_ipv4:
            # 创建获取子域名解析记录的请求
            request = DescribeSubDomainRecordsRequest(SubDomain=item + '.' + self.domain)
            request.set_accept_format('json')
            response = self.client.do_action_with_exception(request)
            domain_list = json.loads(response)

            if domain_list['TotalCount'] == 0:
                # 如果记录不存在,则新建
                self.add(item, self.record_type, ipv4)
                print("新建域名:" + item + ",解析成功")

            elif domain_list['TotalCount'] == 1:
                if domain_list['DomainRecords']['Record'][0]['Value'].strip() != ipv4.strip():
                    # 如果记录存在且IP不同,则更新
                    self.update(domain_list['DomainRecords']['Record'][0]['RecordId'], item, self.record_type, ipv4)
                    print("修改域名:" + item + ",解析成功")
                else:
                    print("IPv4地址没变")

            elif domain_list['TotalCount'] > 1:
                # 如果存在多条记录,删除所有记录,并重新添加新的解析记录
                for record in domain_list['DomainRecords']['Record']:
                    request = DeleteSubDomainRecordsRequest(DomainName=self.domain, RecordId=record['RecordId'])
                    request.set_accept_format('json')
                    response = self.client.do_action_with_exception(request)
                self.add(item, self.record_type, ipv4)
                print("修改域名解析成功")

if __name__ == "__main__":
    DnsController().Get_IPv4()

2023年12月26日修改代码
增加功能
1UpdateDomainRecordRequest 类的构造方法不接受关键字参数
2出于安全考虑,避免硬编码敏感信息到脚本中,设置了 ALIYUN_ACCESS_KEY_ID 和 ALIYUN_ACCESS_KEY_SECRET 环境变量。

#!/usr/bin/env python3
from aliyunsdkcore.client import AcsClient
from aliyunsdkalidns.request.v20150109.DescribeSubDomainRecordsRequest import DescribeSubDomainRecordsRequest
from aliyunsdkalidns.request.v20150109.DeleteSubDomainRecordsRequest import DeleteSubDomainRecordsRequest
from aliyunsdkalidns.request.v20150109.AddDomainRecordRequest import AddDomainRecordRequest
from aliyunsdkalidns.request.v20150109.UpdateDomainRecordRequest import UpdateDomainRecordRequest
from urllib.request import Request, urlopen
import json
import time
import os

class DnsController:
    def __init__(self):
        self.access_key_id = os.environ.get('ALIYUN_ACCESS_KEY_ID')
        self.access_key_secret = os.environ.get('ALIYUN_ACCESS_KEY_SECRET')
        self.region = "cn-shanghai"
        self.record_type = "A"
        self.domain = ""
        self.name_ipv4 = ["management", "www-test", "potree-test"]
        self.client = AcsClient(
            self.access_key_id,
            self.access_key_secret,
            self.region
        )

    def add(self, RR, Type, Value):
        request = AddDomainRecordRequest()
        request.set_DomainName(self.domain)
        request.set_RR(RR)
        request.set_Type(Type)
        request.set_Value(Value)
        request.set_accept_format('json')
        response = self.client.do_action_with_exception(request)

    def update(self, RecordId, RR, Type, Value):
        request = UpdateDomainRecordRequest()
        request.set_RecordId(RecordId)
        request.set_RR(RR)
        request.set_Type(Type)
        request.set_Value(Value)
        request.set_accept_format('json')
        response = self.client.do_action_with_exception(request)

    def Get_IPv4(self):
        time.sleep(1)
        url = 'http://jsonip.com'
        headers = {'User-Agent': 'Mozilla/5.0'}
        req = Request(url, headers=headers)
        ipv4 = json.load(urlopen(req))['ip']
        print("获取到IPv4地址:%s" % ipv4)

        for item in self.name_ipv4:
            request = DescribeSubDomainRecordsRequest()
            request.set_SubDomain(item + '.' + self.domain)
            request.set_accept_format('json')
            response = self.client.do_action_with_exception(request)
            domain_list = json.loads(response)

            if domain_list['TotalCount'] == 0:
                self.add(item, self.record_type, ipv4)
                print("新建域名:" + item + ",解析成功")

            elif domain_list['TotalCount'] == 1:
                if domain_list['DomainRecords']['Record'][0]['Value'].strip() != ipv4.strip():
                    self.update(domain_list['DomainRecords']['Record'][0]['RecordId'], item, self.record_type, ipv4)
                    print("修改域名:" + item + ",解析成功")
                else:
                    print("IPv4地址没变")

            elif domain_list['TotalCount'] > 1:
                request = DeleteSubDomainRecordsRequest()
                request.set_DomainName(self.domain)
                request.set_RR(item)
                request.set_accept_format('json')
                response = self.client.do_action_with_exception(request)
                self.add(item, self.record_type, ipv4)
                print("已清除过旧的记录,并更新了域名:" + item)

if __name__ == "__main__":
    DnsController().Get_IPv4()

添加环境变量

macOS 或 Linux
在 macOS 或 Linux 系统中,你通常会在 ~/.bash_profile, ~/.bashrc, ~/.zshrc 或其他相似的shell配置文件中设置环境变量。

打开终端并根据你使用的Shell输入下列命令:

export ALIYUN_ACCESS_KEY_ID="你的AccessKeyId"
export ALIYUN_ACCESS_KEY_SECRET="你的AccessKeySecret"

为了使这些变量永久生效,你可以将它们添加到你的用户home目录下的 .bashrc 或 .zshrc 配置文件中。可以通过在终端中运行以下命令来完成:

echo 'export ALIYUN_ACCESS_KEY_ID="你的AccessKeyId"' >> ~/.bashrc
echo 'export ALIYUN_ACCESS_KEY_SECRET="你的AccessKeySecret"' >> ~/.bashrc
source ~/.bashrc

如果你的shell是zsh(如在最新版的macOS中),请将 .bashrc 替换为 .zshrc。

请记得将 “你的AccessKeyId” 和 “你的AccessKeySecret” 替换为你实际的凭据值。如果你不确定使用的shell类型,请通过 echo $SHELL 命令来检查。

设置后,你可以通过在终端中运行 echo $ALIYUN_ACCESS_KEY_ID 和 echo $ALIYUN_ACCESS_KEY_SECRET 来检查变量是否设置成功。

在这里插入图片描述

linux服务器上面添加计划任务定时执行

安装python3.7

网上找一下文档这里我就省略到了

wget https://www.python.org/ftp/python/3.7.2/Python-3.7.2.tgz

在linux上执行python

步骤1;先查找python的 绝对路径
使用 which 查询 python3 解释器所在路径

image-20220907140048715

安装阿里云DNS依赖
pip3 install pyyaml
pip3 install aliyun-python-sdk-core-v3
pip3 install aliyun-python-sdk-alidns==2.0.6

image-20220907141509199

修改要运行的 主 python 文件,在第一行增加以下内容

#! /usr/bin/python3

  • #!这个符号叫做 Shebang 或者 Sha-bang
  • Shebang 通常在 Unix 系统脚本的中 第一行开头 使用
  • 指明 执行这个脚本文件解释程序

image-20220907140148055

骤2;先找的python这个文件的路径

上传到服务器上

image-20220907140331788

步骤;给文件一个可以执行权限

修改 主 python 文件 的文件权限,增加执行权限
$ chmod +x dns.py

image-20220907140513767

步骤;运行测试
root@192:~/python_dns# python3 dns.py 
获取到IPv4地址:xxxxxxxxx
IPv4地址没变
IPv4地址没变
IPv4地址没变
IPv4地址没变
IPv4地址没变

image-20220907141619318

添加Crontab的使用

配置计划任务每天执行

一、Crontab的安装

1、Debian下面安装Crontab

apt-get install cron //大部分情况下Debian都已安装。
/etc/init.d/cron restart //重启Crontab

二、Crontab使用方法

1、查看crontab定时执行任务列表

crontab -l
1
2、添加crontab定时执行任务

crontab -e
————————————————

0 9 * * 1  python3 /root/python_dns/dns.py  > dns.log   #每周一早上9点执行这个python

image-20220907151819934

装。
/etc/init.d/cron restart //重启Crontab

二、Crontab使用方法

1、查看crontab定时执行任务列表

crontab -l
1
2、添加crontab定时执行任务

crontab -e
————————————————

0 9 * * 1  python3 /root/python_dns/dns.py  > dns.log   #每周一早上9点执行这个python

[外链图片转存中…(img-yVBcSUP9-1662623656428)]

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值