python自動(dòng)獲取家里寬帶的公網(wǎng)IP佳遣,并發(fā)送郵件

python自動(dòng)獲取家里寬帶的公網(wǎng)IP凡伊,并發(fā)送郵件

前言

有時(shí)候需要在公網(wǎng)訪問家里的NAS或者家里的服務(wù)器或者連接家里的遠(yuǎn)程桌面窗声,但是沒有公網(wǎng)IP無法訪問家里的設(shè)備。
目前已知的解決方案:

  1. 使用第三方公司提供的內(nèi)網(wǎng)穿透服務(wù)拦耐,如:花生殼等等见剩,缺點(diǎn):要錢
  2. 購(gòu)買一臺(tái)云服務(wù)器,獲得一個(gè)公網(wǎng)IP固翰;通過在用frp、ngrok疗琉、nps等等開源工具在本地和云服務(wù)上建立隧道歉铝,缺點(diǎn):要錢、不穩(wěn)定柠贤,網(wǎng)速受限于云服務(wù)器
  3. 使用ssh反向隧道类缤,缺點(diǎn):需要公網(wǎng)服務(wù)器
  4. 跟寬帶運(yùn)營(yíng)商聯(lián)系申請(qǐng)公網(wǎng)IP餐弱,缺點(diǎn):申請(qǐng)過程漫長(zhǎng),受限于聯(lián)通和電信寬帶
  5. 本地定時(shí)自動(dòng)獲取公網(wǎng)IP,發(fā)送通知速缆,如:郵件

由于本人沒錢所以還是選擇省錢的方式吧,本地定時(shí)自動(dòng)獲取公網(wǎng)IP發(fā)送通知郵件剧董。所以破停。真慢。開始搞吧

一、準(zhǔn)備工作

準(zhǔn)備條件:

  1. 已經(jīng)安裝寬帶
  2. 1臺(tái)路由器(最好是可以刷第三方固件管嬉,或者已經(jīng)刷成了三方固件)
  3. 1臺(tái)可以敲代碼的電腦

二朗鸠、獲取公網(wǎng)IP并發(fā)送郵件(重頭戲)

最簡(jiǎn)單的獲取公網(wǎng)IP的方式:打開瀏覽器,打開百度胎挎,輸入ip, ok 你就可以看到自己的公網(wǎng)IP了犹菇,如圖:

baidu_ip.png

很顯然這種方式并不合適。

那么第二種浦辨,打開路由器管理界面查看公網(wǎng)IP 也不推薦

第三種通過代碼獲取流酬,這才是比較推薦的方式
那么我所了解的通過代碼獲取IP的方式歸納起來應(yīng)該有兩種:
一種是直接訪問提供查看公網(wǎng)IP功能的服務(wù)器列另,獲取訪問的IP
例如:

import requests

url='http://jsonip.com'
# 獲取IP地址
resp = requests.get(url)
info = resp.json()
public_ip = info.get('ip')

OK 5行代碼就搞定了獲取公網(wǎng)IP的問題。但是這方式有兩個(gè)缺點(diǎn):1.需要寄托于別人的服務(wù)器正常運(yùn)行的情況摊滔,如果出現(xiàn)服務(wù)器維護(hù)的時(shí)候那就獲取不到公網(wǎng)IP店乐,2.如果你在路由器中配置了代理眨八,那么你獲取到的公網(wǎng)IP會(huì)是你代理服務(wù)器的IP,然而通過代理IP是無法訪問家里的設(shè)備的页响,所以不推薦這種方式段誊。

另一種就是直接在路由器中獲取公網(wǎng)IP
基本思路:使用代碼訪問路由器管理界面,獲取公網(wǎng)IP没陡∷魃停可選的技術(shù):1.使用爬蟲的方式,2.使用selenium

首先使用爬蟲的方式:requests庫(kù)强岸,只是簡(jiǎn)單的獲取IP蝌箍,就沒有必要使用scrapy

我使用的是路由器刷了三方固件PandoraBox,只是做演示,提供思路妓盲,不是通用的,如需嘗試需要依據(jù)自己的路由情況

分析頁面:
首先需要登錄弹沽,需要找到登錄按鈕提交的鏈接:

luyouqi_login.png

查找方法:
第一種策橘,在瀏覽器中按F12娜亿,查看form節(jié)點(diǎn),其action屬性值就是訪問鏈接沛婴,或者也可以在瀏覽器中按下F12切換到Network選項(xiàng)卡中督赤,點(diǎn)擊一次提交,查看提交數(shù)據(jù)的URI; 所以提交登錄的鏈接為:http://192.168.1.1/cgi-bin/luci

image.png

第二種丑婿,使用fiddler等等抓包工具,抓取提交登錄的鏈接:

image.png

接下來就是使用代碼訪問這個(gè)鏈接自動(dòng)登錄

import requests

login_info = {
    'username': 'root',
    'password': 'XXXXX'
}
url = 'http://192.168.1.1/cgi-bin/luci'
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36"
}

def get_ip():
    info_dict = {}
    session = requests.session()
    resp = session.post(url, headers=headers, data=login_info)
    resp_info= resp.text

然后分析resp.text返回的內(nèi)容枯冈,發(fā)現(xiàn)其中并沒有我們要的IP數(shù)據(jù),通過查看網(wǎng)頁源代可以知道滩褥,公網(wǎng)IP等信息有獨(dú)立的url。
如圖:

image.png

根據(jù)源代碼铺然,注意看:XHR.poll(5, '/cgi-bin/luci/;stok=4d9ab104d86153a97b35619e7f89dad9', { status: 1 }, 這就是路由器后臺(tái)管理返回?cái)?shù)據(jù)的真實(shí)URL, 由此我們可以知道公網(wǎng)IP的真實(shí)鏈接為:http://192.168.1.1/cgi-bin/luci/;stok=b92111c0fa47d24429f29de8b974d6b8?status=1

由于鏈接中的stok是動(dòng)態(tài)的所以需要先獲取該值魄健,然后構(gòu)造一個(gè)新的鏈接插勤。

在瀏覽器中訪問該鏈接革骨,會(huì)首先讓你登錄良哲,登錄之后會(huì)返回如圖信息:


image.png

接下來實(shí)現(xiàn)自動(dòng)登錄獲取IP信息:

import requests
import re

login_info = {
    'username': 'root',
    'password': 'XXXXX'
}

url = 'http://192.168.1.1/cgi-bin/luci'
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36"
}

def get_ip():
    info_dict = {}
    session = requests.session()
    resp = session.post(url, headers=headers, data=login_info)
    # resp_info = resp.json()

    patter = "XHR.poll\(5, '/cgi-bin/luci/;stok=(.*?)', { status: 1 },"
    stock = re.compile(patter).findall(resp.text)
    info_url = url + '/;stok=' + ''.join(stock) + '?status=1'
    resp_info = session.get(info_url, headers=headers).json()

    if not resp_info:
        info_dict = {'msg': '獲取信息出錯(cuò)'}
    wan_info = resp_info.get('wan')
    leases_info = resp_info.get('leases')
    # 由于返回的信息太多了筑凫,只需要獲取自己想要的數(shù)據(jù)
    if wan_info and leases_info:
        leases_str = ''.join([str(leases) for leases in leases_info])
        info_dict = {
            'wan信息': {
                '類型': wan_info.get('proto'),
                'IP地址': wan_info.get('ipaddr'),
                '子網(wǎng)掩碼': wan_info.get('netmask'),
                '網(wǎng)關(guān)': wan_info.get('gwaddr'),
                'DNS': wan_info.get('dns'),
                '已連接': '{}天'.format(wan_info.get('uptime') / 60 / 60 / 24),
            },
            '連接的設(shè)備數(shù)量': len(leases_info),
            'DHCP分配設(shè)備信息': leases_str.replace('expires', '剩余租期').replace('macaddr', 'MAC地址').replace('ipaddr', 'IPV4地址').replace('hostname', '主機(jī)名')
        }
    return info_dict

最后再加上發(fā)送郵件的代碼

直接上代碼吧:

# coding: utf-8

import requests
import re
import smtplib
from email.mime.text import MIMEText
from email.header import Header

login_info = {
    'username': 'XXXX',
    'password': 'XXXXX'
}
url = 'http://192.168.1.1/cgi-bin/luci'
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36"
}
mail_info = {
    'recv_address': 'XXXX@qq.com',
    'sender_name': 'XXXX@qq.com',
    'sender_pwd': 'XXXXXXX',
    'smtp_server': 'smtp.qq.com',
    'subject': '路由器IP信息已更新',
    'content': '您的公網(wǎng)IP信息: {},其他相關(guān)信息如下:{}'

}


def get_ip():
    info_dict = {}
    session = requests.session()
    resp = session.post(url, headers=headers, data=login_info)
    # resp_info = resp.json()

    patter = "XHR.poll\(5, '/cgi-bin/luci/;stok=(.*?)', { status: 1 },"
    stock = re.compile(patter).findall(resp.text)
    info_url = url + '/;stok=' + ''.join(stock) + '?status=1&_=0.3290479886974037'
    resp_info = session.get(info_url, headers=headers).json()

    if not resp_info:
        info_dict = {'msg': '獲取信息出錯(cuò)'}
    wan_info = resp_info.get('wan')
    leases_info = resp_info.get('leases')

    if wan_info and leases_info:
        leases_str = ''.join([str(leases) for leases in leases_info])
        info_dict = {
            'wan信息': {
                '類型': wan_info.get('proto'),
                'IP地址': wan_info.get('ipaddr'),
                '子網(wǎng)掩碼': wan_info.get('netmask'),
                '網(wǎng)關(guān)': wan_info.get('gwaddr'),
                'DNS': wan_info.get('dns'),
                '已連接': '{}天'.format(wan_info.get('uptime') / 60 / 60 / 24),
            },
            '連接的設(shè)備數(shù)量': len(leases_info),
            'DHCP分配設(shè)備信息': leases_str.replace('expires', '剩余租期').replace('macaddr', 'MAC地址').replace('ipaddr', 'IPV4地址').replace('hostname', '主機(jī)名')
        }
    return info_dict


def send_message(content):
    # 設(shè)置發(fā)送郵件的內(nèi)容
    msg = MIMEText(content, 'plain', 'utf-8')
    msg['From'] = Header(mail_info.get('sender_name'))
    msg['Subject'] = Header(mail_info.get('subject'), 'utf-8')
    msg['To'] = Header(mail_info.get('recv_address'))
    # 發(fā)送郵件
    smtp = smtplib.SMTP()
    smtp.connect(mail_info['smtp_server'])
    smtp.login(mail_info['sender_name'], mail_info['sender_pwd'])
    smtp.sendmail(mail_info['sender_name'], mail_info['recv_address'], msg.as_string())


info_dict = get_ip()
content = ''
if info_dict.get('msg'):
    content = info_dict.get('msg')
else:
    content = mail_info.get('content').format(info_dict.get('wan信息').get('IP地址'), str(info_dict))
send_message(content)

** 另外一種直接使用selenium的方式,直接放代碼:


import platform
import time
import os
from selenium import webdriver

url = 'http://192.168.1.1/cgi-bin/luci'
username = 'xxxx'
password = 'xxxx'


def get_ip():
    option = webdriver.ChromeOptions()
    option.add_argument("--headless")  # 通過ChromeOptions設(shè)置隱藏瀏覽器
    option.add_argument('--no-sandbox')  # 在Linux上禁用瀏覽器沙盒
    driver_path = loading_file_path(
        'chromedriver.exe') if platform.system() == 'Windows' else loading_file_path(
        'chromedriver')
    driver = webdriver.Chrome(executable_path=driver_path, options=option)
    driver.get(url)

    user = driver.find_element_by_xpath('//form/div[1]/fieldset/fieldset/div[1]/div/input')
    user.clear()
    user.send_keys(username)
    pwd = driver.find_element_by_id('focus_password')
    pwd.clear()
    pwd.send_keys(password)
    login_btn = driver.find_element_by_xpath('//*[@id="maincontent"]/form/div[2]/input[1]')
    login_btn.click()

    time.sleep(2)
    ip_info = driver.find_element_by_id('wan4_s').text
    return ip_info


def loading_file_path(filename):
    # 獲取當(dāng)前文件路徑
    current_path = os.path.abspath(__file__)
    # 獲取當(dāng)前文件的父目錄
    father_path = os.path.abspath(os.path.dirname(current_path) + os.path.sep + ".")
    # chromedriver文件路徑,獲取當(dāng)前目錄的父目錄與chromedriver拼接
    webdriver_path = os.path.join(father_path, filename)
    return webdriver_path


wan_ip = get_ip()

是不是覺得這種方式很簡(jiǎn)單蔫浆,確實(shí)使用selenium可以很簡(jiǎn)單的獲取到公網(wǎng)IP 信息瓦盛,但是這種方式部署的時(shí)候不適合NAS或者路由器

三外潜、部署腳本

1.可以在nas中添加一個(gè)定時(shí)任務(wù),不做演示
2.在路由器中添加定時(shí)任務(wù)嘱吗,不做演示(需要使用刷了三方固件的路由器)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谒麦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子绕德,更是在濱河造成了極大的恐慌摊阀,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件臣咖,死亡現(xiàn)場(chǎng)離奇詭異夺蛇,居然都是意外死亡酣胀,警方通過查閱死者的電腦和手機(jī)愿卸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門趴荸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宦焦,“玉大人,你說我怎么就攤上這事酝豪。” “怎么了孵淘?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵瘫证,是天一觀的道長(zhǎng)庄撮。 經(jīng)常有香客問我,道長(zhǎng)洞斯,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任么抗,我火速辦了婚禮蝇刀,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘熊泵。我一直安慰自己甸昏,他們只是感情好徐许,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著翻默,像睡著了一般。 火紅的嫁衣襯著肌膚如雪修械。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天翘单,我揣著相機(jī)與錄音蹦渣,去河邊找鬼。 笑死认臊,一個(gè)胖子當(dāng)著我的面吹牛锄奢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拘央,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼堪滨,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了遏乔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤盟萨,失蹤者是張志新(化名)和其女友劉穎捻激,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胞谭,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡丈屹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年伶棒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了彩库。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骇钦。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡竞漾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出坦仍,到底是詐尸還是另有隱情,我是刑警寧澤繁扎,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布梳玫,位于F島的核電站,受9級(jí)特大地震影響提澎,放射性物質(zhì)發(fā)生泄漏念链。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一谦纱、第九天 我趴在偏房一處隱蔽的房頂上張望君编。 院中可真熱鬧,春花似錦吃嘿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽艾蓝。三九已至斗塘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間馍盟,已是汗流浹背茧吊。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瞄桨,地道東北人讶踪。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像柱查,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子唉工,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容