使用python把家里的动态公网IP自动同步到阿里云域名下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#!/usr/bin/env python3
# coding=utf-8

# 加载核心SDK
import re

from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException

# 加载获取 、 新增、 更新、 删除接口
from aliyunsdkalidns.request.v20150109 import DescribeSubDomainRecordsRequest, AddDomainRecordRequest, \
UpdateDomainRecordRequest, DeleteDomainRecordRequest

# 加载内置模块
import json, urllib

# AccessKey 和 Secret 建议使用 RAM 子账户的 KEY 和 SECRET 增加安全性
ID = 'AccessKey'
SECRET = 'Secret'

# 地区节点 可选地区取决于你的阿里云帐号等级,普通用户只有四个,分别是杭州、上海、深圳、河北,具体参考官网API
regionId = 'cn-hangzhou'

# 配置认证信息
client = AcsClient(ID, SECRET, regionId)

# 设置主域名
DomainName = 'xclikee.top'

# 子域名列表 列表参数可根据实际需求增加或减少值
SubDomainList = ['www', 'a', '@']


# 查询记录
def getDomainInfo(SubDomain):
request = DescribeSubDomainRecordsRequest.DescribeSubDomainRecordsRequest()
request.set_accept_format('json')

# 设置要查询的记录类型为 A记录 官网支持A / CNAME / MX / AAAA / TXT / NS / SRV / CAA / URL隐性(显性)转发 如果有需要可将该值配置为参数传入
request.set_Type("A")

# 指定查记的域名 格式为 'test.example.com'
request.set_SubDomain(SubDomain)

response = client.do_action_with_exception(request)
response = str(response, encoding='utf-8')

# 将获取到的记录转换成json对象并返回
return json.loads(response)


# 新增记录 (默认都设置为A记录,通过配置set_Type可设置为其他记录)
def addDomainRecord(client, value, rr, domainname):
request = AddDomainRecordRequest.AddDomainRecordRequest()
request.set_accept_format('json')

# request.set_Priority('1') # MX 记录时的必选参数
request.set_TTL('600') # 可选值的范围取决于你的阿里云账户等级,免费版为 600 - 86400 单位为秒
request.set_Value(value) # 新增的 ip 地址
request.set_Type('A') # 记录类型
request.set_RR(rr) # 子域名名称
request.set_DomainName(domainname) # 主域名

# 获取记录信息,返回信息中包含 TotalCount 字段,表示获取到的记录条数 0 表示没有记录, 其他数字为多少表示有多少条相同记录,正常有记录的值应该为1,如果值大于1则应该检查是不是重复添加了相同的记录
response = client.do_action_with_exception(request)
response = str(response, encoding='utf-8')
relsult = json.loads(response)
return relsult


# 更新记录
def updateDomainRecord(client, value, rr, record_id):
request = UpdateDomainRecordRequest.UpdateDomainRecordRequest()
request.set_accept_format('json')

# request.set_Priority('1')
request.set_TTL('600')
request.set_Value(value) # 新的ip地址
request.set_Type('A')
request.set_RR(rr)
request.set_RecordId(record_id) # 更新记录需要指定 record_id ,该字段为记录的唯一标识,可以在获取方法的返回信息中得到该字段的值

response = client.do_action_with_exception(request)
response = str(response, encoding='utf-8')
return response


# 删除记录
def delDomainRecord(client, subdomain):
info = getDomainInfo(subdomain)
if info['TotalCount'] == 0:
print('没有相关的记录信息,删除失败!')
elif info["TotalCount"] == 1:
print('准备删除记录')
request = DeleteDomainRecordRequest.DeleteDomainRecordRequest()
request.set_accept_format('json')

record_id = info["DomainRecords"]["Record"][0]["RecordId"]
request.set_RecordId(record_id) # 删除记录需要指定 record_id ,该字段为记录的唯一标识,可以在获取方法的返回信息中得到该字段的值
result = client.do_action_with_exception(request)
print('删除成功,返回信息:')
print(result)
else:
# 正常不应该有多条相同的记录,如果存在这种情况,应该手动去网站检查核实是否有操作失误
print("存在多个相同子域名解析记录值,请核查后再操作!")


# 有记录则更新,没有记录则新增
def setDomainRecord(client, value, rr, domainname):
info = getDomainInfo(rr + '.' + domainname)
if info['TotalCount'] == 0:
print('准备添加新记录')
add_result = addDomainRecord(client, value, rr, domainname)
print(add_result)
elif info["TotalCount"] == 1:
print('准备更新已有记录')
record_id = info["DomainRecords"]["Record"][0]["RecordId"]
cur_ip = getIp()
old_ip = info["DomainRecords"]["Record"][0]["Value"]
if cur_ip == old_ip:
print("新ip与原ip相同,无法更新!")
else:
update_result = updateDomainRecord(client, value, rr, record_id)
print('更新成功,返回信息:')
print(update_result)
else:
# 正常不应该有多条相同的记录,如果存在这种情况,应该手动去网站检查核实是否有操作失误
print("存在多个相同子域名解析记录值,请核查删除后再操作!")


def Request(url):
try:
with urllib.request.urlopen(url, timeout=2) as response:
return response.read()
except Exception as e:
print(url + "请求错误:" + e)
return None


# 获取外网IP 捅过正则表达式 提取IP
# 以防其中过一个挂掉了多配置几条查询网站
def getIp():
# 备选地址:
# http://pv.sohu.com/cityjson?ie=utf-8 2,curl -L tool.lu/ip
# http://myip.ipip.net/
# https://ifconfig.me/

urlList = ['http://pv.sohu.com/cityjson?ie=utf-8',
' http://myip.ipip.net/',
'https://ifconfig.me/'
]
ip = None
for url in urlList:
html = Request('http://myip.ipip.net/')
if html is not None:
content = str(html, encoding='utf-8')
try:
reIp = re.search(r'((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}',
content)
if reIp is not None:
return reIp.group()
except:
pass

return ip


IP = getIp()

if IP is None:
print("Ip 地址获取失败")
else:
print(IP)
# 循环子域名列表进行批量操作
for x in SubDomainList:
setDomainRecord(client, IP, x, DomainName)