用python進行外網對自己服務器訪問(不需要花生殼)

之前一直想用樹莓派來做自己的數據庫,但是苦于沒法外網訪問,然后利用免費的花生殼,那穩定性實在不敢奉為。所以自己想了個別的辦法來獲取自己家里的樹莓派的公網ip。

這里首先說明下實現的原理:在你的服務器上利用python爬蟲,訪問 http://www.ip.cn/ 網站,爬取該網站上顯示的你機器的ip,然后將獲得的ip發送到你的郵箱內,該程序每1分鐘運行一次,那么久算公網ip改變也基本可以第一時間發到你郵箱。

另一端是你的客戶端,只需要利用python的郵件模塊去郵箱里抓取你的服務器ip地址的那一份郵件就可以獲得你的服務器當前ip地址。

在這里你還需要做的一件事就是去你的路由器里設置端口映射,比如你需要使用3306號端口做mysql,那你就在路由器里設置本地ip:3306號端口映射到外網ip:3306號端口就可以直接用 外網:3306 進行訪問。

import urllib.request
from smtplib import SMTP_SSL
from email.header import Header
from email.mime.text import MIMEText
import time
from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr
import poplib
import re
import os, sys, string
import traceback
url ='http://www.ip.cn/'
#從郵箱內獲取最近的一次ip,因為程序每五分鐘執行一次,
# 所以需要確認該ip是否已經發送,沒有發送才進行送。  已經發送的就不需要再發送
                                      
def  Ip_recv(name):         
    ip_address =0
    message =[]
    # pop3服務器地址
    host ="pop3.163.com"
    # 用戶名
    username ="xxxxxx@163.com"
    # 密碼
    password ="xxxxxxx"
    # 創建一個pop3對象,這個時候實際上已經連接上服務器了
    pp = poplib.POP3_SSL(host)
    # 設置調試模式,可以看到與服務器的交互信息
    #pp.set_debuglevel(1)
    # 向服務器發送用戶名
    pp.user(username)
    # 向服務器發送密碼
    pp.pass_(password)
    # 獲取服務器上信件信息,返回是一個列表,
    第一項是一共有多上封郵件,第二項是共有多少字節
    ret = pp.stat()
    num=ret[0]#ret[0]總共有幾封郵件
    # 取第一封郵件完整信息,在返回值里,
    是按行存儲在down[1]的列表里的。down[0]是返回的狀態信息
    while(ip_address is 0):
        ret= pp.list()
        hdr,lines,octet = pp.retr(num)
        try:
            for line in lines:
                message.append(line.decode('utf-8'))
                msg_content ='\r\n'.join(message)
                msg = Parser().parsestr(msg_content)
        except:
            pass
        num = num -1
        if(numis0):
            pp.quit()#退出pop
            return0
        try:
            ip_flag = (decode_str(msg.get('Subject')))#獲取主題
            #print ("檢查郵件...")
            if  name  in  ip_flag:#獲取樹莓派IP
                ip = ip_flag.split(':')#字符分割
                ip_address = ip[1]#獲取ip地址
                #print("取得IP成功.")
                return  ip_address
            else:
                del message[:]
        except:
            #print("取得IP失敗,請檢查郵箱")
            pass
    pp.quit()
def  decode_str(s):#郵件格式轉換
    value, charset = decode_header(s)[0]
    if  charset:
        value = value.decode(charset)
    return  value

def get_local():
    ip_local =input("輸入查詢地址:1是home,2是company\n")
    ip_local=int(ip_local)
    if ip_local is 1:
        name ="RaspberryIP"#用于識別是家里的ip,還是公司的ip
    elif ip_local is 2:
        name ="CompanyIP"
    else:
        name=get_local()
    return name

if__name__ =='__main__':
    content_pre =0
    count =0
    name=get_local()#確認需要獲取哪里的ip,如果單純在樹莓派上運行,
                                            #則直接把判斷變成肯定就行
    print("name is %s"%name)
    while True:
        try:#偽裝頭,用于防止網站服務器屏蔽你的ip
            req = urllib.request.Request(url,headers= {
                        'Connection':'Keep-Alive',
                        'Accept':'text/html, application/xhtml+xml, */*',
                    'Accept-Language':'en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3',
                    'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) 
                    like Gecko'
            })
            wp = urllib.request.urlopen(req)
            content = wp.read()
            content=content.decode('utf-8','ignore')#utf-8解碼
            index =  content.find("IP:")#找到ip所在地
            content=content[content.find("IP:")+1:]#抓取ip所在位置
            #print(content)
            content=content[content.find("")+6:content.find("")]#抓取ip
        except:
        #print("get ip error")
            pass
        try:
            E_mail_ip=Ip_recv(name)#從郵箱里獲取郵件里已有ip
        except:
            E_mail_ip = content
        if((content_pre != content)and(E_mail_ip != content)):
        #如果新ip與已存在的老ip不一樣,則發送郵件,反之不發
            count =count+1
            content_pre =content
            mail_info = {
                "from":"yyyyyyy@qq.com",                          #你發送ip的郵箱
                "to":"xxxxxxxx@163.com",                          #你接受ip的郵箱
                "hostname":"smtp.qq.com",                       
                "username":"yyyyyyyyyy@qq.com",            #你接受ip的郵箱名
                "password":"yyyyy",                                     #接受ip郵箱的密碼
                "mail_subject":'%s:%s'%(name,content),    #郵件主題
                "mail_text":"%s"%content,                          #ip地址
                "mail_encoding":"utf-8"                               #編碼形式
            }
            #這里使用SMTP_SSL就是默認使用465端口
            smtp = SMTP_SSL(mail_info["hostname"])
            smtp.set_debuglevel(1)
            try:
                smtp.ehlo(mail_info["hostname"])
                smtp.login(mail_info["username"], mail_info["password"])
                msg = MIMEText(mail_info["mail_text"],"plain", mail_info["mail_encoding"])
                msg["Subject"] = Header(mail_info["mail_subject"], 
                        mail_info["mail_encoding"])
                msg["from"] = mail_info["from"]
                msg["to"] = mail_info["to"]
                smtp.sendmail(mail_info["from"], mail_info["to"], msg.as_string())
                smtp.quit()
                print(count)
            except:
                print("send email error")
                pass
        time.sleep(60)
#GBK,GB2312,Big5,utf-8
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,923評論 18 139
  • 作用:限制類型 為什么退出泛型:迎合swift 泛型的作用: 限制類型 提高代碼的規范,減少溝通的成本 泛型的用法...
    Homer1ynn閱讀 366評論 0 0
  • 當自由成為書寫的前提,這是期待已久的事,但為何有些近情情卻,提起筆所有的詞匯在腦海中激蕩但卻在涌出的那刻擁塞了,或...
    茹小茹啊閱讀 132評論 2 0
  • 我這個不是電影迷,但有時間卻要去電影院小資一把的人,這次無意當中搶先觀看了電影《一句頂一萬句》。 看完之后感覺拍的...
    長毛兔呀閱讀 1,334評論 3 5
  • 群里的伙伴估計大部分都到到家了,我卻一個人在北京瞎耗,我發誓,這是我最后一次這么晚回家~ 之前錯誤了預估哈爾濱小伙...
    farewell兔too閱讀 355評論 0 0