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