百度域名解析DDns Python实现代码

前言

办公室的网络是光猫拨号上网,每次拨号都动态分配一个新的IP地址。

公司内网做了一个erp系统,想外网能使用,买了百度域名和AiPage,无奈域名绑定的事成立一个问题。

花生壳能解决这个问题,但是要收费,还不低,每年大几百。作为白嫖党,岂能白白交这份钱。

借鉴代码

csdn拔了一圈,这位大神给了解决思路 :百度域名解析API+python实现百度云DDNS功能绑定动态公网ip_百度ddns-优快云博客

程序员节礼物

白嫖完,刚好看到csdn程序员节老大推得insCode,马上现学现用,解决了上面代码获取公网IP的bug,在包装一下,加了配置文件,变成下面的样子:

本着不白嫖的精神,同样把代码分享出来,以示对原作者 A欢笑与泪滴 的谢意。

源码

直接贴代码

import hmac
import time
import requests
import socket
import os

import urllib.request
import threading
from tkinter import *
from tkinter import font
from tkinter import PhotoImage
import json

from sympy import false


class DDNS:
    def __init__(self,url,AK,SK,Domain):
        self.url=url
        self.AK=AK
        self.SK=SK
        self.Domain=Domain

    def getTime(self):#获取网络时间戳,用于鉴权
        url="http://acs.m.taobao.com/gw/mtop.common.getTimestamp/"
        res=requests.get(url,timeout=5).text
        res=json.loads(res)["data"]["t"]
        return int(res)/1000

    def getPublicIP(self): # 获取公网地址的函数
        ip1 = requests.get("https://httpbin.org/ip").json()["origin"]
        ip2 = requests.get("https://ifconfig.me/ip").text.strip()
        if ip1 == ip2:
            return ip1
        else:
            return None

    def enc(self,key,message):
        h=hmac.new(key,message,digestmod="SHA256")
        return h.hexdigest()

    def post(self,URI,_data):
        #获取UTC时间
        utc = time.strftime('%Y-%m-%dT%H:%M:%SZ',time.gmtime(self.getTime()))
        #POST字典1
        data=json.dumps(_data)
        #创建请求header字典
        _headers={
            "host":"bcd.baidubce.com",
            "x-bce-date":utc,
            "Content-Type":"application/json;charset=utf-8",
            "Content-Length":str(len(data))
        }
        #格式化字典为http头标准格式
        headers=""
        for a,b in _headers.items():
            headers+=a+":"+b+"\r\n"

        #生成CanonicalHeaders
        method = "POST"
        CanonicalQueryString=""
        CanonicalURI = urllib.parse.quote(URI)  
        result = []
        for key,value in _headers.items():
            tempStr = str(urllib.parse.quote(key.lower(),safe="")) + ":" + str(urllib.parse.quote(value,safe=""))
            result.append(tempStr)
        result.sort()
        CanonicalHeaders = "\n".join(result)

        #拼接得到CanonicalRequest
        CanonicalRequest = method + "\n" + CanonicalURI + "\n" + CanonicalQueryString +"\n" + CanonicalHeaders
        #计算signingKey
        signingKey=self.enc(self.SK.encode(),b"bce-auth-v1/%b/%b/1800"%(self.AK.encode(),utc.encode()))
        #计算signature
        signature=self.enc(signingKey.encode(),CanonicalRequest.encode())
        #生成认证Authorization
        Authorization="bce-auth-v1/%s/%s/1800/content-length;content-type;host;x-bce-date/%s"%(self.AK,utc,signature)


        http="POST %s HTTP/1.1\r\n%sAuthorization:%s\r\n\r\n"%(URI,headers,Authorization)+data

        #建立socket链接,发送http数据
        s=socket.socket()
        s.connect(("bcd.baidubce.com",80))
        s.send(http.encode())
        res=b"" 
        while True:
            _res=s.recv(10240)
            res+=_res
            if b"chunked" not in res: #如果不是chunked,一次性读完退出
                break
            if _res[-5:]==b"0\r\n\r\n": #chunked标志,连续读取到标识符退出
                break
        s.close()
        return res

    def getID(self):
        data={
            'domain':self.url,
            'pageNo':1,
            'pageSize':100
            }
        url="/v1/domain/resolve/list"
        res=self.post(url,data)
        res=res.decode().split("\r\n{")[1].split("}\r\n")[0]
        res="{"+res+"}"
        res=json.loads(res)["result"]

        recordId={}
        for i in res:
            recordId[i["domain"]]=(i["recordId"],i["rdata"])
        return recordId

    def SET(self,domain,ip):
        recordId=self.getID()
        self.urlIP=recordId[domain][1]
        if ip!=recordId[domain][1]:
            url="/v1/domain/resolve/edit"
            data={
                    "domain" : domain,
                    "rdType" : "A",
                    "rdata" : ip,
                    "ttl" : 600,
                    "zoneName" : self.url,
                    "recordId" : recordId[domain][0]
                }

            res=self.post(url,data)
            print(res)

class DDNSApp:
    def __init__(self, root):
        self.root = root
        self.root.title("百度DDNS动态域名解析工具")
        self.root.geometry("500x500")

        # Set background color
        self.root.configure(bg="#f0f0f0")

        # Define font
        bold_font = font.Font(weight="bold")

        default_text = """#参数设置\nurl="baidu.com"  #填写你的域名,如http://www.baidu.com,仅填写baidu.com\nDomain="bcd"\nAK="2d132b22XXXXXXXXXXXXXXXXXXXXXXXX"	#Access Key 百度云控制台申请\nSK="05422f2XXXXXXXXXXXXXXXXXXXXXXXXX"	#Secret Key 百度云控制台申请\nsync=3600 #检测间隔时间,3600秒"""
        
        self.url_label = Label(root, text="URL:", bg="#f0f0f0", font=bold_font, anchor="e")
        self.url_label.grid(row=0, column=0, padx=10, pady=10, sticky="e")
        self.url_entry = Entry(root)
        self.url_entry.grid(row=0, column=1, padx=10, pady=10, ipadx=50)

        self.domain_label = Label(root, text="Domain:", bg="#f0f0f0", font=bold_font, anchor="e")
        self.domain_label.grid(row=1, column=0, padx=10, pady=10, sticky="e")
        self.domain_entry = Entry(root)
        self.domain_entry.grid(row=1, column=1, padx=10, pady=10, ipadx=50)

        self.ak_label = Label(root, text="AK:", bg="#f0f0f0", font=bold_font, anchor="e")
        self.ak_label.grid(row=2, column=0, padx=10, pady=10, sticky="e")
        self.ak_entry = Entry(root)
        self.ak_entry.grid(row=2, column=1, padx=10, pady=10, ipadx=50)

        self.sk_label = Label(root, text="SK:", bg="#f0f0f0", font=bold_font, anchor="e")
        self.sk_label.grid(row=3, column=0, padx=10, pady=10, sticky="e")
        self.sk_entry = Entry(root)
        self.sk_entry.grid(row=3, column=1, padx=10, pady=10, ipadx=50)

        self.sync_label = Label(root, text="间隔时间(秒):", bg="#f0f0f0", font=bold_font, anchor="e")
        self.sync_label.grid(row=4, column=0, padx=10, pady=10, sticky="e")
        self.sync_entry = Entry(root)
        self.sync_entry.grid(row=4, column=1, padx=10, pady=10, ipadx=50)

        self.start_button = Button(root, text="开始(&S)", command=self.start_ddns)
        self.start_button.grid(row=5, column=0, padx=10, pady=10)
        self.stop_button = Button(root, text="停止(&P)", command=self.stop_ddns)
        self.stop_button.grid(row=5, column=1, padx=10, pady=10)

        self.result_text = Text(root, height=15, width=50)
        self.result_text.grid(row=6, column=0, columnspan=2, padx=10, pady=10)
        self.result_text.insert(END, default_text)

        self.running = False
        self.thread = None
        self.config_file = "ddns_config.json"
        self.load_config()
        self.stoped=False

    def save_config(self):
        config = {
            "url": self.url_entry.get(),
            "domain": self.domain_entry.get(),
            "ak": self.ak_entry.get(),
            "sk": self.sk_entry.get(),
            "sync": self.sync_entry.get()
        }
        with open(self.config_file, "w") as f:
            json.dump(config, f)

    def load_config(self):
        if os.path.exists(self.config_file):
            with open(self.config_file, "r") as f:
                config = json.load(f)
                self.url_entry.insert(0, config.get("url", ""))
                self.domain_entry.insert(0, config.get("domain", ""))
                self.ak_entry.insert(0, config.get("ak", ""))
                self.sk_entry.insert(0, config.get("sk", ""))
                self.sync_entry.insert(0, config.get("sync", ""))

    def start_ddns(self):
        self.save_config()
        if not self.running:
            self.running = True
            self.stoped=False
            self.thread = threading.Thread(target=self.run_ddns)
            self.thread.start()

    def stop_ddns(self):
        self.running = False
        self.stoped=True
       
        if self.thread is not None:
            self.thread.join()
            self.thread = None

    def run_ddns(self):
        url = self.url_entry.get()
        domain = self.domain_entry.get()
        ak = self.ak_entry.get()
        sk = self.sk_entry.get()
        sync = int(self.sync_entry.get())

        ddns = DDNS(url, ak, sk, domain)
        first = True
        jsq = sync

        while self.running:
            if jsq == 0 or first:
                try:
                    ddns.SET(domain, ddns.getPublicIP())
                    now = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(ddns.getTime()))
                    result_text = f"---------同步成功---------\n\n---------百度域名DDNS信息---------\n\n域名:{domain}.{url}\n-----\n域名解析IP:{ddns.urlIP}\n本地公网IP:{ddns.getPublicIP()}\n更新时间:{now}\n"
                    self.result_text.insert(END, result_text)
                    self.result_text.see(END)
                except Exception as e:
                    error_text = f"Error: {e}\n"
                    self.result_text.insert(END, error_text)
                    self.result_text.see(END)
                    
                jsq = sync
                first = False
            if self.stoped==False:
                time.sleep(1)
            jsq -= 1
            self.update_countdown(jsq)

    def update_countdown(self, seconds):
        self.root.title(f"百度DDNS动态域名解析工具 - 倒计时: {seconds}秒")

if __name__ == "__main__":
    root = Tk()
    app = DDNSApp(root)
    root.mainloop()

下载

直接运行可能会报错,需要完整版的可以到这里下载,或Gitee下载

csdn:百度域名动态解析DDns资源-优快云文库

gitee:百度域名动态解析: 获取本地网络外网地址,动态同步更新到百度域名服务 (gitee.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈义源

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值