【Python】自动更新阿里云DDNS上的IP

发布时间 2023-05-07 03:49:07作者: 我,猪八戒

1、开发环境

  1. Python 3.7.9
  2. Windows 10

2、开发准备

  1. pip3 install aliyun-python-sdk-core
  2. pip3 install aliyun-python-sdk-alidns

3、具体实现

'''
# 思想思路:
# 1、从www.jsonip.com上获取外网IP地址;
# 2、从保持的Record文件中或阿里云上获取记录的Record;
# 3、判断1中的IP和2中的IP是否相同,不同则更新Record;
# 4、不管是否更新了DDNS都从新记录Record到文件;
'''
import os;
import json;
import datetime;
import time;
import urllib.request;

from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkalidns.request.v20150109 import DescribeDomainRecordsRequest
from aliyunsdkalidns.request.v20150109 import UpdateDomainRecordRequest

class DDNS:
    m_RecordPath = 'AliRecord.log';
    m_logPath = 'Trace.log';
    
    '''-------------------------------------------
    # 保存外网IP地址;
    -------------------------------------------'''
    m_publicIP = '';
    m_aliClient = None;
    
    m_doaminName = 'yvqvan.cn';

    m_rrKeyword = '*';
    m_keywordType = 'A';
    m_accessKeyID = 'LTAI4wUQghIyy6yR';
    m_accessKeySecret = 'ccSLN77xDvKao8n9HTqfHhT8yD2eoq';
    m_aliRecord = '';

    '''-------------------------------------------
    # 初始化类示例;
    # 内部获取外网IP地址;
    # 内部获取阿里云DDNS记录;
    -------------------------------------------'''
    def __init__(self):
        # 删除日志文件和Record文件
        self.DeleteFile(self.m_logPath);
        # 初始化阿里云的Client
        self.m_aliClient = AcsClient(self.m_accessKeyID, self.m_accessKeySecret);
        # 获取外网IP地址
        self.m_publicIP = self.GetPublicIP();
        # 获取阿里云DDNS记录
        self.m_aliRecord = self.GetRecord();

    '''-------------------------------------------
    # 获取本机的外网IP地址
    -------------------------------------------'''
    def GetPublicIP(self):
        httpHead = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0)'};
        requestx = urllib.request.Request('http://jsonip.com', headers=httpHead);
        retValue = urllib.request.urlopen(requestx);
        retValue = json.load(retValue)['ip'];
        self.Trace('当前外网IP地址 = ' + retValue);
        return retValue;

    '''-------------------------------------------
    # 获取记录的IP;先判断本地文件中保持的IP,
    # 如果不存在文件,则从阿里云上获取记录的IP;
    # 如果存在文件,则从文件中获取IP地址;
    -------------------------------------------'''
    def GetRecord(self):
        msg = '';
        if os.path.isfile(self.m_RecordPath):
            file = open(self.m_RecordPath, 'r');
            r = file.read();
            file.close();
            msg = '当前文件内容: ';
        else:
            request = DescribeDomainRecordsRequest.DescribeDomainRecordsRequest();
            #request.set_action_name("DescribeDomainRecords");
            #request.set_RRKeyWord(self.m_rrKeyword);
            #request.set_TypeKeyWord(self.m_keywordType);
            request.set_DomainName(self.m_doaminName);
            r = self.m_aliClient.do_action_with_exception(request).decode("UTF-8");
            msg = '阿里云获取内容: ';
        self.Trace(msg + r);
        return r;

    '''-------------------------------------------
    # 将阿里云上获取的信息,记录到文件中
    -------------------------------------------'''
    def WriteRecord(self):
        self.Trace('写入阿里云DDNS的记录');
        self.DeleteFile(self.m_RecordPath);
        self.WriteFile(self.m_RecordPath, self.m_aliRecord);

    '''-------------------------------------------
    # 记录日志
    -------------------------------------------'''
    def Trace(self, v):
        tm = datetime.datetime.now();
        vv = datetime.datetime.strftime(tm, '%H:%M:%S');
        self.WriteFile(self.m_logPath, '' + vv + '' + v + '\r\n');
        print(v);

    '''-------------------------------------------
    # 写文件
    -------------------------------------------'''  
    def WriteFile(self, f, v):
        # 这里以追加的方式打开文件
        file = open(f, 'a');
        file.write(v);
        file.close();

    '''-------------------------------------------
    # 删除文件
    -------------------------------------------'''
    def DeleteFile(self, f):
        # 文件存在才删除
        if os.path.isfile(f):
            os.remove(f);

    '''-------------------------------------------
    # 获取阿里云中解析的记录ID
    -------------------------------------------'''
    def GetRecordId(self):
        record = json.loads(self.m_aliRecord);
        return record["DomainRecords"]["Record"][0]["RecordId"];

    '''-------------------------------------------
    # 获取阿里云中解析的IP地址
    -------------------------------------------'''
    def GetRecordIP(self):
        record = json.loads(self.m_aliRecord);
        saveIP = record["DomainRecords"]["Record"][0]["Value"];
        self.Trace("记录中的IP = " + saveIP);
        return saveIP;

    '''-------------------------------------------
    # 向阿里云设置DDNS记录
    -------------------------------------------'''
    def SetRecord(self):
        self.Trace("执行更新, 上传IP = " + self.m_publicIP);
        request = UpdateDomainRecordRequest.UpdateDomainRecordRequest();
        request.set_action_name("UpdateDomainRecord");
        request.set_RecordId(self.GetRecordId());
        request.set_Type(self.m_keywordType);
        request.set_RR(self.m_rrKeyword);
        request.set_Value(self.m_publicIP);
        return self.m_aliClient.do_action_with_exception(request);
    
    '''-------------------------------------------
    # 执行DDNS;
    # 1、先判断IP是否相同;
    # 2、如果不相同,则更新IP;
    -------------------------------------------'''
    def RunDDNS(self):
        # 判断当前IP地址与记录中的IP不同,则更新DDNS记录
        if self.m_publicIP != self.GetRecordIP():
            self.SetRecord();
        else:
            self.Trace('不执行更新');
        self.WriteRecord();
        return 1;


'''-----------------------------------------------
# 执行代码
-----------------------------------------------'''
aliyun = DDNS();
aliyun.RunDDNS();