用python进行外网对自己服务器访问(不需要花生壳)
本帖最后由 jackwmj12 于 2017-4-23 09:22 编辑之前一直想用树莓派来做自己的数据库,但是苦于没法外网访问,然后利用免费的花生壳,又对流量有所限制。所以自己想了个别的办法来获取自己家里的树莓派的公网ip,获取IP我这里有两个阶段,第一个阶段是我树莓派通过花生壳建立一个网页,这个网页什么都不干,就返回一个IP地址,该返回的IP地址取值于树莓派服务器的数据库。第二阶段是树莓派还会讲IP发送到你指定的邮箱和地址。所以我们要做的就是让树莓派跑一个脚本,这个脚本的功能就是运行一个爬虫,访问访问 http://www.ip.cn/ ,或者http://members.3322.org/dyndns/getip,爬去该网页上显示的你的机器的公网IP,如果IP变更,那么就将你树莓派上数据库里IP值变更掉,并且将IP发送到你的邮箱内。
这样,我们的树莓派公网IP我们就获得了,如果你在外网需要访问树莓派的服务器或者是ssh远程控制你的树莓派,那么只需要检查邮箱或者查看你的网页下显示的IP地址就可以了。当然这里有一个前提,那就是你需要用端口映射来设置路由器,将你路由器上的公网端口映射到你内网的树莓派上的IP地址
比如你需要使用3306号端口做mysql,那你就在路由器里设置本地ip:3306号端口映射到外网ip:3306号端口就可以直接用 外网:3306 进行访问。
#!/usr/bin/python3
#-*- coding:utf-8 -*-
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
import poplib
import info_init
import pymongo
class Applaction:
def __init__(self):
info_app = info_init.Applaction()
# info_data=info_app.load_decode(file_path=r"E:\data_init.jason") #这个jason文件保存着你的资料
# self.url = info_data["url"]
self.url = r"http://members.3322.org/dyndns/getip"
self.email_head =info_data["email_head"] #email头,用于脚本自动从邮箱读取IP时筛选邮件
self.email_send =info_data["email_send"] #发送的邮箱号
self.email_sendpw=info_data["email_sendpw"] #发送邮箱密码
self.email_sendhost = info_data["email_sendhost"] #发送邮箱host
self.email_recv=info_data["email_recv"] #接收邮箱号
self.email_recvpw = info_data["email_recvpw"] #接受邮箱密码 #用于从邮箱读取IP信息
self.email_recvhost = info_data["email_recvhost"] #接受邮箱HOST
self.ip_url = "你树莓派显示IP的网站名"
user = info_data["mongo_user"] #数据库账号
pwd = info_data["mongo_pw"] #数据库密码
uri = 'mongodb://' + user + ":" + pwd + "@" + "localhost" + ":" + "27017"
client = pymongo.MongoClient(uri)
metal = client['金属价格']
coper = metal['coper']
self.mongo_ip = coper['ip']
def ip_check(self):
content = None
try:
content = self.mongo_ip.find()["ip"]
except Exception as e:
print(e)
if content is None:
ip_address = 0
message =[]
# pop3服务器地址
host = self.email_recvhost
# 用户名
username = self.email_recv
# 密码
password = self.email_recvpw
# 创建一个pop3对象,这个时候实际上已经连接上服务器了
pp = poplib.POP3_SSL(host)
# 设置调试模式,可以看到与服务器的交互信息
#pp.set_debuglevel(1)
# 向服务器发送用户名
pp.user(username)
# 向服务器发送密码
pp.pass_(password)
# 获取服务器上信件信息,返回是一个列表,第一项是一共有多上封邮件,第二项是共有多少字节
ret = pp.stat()
num=ret#ret总共有几封邮件# 取第一封邮件完整信息,在返回值里,是按行存储在down的列表里的。down是返回的状态信息
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 Exception as e:
print(e)
num = num -1
if (num is 0):
pp.quit()#退出pop
return None
try:
ip_flag = (self.decode_str(msg.get('Subject')))#获取主题
if self.email_head in ip_flag:#获取树莓派IP
ip = ip_flag.split(':')#字符分割
ip_address = ip #获取ip地址
return ip_address
else :
del message[:]
except Exception as e:
print(e)
pp.quit()
return content
def ip_crawler(self):
try:# 伪装头,用于防止网站服务器屏蔽你的ip
req = urllib.request.Request(self.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解码
# content = content# 抓取ip所在位置
# content = content# 抓取ip
return content
except Exception as e:
print(e)
return None
def send_email(self,content):
mail_info = {
"from": self.email_send,
"to": self.email_recv,
"hostname": self.email_sendhost,
"username": self.email_send,
"password": self.email_sendpw,
"mail_subject": '%s:%s' % (self.email_head, content),
"mail_text": "%s" % content,
"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()
return True
except Exception as e:
print(e)
return False
def decode_str(self,s):#邮件格式转换
value, charset = decode_header(s)
if charset:
value = value.decode(charset)
return value
def ip_update(self,data):
print("IP更新为{}".format(data))
self.mongo_ip.update({'num': '0'}, {'$set': {'ip':data}})
def ip_get(self):
content = None
try:
wp = urllib.request.urlopen(self.ip_url)
content = wp.read()
content = content.decode("UTF-8").split(":").strip()
except Exception as e:
print(e)
if content is None:
ip_address = 0
message = []
# pop3服务器地址
host = self.email_recvhost
# 用户名
username = self.email_recv
# 密码
password = self.email_recvpw
# 创建一个pop3对象,这个时候实际上已经连接上服务器了
pp = poplib.POP3_SSL(host)
# 设置调试模式,可以看到与服务器的交互信息
# pp.set_debuglevel(1)
# 向服务器发送用户名
pp.user(username)
# 向服务器发送密码
pp.pass_(password)
# 获取服务器上信件信息,返回是一个列表,第一项是一共有多上封邮件,第二项是共有多少字节
ret = pp.stat()
num = ret# ret总共有几封邮件# 取第一封邮件完整信息,在返回值里,是按行存储在down的列表里的。down是返回的状态信息
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 Exception as e:
print(e)
num = num - 1
if (num is 0):
pp.quit()# 退出pop
return None
try:
ip_flag = (self.decode_str(msg.get('Subject')))# 获取主题
if self.email_head in ip_flag:# 获取树莓派IP
ip = ip_flag.split(':')# 字符分割
ip_address = ip# 获取ip地址
return ip_address
else:
del message[:]
except Exception as e:
print(e)
pp.quit()
return content
if __name__ == '__main__':
content=None
content_email=None
ip_get =Applaction()
while True:
if content_email is None:
content_email = ip_get.ip_check()
print(content_email)
content = ip_get.ip_crawler()
print(content)
if ((content_email != content) and content_email != None and content != None):#如果新ip与已存在的老ip不一样,则发送邮件,反之不发
content_email =content
ip_get.send_email(content)
ip_get.ip_update(content)
elif content ==None:
time.sleep(60)
time.sleep(3600) 当然这里有一个前提,那就是你需要用端口映射来设置路由器,将你路由器上的公网端口映射到你内网的树莓派上的IP地址 现在公网IP很少了吧 前提是得有个公网ip,不然一切都是扯淡。 如何知道一个 adslip是公网ip? 小区网络NAT太深了就无效了吧 需要要公网ip的,可以给运营商打电话试试,我就要到了一个 3050311118 发表于 2017-4-23 12:29
小区网络NAT太深了就无效了吧
小区是没法用的,小区的IP实际上是一个局域网IP,直接用公网IP是没办法访问到的。 开个qq,同意远程密码控制,远程过去,查下IP,这个方案可行吗 楼主,你需要ddclient 每次都要去开邮箱查iP不觉得烦吗,搞个免费域名,每次访问轻松愉快 frp可以解决这个 SNOOKER 发表于 2017-4-23 16:47
每次都要去开邮箱查iP不觉得烦吗,搞个免费域名,每次访问轻松愉快
第一点:你外部访问你树莓派的数据库和SSH是没法通过域名访问的
第二点:我上面提到我实际上是有域名的,并且用了花生壳,但是花生壳我用的是免费版,每个月是有一定的流量限制的,所以我在我的个人主页上也用了一个链接的办法,点进主页需要用到域名,点域名上的链接全部由django将域名转化成IP地址直接访问,这样有个好处就是通过IP直接访问是不需要用到花生壳流量的。
第三点:我查看我的ip地址不是只有邮箱查询一个办法的,还可以通过域名访问,我讲IP地址存在树莓派服务器的数据库里,然后把IP地址显示在我的一个域名链接上。当我其它软件需要访问到我的树莓派数据库的时候,我的软件会自动去这个域名地址爬去IP地址然后进行访问,这个是最最重要的,如果这个办法爬去到的IP不能访问,我的程序会退而进行邮箱里查询IP地址。因为第二者速度慢,所以优先第一种。 轻风 发表于 2017-4-23 15:42
开个qq,同意远程密码控制,远程过去,查下IP,这个方案可行吗
其实你稍微会点网站就行。把IP地址直接显示在自己域名网站上就行 轻风 发表于 2017-4-23 15:42
开个qq,同意远程密码控制,远程过去,查下IP,这个方案可行吗
这样很不方便 jackwmj12 发表于 2017-4-23 17:28
第一点:你外部访问你树莓派的数据库和SSH是没法通过域名访问的
第二点:我上面提到我实际上是有域名的, ...
数据库我不太清楚,sSH为何不能通过域名访问?你是指需要通过端口映射吗 把花生壳用错地方了,你需要的是oray的ddns 不是花生壳 panjun10 发表于 2017-4-23 19:06
把花生壳用错地方了,你需要的是oray的ddns 不是花生壳
花生壳也是需要的,我本身有个主页用到的,我是有了花生壳顺便扩展了这个功能。 楼主这个功能是对花生壳的拓展。这个想法不错。 没有看明白,直接路由器中设花生壳,端口映射不可以? 楼主研究下 IPV6 咋搞。我这里运营商支持IPV6 ,但是 IPV6 不懂啊。不知道IPV6是不是也有内网,外网的说法。 花生棒,拿走不谢。当然也有免费的 ngrok 还是ddns安逸 公网IP 有这个只需要用域名绑定IP,路由端口映射就可以了 哪来那么多复杂的东西
页:
[1]