当我们有长期域名但是发现云服务器价格配置低价格昂贵时
就想有没有方法实现使用自己的电脑做服务器,这时我们需要解决一个问题
域名解析需要一个公网IP地址,家用的公网IP与云服务器不同,是不定时更新的,购买固定IP价格个人也是承受不起的。那我们可不可是动态修改IP呢?
答案是:可以的。
一、实现动态修改IP需要以下条件:
1、拥有实名的域名 例如:baidu.com
2、在阿里云注册 AccessKeyID 和 AccessSecret (控制台点击头像就能看到)
3、安装支持包:
pip install aliyun-python-sdk-core
pip install aliyun-python-sdk-domain
pip install aliyun-python-sdk-alidns
pip install requests
pip install APScheduler
4、使用代码
二、代码实现讲解
1、查询当前外网IP地址
2、使用AccessKey 秘钥查询 域名和完整域名 如:www.baidu.com
3、对比解析域名IP和当前域名IP是否存在或者IP是否一致
4、完整域名不存在新建域名解析,存在IP地址一致不修改反之修改
三、上代码:代码设置每5分钟查询更新
# -*- coding:utf-8 -*-
# @Author : 小福不认命
import datetime
import json
import requests
from aliyunsdkcore.client import AcsClient
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.schedulers.background import BackgroundScheduler
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
ipv4_flag = 1 # 是否开启ipv4 ddns解析,1为开启,0为关闭
ipv6_flag = 1 # 是否开启ipv6 ddns解析,1为开启,0为关闭
accessKeyId = "" # 将accessKeyId改成自己的accessKeyId
accessSecret = "" # 将accessSecret改成自己的accessSecret
domain = "baidu.com" # 你的主域名
name_ipv4 = "www" # 要进行ipv4 ddns解析的主机记录,即前缀
name_ipv6 = "www" # 要进行ipv6 ddns解析的主机记录,即前缀 [此处对应的是阿里云解析中的 主机记录 应填写 www 或 @ 等。填写www解析后的域名为www.xxx.com;填写@解析后为主域名xxx.com]
ip_v4_url = [{"url": 'https://test.ipw.cn/', 'res_t': "text", 'key': "\n"}]
ip_v6_url = [{"url": 'https://test.ipw.cn/', 'res_t': "text", 'key': "\n"}]
client = AcsClient(accessKeyId, accessSecret, 'cn-hangzhou')
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"}
def update(RecordId, RR, Type, Value): # 修改域名解析记录
try:
request = UpdateDomainRecordRequest()
request.set_accept_format('json')
request.set_RecordId(RecordId)
request.set_RR(RR)
request.set_Type(Type)
request.set_Value(Value)
response = client.do_action_with_exception(request)
print("这是更新请求结果", response)
return Type
except Exception as e:
print("更新结果异常", e)
return False
# 添加新的域名解析记录
def add(DomainName, RR, Type, Value):
try:
request = AddDomainRecordRequest()
request.set_accept_format('json')
request.set_DomainName(DomainName)
request.set_RR(RR)
request.set_Type(Type)
request.set_Value(Value)
response = client.do_action_with_exception(request)
print("这是新增请求结果", response)
return True
except Exception as e:
print("这是新增请求结果异常", e)
return False
def get_ip_address(type_re: int = 1):
if type_re == 1:
url_list = ip_v4_url
elif type_re == 2:
url_list = ip_v6_url
else:
return False
for index, item in enumerate(url_list):
try:
res = requests.get(item['url'], headers=headers)
if res.status_code == 200:
if item['res_t'] == "json":
return res.json()[item['key']]
res.encoding = "utf-8"
return res.text.split(item['key'])[0]
if res.status_code != 200 and index != len(url_list) - 1:
continue
else:
return False
except Exception as e:
print("请求获取IP异常", e)
print("请求获取IP异常", type_re)
continue
return False
def run_ipv4():
print("运行ipv4:{}".format(datetime.datetime.now()))
# 获得请求
request = DescribeSubDomainRecordsRequest()
# 设置返回类型
request.set_accept_format('json')
# 加载需要查询的域名
request.set_DomainName(domain)
# 查询域名前缀和域名拼接 完整域名
request.set_SubDomain(name_ipv4 + '.' + domain)
# 查询记录类型 A 解析IP
request.set_Type("A")
# 获取域名解析记录列表
response = client.do_action_with_exception(request)
print("获得查询结果", response)
# 将返回的JSON数据转化为Python能识别的
domain_list = json.loads(response)
# 查询 当前服务器 IP地址
# 使用IP.SB的接口获取ipv4地址
ipv4 = get_ip_address(1)
if not ipv4:
return False
print("获取到IPv4地址:%s" % ipv4)
# 如果 前缀没有解析域名 新增
if domain_list['TotalCount'] == 0:
reso = add(domain, name_ipv4, "A", ipv4)
if reso:
print("新建域名解析成功")
else:
print("新建域名解析失败")
# 如果 前缀存在解析获得解析的IP地址
elif domain_list['TotalCount'] == 1:
# 获得 解析的IP地址 不同则更新
if domain_list['DomainRecords']['Record'][0]['Value'].strip() != ipv4.strip():
reso = update(domain_list['DomainRecords']['Record'][0]['RecordId'], name_ipv4, "A", ipv4)
if reso:
print("修改域名解析成功")
else:
print("修改域名解析失败")
# 相同IP地址 不进行操作
else:
print("IPv4地址没变")
# 如果 解析有多个 前缀相同时
elif domain_list['TotalCount'] > 1:
# 删除 子域名请求
request = DeleteSubDomainRecordsRequest()
request.set_accept_format('json')
request.set_DomainName(domain)
request.set_RR(name_ipv4)
# 解析类型 A
request.set_Type("A")
# 提交请求
response = client.do_action_with_exception(request)
print("这是删除请求结果", response)
# 设置新增地址
add(domain, name_ipv4, "A", ipv4)
print("修改域名解析成功")
def run_ipv6():
request = DescribeSubDomainRecordsRequest()
# 设置请求类型
request.set_accept_format('json')
# 查询的域名
request.set_DomainName(domain)
# 查询域名的前缀
request.set_SubDomain(name_ipv6 + '.' + domain)
# 设定使用 ipv6
request.set_Type("AAAA")
# 获取域名解析记录列表
response = client.do_action_with_exception(request)
print("获得查询结果", response)
# 将返回的JSON数据转化为Python能识别的
domain_list = json.loads(response)
# 使用IP.SB的接口获取ipv6地址
ipv6 = get_ip_address(1)
if not ipv6:
return False
print("获取到IPv6地址:%s" % ipv6)
if domain_list['TotalCount'] == 0:
reso = add(domain, name_ipv6, "AAAA", ipv6)
if reso:
print("新增域名解析成功")
else:
print("新增域名解析失败")
elif domain_list['TotalCount'] == 1:
if domain_list['DomainRecords']['Record'][0]['Value'].strip() != ipv6.strip():
reso = update(domain_list['DomainRecords']['Record'][0]['RecordId'], name_ipv6, "AAAA", ipv6)
if reso:
print("修改域名解析成功")
else:
print("修改域名解析失败")
else:
print("IPv6地址没变")
elif domain_list['TotalCount'] > 1:
request = DeleteSubDomainRecordsRequest()
request.set_accept_format('json')
request.set_DomainName(domain)
request.set_RR(name_ipv6)
request.set_Type("AAAA")
response = client.do_action_with_exception(request)
print("存在多个IPv6地址返回结果", response)
add(domain, name_ipv6, "AAAA", ipv6)
print("修改域名解析成功")
# 定时任务 间隔时间启动 启动 第一次不会运行
def task_ipv4():
she = BlockingScheduler()
she.add_job(func=run_ipv4, trigger="interval", minutes=5, id="update_ip", name="update_ip")
she.start()
if __name__ == '__main__':
if ipv4_flag == 1:
task_ipv4()
# if ipv6_flag == 1:
# run_ipv6()
效果展示: