利用Python+阿里云實(shí)現(xiàn)DDNS動(dòng)態(tài)域名解析的方法
引子
我想大家應(yīng)該都很熟悉DNS了,這回在DNS前面加了一個(gè)D又變成了什么呢?這個(gè)D就是Dynamic(動(dòng)態(tài)),也就是說(shuō),按照傳統(tǒng),一個(gè)域名所對(duì)應(yīng)的IP地址應(yīng)該是定死的,而使用了DDNS后,域名所對(duì)應(yīng)的IP是可以動(dòng)態(tài)變化的。那這個(gè)有什么用呢?
比如,在家里的路由器上連著一個(gè)raspberry pi(樹(shù)莓派),上面跑著幾個(gè)網(wǎng)站,我應(yīng)該如和在外網(wǎng)環(huán)境下訪問(wèn)網(wǎng)站、登陸樹(shù)莓派的SSH呢?
還有,家里的NAS(全稱Network Attach Storage 網(wǎng)絡(luò)附屬存儲(chǔ),可以理解為私有的百度網(wǎng)盤(pán))上存儲(chǔ)著大量的視頻、照片,如何在外網(wǎng)環(huán)境下和朋友分享呢?
這時(shí),就要靠DDNS了!它會(huì)動(dòng)態(tài)偵運(yùn)營(yíng)商分配給你的IP變化,并映射到域名上,這時(shí)就可以用域名來(lái)訪問(wèn)家庭環(huán)境中的內(nèi)容了~
哈!有了域名,走遍天下都不怕有木有
實(shí)現(xiàn)效果(因?yàn)槲乙呀?jīng)更新過(guò)了,所以它提示IP地址已存在,阿里云是不允許同一個(gè)IP重復(fù)更新的)
本地:
使用DDNS后,在外網(wǎng)環(huán)境下:
注:
這篇帖子適用于家庭寬帶的IP是公網(wǎng)IP的小伙伴,但是注意,這種公網(wǎng)IP是臨時(shí)的,會(huì)不定時(shí)進(jìn)更改。判斷方法很簡(jiǎn)單:先去百度搜索IP,查到自己的IP地址;接著本地開(kāi)一個(gè)網(wǎng)站,比如在Windows下直接啟動(dòng)IIS,Linux下安裝一個(gè)Apache或者Nginx啟動(dòng),使用它們的默認(rèn)頁(yè)面;然后在路由器上設(shè)置好轉(zhuǎn)發(fā)規(guī)則,公網(wǎng)IP的網(wǎng)絡(luò)訪問(wèn)端口最好不要用80,80端口可能被運(yùn)營(yíng)商封了;最后利用前面查到的公網(wǎng)IP+端口號(hào)訪問(wèn)一下,看看能不能顯示內(nèi)網(wǎng)上的頁(yè)面,如果可以,恭喜你!
本文涉及到的技術(shù)點(diǎn)會(huì)比較多,比如爬蟲(chóng)啊,設(shè)計(jì)模式啊,函數(shù)修飾符啊等等,可以算是一個(gè)綜合運(yùn)用了吧~
實(shí)現(xiàn)思路
前面引文已經(jīng)說(shuō)的很清楚了,就是探測(cè)家庭寬帶公網(wǎng)IP的變化,然后利用我們的程序?qū)⑦@個(gè)IP更新到它所綁定的二級(jí)域名上~
綜上,我的思路是這樣的:
1、利用Python去網(wǎng)上爬取自己真實(shí)的IP地址
2、利用阿里云所提供的接口更新IP
前期準(zhǔn)備
1、一個(gè)域名(國(guó)內(nèi)需要備案,港澳臺(tái)和國(guó)外聽(tīng)說(shuō)是不要的,我也沒(méi)嘗試過(guò))
2、將域名的解析設(shè)置到阿里云的云解析上
3、為我們的DDNS創(chuàng)建一個(gè)二級(jí)域名(例如 ddns.expamle.com)
4、安裝阿里云Python SDK(具體教程可以去阿里云上找
5、建議先去閱讀一下Python SDK的使用示例
6、約定:所有的API請(qǐng)求都返回JSON格式,所以要使用Python的JSON模塊進(jìn)行解析
環(huán)境版本
1、Python 3.6
2、網(wǎng)頁(yè)解析利用BeautifulSoup 4
3、阿里的云解析API和Python SDK直接使用官方最新版本即可
實(shí)現(xiàn)步驟
項(xiàng)目結(jié)構(gòu)
注:
AcsClientSingleton.py => 阿里云AcsClient單實(shí)例類(lèi)
CommonRequestSingleton.py => 阿里云CommonRequest的單實(shí)例類(lèi),獲取阿里云Common Request請(qǐng)求類(lèi)
DDNS.py => 主程序
IpGetter.py =>獲取家庭寬帶實(shí)際的公網(wǎng)IP
Utils.py => 工具類(lèi)
爬IP
首當(dāng)其沖的就是要獲得我們實(shí)際的IP地址,推薦ip138.com
你看到的頁(yè)面是這樣的:
畫(huà)紅框的部分是一個(gè)iframe
其中的URL是一直會(huì)變化的,所以第一步是要獲取這個(gè)URL,我這里用到的解析框架是BeautifulSoup,感覺(jué)用Scrapy有點(diǎn)大材小用了
#獲得IP檢測(cè)的網(wǎng)頁(yè)URL def getIpPage(): url = "http://www.ip138.com/" response = urllib.request.urlopen(url) html = response.read().decode("gb2312") soup = BeautifulSoup(html, "lxml") _iframe = soup.body.iframe return _iframe["src"]
獲取到檢測(cè)IP地址的URL后,我們可以觀察一下網(wǎng)頁(yè)結(jié)構(gòu)
發(fā)現(xiàn),我們只需要獲取到center標(biāo)簽的內(nèi)容,然后用正則提取出IP即可
#獲取IP地址 def getRealIp(url): response = urllib.request.urlopen(url) html = response.read().decode("gb2312") pattern = r"(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)" matchs = re.search(pattern,html) ip_addr = "" for i in range(1,5): ip_addr += matchs.group(i) + "." return ip_addr[:-1]
然后我們爬的工作就完成了,可以將這個(gè)獲取IP的過(guò)程進(jìn)行封裝,放進(jìn)工具類(lèi)里
查文檔
阿里云云解析API文檔
我們需要用到的是UpdateDomainRecord這個(gè)Action。
可以觀察一下它的請(qǐng)求參數(shù)
在阿里的請(qǐng)求中,有一個(gè)公共參數(shù)(上面沒(méi)有提及),里面有一個(gè)簽名,這個(gè)簽名雖然官方提供了簽名生成的算法,不過(guò)如果自己實(shí)現(xiàn)很容易出錯(cuò),所以我們使用它的Python SDK。在簽名中,有一個(gè)至關(guān)重要的是AccessKey,AccessKey的生成可以在管理控制臺(tái)的AccessKeys模塊獲取
生成之后一定要保管好這個(gè)密鑰哦!?。。?!
由于云解析官方并沒(méi)有提供對(duì)應(yīng)的SDK模塊,只提供了API,不過(guò)我們可以利用SDK中的CommonRequest對(duì)象來(lái)進(jìn)行API操作。不知道各位有木有發(fā)現(xiàn)在更新域名解析記錄的請(qǐng)求參數(shù)中有一個(gè)RecordId,這個(gè)RecordId要利用DescribeDomainRecords這個(gè)Action來(lái)獲取。
如果每次請(qǐng)求都要使用CommonRequest對(duì)象,這樣難免會(huì)造成一定的內(nèi)存浪費(fèi),所以使用面向?qū)ο笤O(shè)計(jì)模式中的單例模式進(jìn)行優(yōu)化。
class CommonRequestSing: #私有類(lèi)變量 __request = None #該修飾符將實(shí)例方法變成類(lèi)方法 #,因?yàn)轭?lèi)方法無(wú)法操作私有的類(lèi)變量,所以使用實(shí)例方法進(jìn)行操作,再進(jìn)行轉(zhuǎn)換為類(lèi)方法 @classmethod def getInstance(self): if self.__request is None: self.__request = CommonRequest() return self.__request
同時(shí),在構(gòu)造請(qǐng)求式,也會(huì)用到AcsClient對(duì)象,也可使用單例模式優(yōu)化
class AcsClientSing: __client = None @classmethod def getInstance(self): if self.__client is None: self.__client = AcsClient('Your_AccessKeyId', 'Your_AccessKeySecret', 'cn-hangzhou') return self.__client
這里用到了函數(shù)修飾符@classmethod,主要功能是將實(shí)例方法轉(zhuǎn)換為類(lèi)方法。
這兩個(gè)單實(shí)例都可封裝進(jìn)工具類(lèi)中,直接調(diào)用工具類(lèi)獲取實(shí)例就可以了,代碼會(huì)更美觀一些。
獲取RecordID
利用DescribeDomainRecords 這個(gè)Action來(lái)獲得。
#獲取二級(jí)域名的RecordId def getRecordId(domain): client = Utils.getAcsClient() request = Utils.getCommonRequest() request.set_domain('alidns.aliyuncs.com') request.set_version('2015-01-09') request.set_action_name('DescribeDomainRecords') request.add_query_param('DomainName', 'Your_DomainName eg.example.com') response = client.do_action_with_exception(request) jsonObj = json.loads(response.decode("UTF-8")) records = jsonObj["DomainRecords"]["Record"] for each in records: if each["RR"] == domain: return each["RecordId"]
更新解析記錄IP,DDNS邏輯核心
def DDNS(): client = Utils.getAcsClient() recordId = Utils.getRecordId('ddns') ip = Utils.getRealIP() request = Utils.getCommonRequest() request.set_domain('alidns.aliyuncs.com') request.set_version('2015-01-09') request.set_action_name('UpdateDomainRecord') request.add_query_param('RecordId', recordId) request.add_query_param('RR', 'ddns') request.add_query_param('Type', 'A') request.add_query_param('Value', ip) response = client.do_action_with_exception(request) return response if __name__ == "__main__": try: result = DDNS() print("成功!") except (ServerException,ClientException) as reason: print("失敗!原因?yàn)?) print(reason.get_error_msg())
至此結(jié)束~然后設(shè)置好路由器端口映射,這時(shí)候你就可以使用ddns.example.com:XXX來(lái)進(jìn)行訪問(wèn)設(shè)置在家庭網(wǎng)絡(luò)中的資源了~
然后可以將這個(gè)Python代碼設(shè)置為定時(shí)任務(wù),比如每天執(zhí)行一次,或者根據(jù)運(yùn)營(yíng)商的IP變化策略調(diào)整~
源碼(最新):https://github.com/mgsky1/DDNS
源碼(結(jié)構(gòu)與文章一樣的):點(diǎn)擊這里
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Python模塊域名dnspython解析
- python批量處理多DNS多域名的nslookup解析實(shí)現(xiàn)
- Python爬蟲(chóng)DNS解析緩存方法實(shí)例分析
- Python實(shí)現(xiàn)的簡(jiǎn)單dns查詢功能示例
- python實(shí)現(xiàn)域名系統(tǒng)(DNS)正向查詢的方法
- Python中使用scapy模擬數(shù)據(jù)包實(shí)現(xiàn)arp攻擊、dns放大攻擊例子
- Python寫(xiě)的一個(gè)簡(jiǎn)單DNS服務(wù)器實(shí)例
- python實(shí)現(xiàn)DNS正向查詢、反向查詢的例子
- Python DNS查詢放大攻擊實(shí)現(xiàn)原理解析
相關(guān)文章
Django Channels 實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)實(shí)時(shí)聊天和消息推送功能
這篇文章主要介紹了Django Channels 實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)實(shí)時(shí)聊天和消息推送功能,本文分步驟給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-07-07python實(shí)現(xiàn)決策樹(shù)C4.5算法詳解(在ID3基礎(chǔ)上改進(jìn))
下面小編就為大家?guī)?lái)一篇python實(shí)現(xiàn)決策樹(shù)C4.5算法詳解(在ID3基礎(chǔ)上改進(jìn))。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05python 實(shí)現(xiàn)提取PPT中所有的文字
這篇文章主要介紹了python 實(shí)現(xiàn)提取PPT中所有的文字,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03深入探索Python解碼神器Chardet自動(dòng)檢測(cè)文本編碼
Chardet,洞察編碼的清晰水晶球,一個(gè)讓你與編碼不再“失聯(lián)”的神器,本文帶大家走近這個(gè)隱藏在Python工具箱中的小寶貝,探索它的秘密2024-01-01Python數(shù)據(jù)擬合實(shí)現(xiàn)最小二乘法示例解析
這篇文章主要為大家介紹了Python數(shù)據(jù)擬合實(shí)現(xiàn)最小二乘法的示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-10-10詳解通過(guò)API管理或定制開(kāi)發(fā)ECS實(shí)例
在本文里我們給大家整理了關(guān)于通過(guò)API管理或定制開(kāi)發(fā)ECS的相關(guān)實(shí)例內(nèi)容,有需要的朋友們參考學(xué)習(xí)下。2018-09-09