动机与脚本
我工位所用的网络是公司特批的海外专线,速度OK还能翻墙出去看看,自从有了这条线爽的飞起,但缺陷就是每周IP地址都会变,IP一变很多的阿里云ecs安全组就要重新配置,因为有一些公网端口比如grafana或者跳板机是只能公司运维人员访问的。这样每周都要手动改一次IP地址太烦了,于是乎,写了下面这个脚本,一劳永逸的解决这个问题:
    1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76#coding=utf-8
#这个脚本在python3.6下自验通过,用途是去爬当前的IP地址然后给阿里云安全组添加新的IP,并且删除掉老的IP
from aliyunsdkcore import client
from aliyunsdkecs.request.v20140526 import AuthorizeSecurityGroupRequest
from aliyunsdkecs.request.v20140526 import RevokeSecurityGroupRequest
from aliyunsdkcore.profile import region_provider
import requests,sys,re,os
from bs4 import BeautifulSoup
clt = client.AcsClient('这里是AK', '这里是SK', 'cn-hangzhou')			#鉴权
file = "F:\\ip.txt"
def checkDIR():
    global file
    if os.path.exists(file) == True:	#先判断文件是否存在
        with open(file, "r") as f:
            old_ip = f.read()
            return (old_ip)		#获取旧ip
    else:
        print("ip.txt文件不存在,请手动生成!")
        sys.exit()		#文件不存在直接退出
def getIP():
    global file
    r = requests.get('http://www.ip111.cn/')        #这里输入要爬的网站域名
    soup = BeautifulSoup(r.text, "lxml")
    context = []
    for link in soup.find_all('td'):    #获取所有td标签内容
        context.append(link.get_text())     #添加一个列里
    str = context[4]
    ip = re.split(r'[\n\s]\s*', str)[1]			#多符号分割字符串
    with open(file, "w") as f:
        f.write(ip)
    return ip
def addnewRULE(func):
    global clt
    # 设置参数
    for port in ['3000/3000', '34872/34872']:		#这里是端口
        request = AuthorizeSecurityGroupRequest.AuthorizeSecurityGroupRequest()
        request.set_accept_format('json')
        request.add_query_param('RegionId', 'cn-hangzhou')
        request.add_query_param('SecurityGroupId', '目标安全组ID')
        request.add_query_param('IpProtocol', 'tcp')
        request.add_query_param('PortRange', port)
        request.add_query_param('SourceCidrIp',func())
        request.add_query_param('NicType', 'intranet')      #如果不加这句话就是公网添加
        if port == '3000/3000':
            request.add_query_param('Description', 'Grafana使用端口')
        else:
            request.add_query_param('Description', 'Zabbix和堡垒机使用端口')
        # 发起请求
        response = clt.do_action(request)
        print (response)
def deloldRULE(func):
    global clt
    # 设置参数
    for port in ['3000/3000','34872/34872']:
        request = RevokeSecurityGroupRequest.RevokeSecurityGroupRequest()
        request.set_accept_format('json')
        request.add_query_param('RegionId', 'cn-hangzhou')
        request.add_query_param('SecurityGroupId', '目标安全组ID')
        request.add_query_param('IpProtocol', 'tcp')
        request.add_query_param('PortRange', port)
        request.add_query_param('SourceCidrIp', func())
        request.add_query_param('NicType', 'intranet')      #如果不加这句话就是公网删除
        # 发起请求
        response = clt.do_action(request)
        print (response)
if __name__ == '__main__':
    checkDIR()
    deloldRULE(checkDIR)
    getIP()
    addnewRULE(getIP)
整个脚本的逻辑就是先在F盘下有ip.txt里面就保存当前IP地址,然后执行脚本的时候就会先在目标安全组里删除掉这个IP相关的3000端口和34872端口,然后去www.ip111.cn里爬取当前的网址,把新IP写入到ip.txt的同时,再去目标安全组里添加这个新IP相关的3000端口和34872端口。
新的知识点
- 把上一个函数结果当作参数在下一个函数里执行的方法:

 python的退出有两个:
os._exit()和sys.exit():os._exit()会直接将python程序终止,之后的所有代码都不会执行;sys.exit()会抛出一个异常:SystemExit,如果这个异常没有被捕获,那么python解释器将会退出。如果有捕获该异常的代码,那么这些代码还是会执行。使用sys.exit()来退出程序比较优雅,一般情况下也用这个,os._exit()可以在os.fork()产生的子进程里使用。在windows里定时执行python脚本的方法:
打开控制面板—>系统和安全—>计划任务。如图:
点击右侧的创建基本任务,输入任务名称和可选的描述。点击下一步,设置任务的开始时间,可以选择每日执行、每周执行或每月执行。点击下一步,操作选择启动程序,点击下一步输入参数。如图:
    1
2
3程序或脚本:python.exe  
添加参数:输入要执行的python脚本路径(包括文件名)
起始于:输入python.exe的目录(不包括文件名)
最后点击下一步,整个过程搞定。
- 目前
http://www.ip111.cn/网站已经更改了网页格式,上述的代码有一段已经不好使了,需要将getIP()这个函数改成如下的方法:1
2
3
4
5
6
7
8
9
10
11
12def getIP():
global file
r = requests.get('http://2018.ip138.com/ic.asp') #改用这个域名
soup = BeautifulSoup(r.text, "lxml")
context = []
for link in soup.find_all('body'): #获取body内容
context.append(link.get_text()) #添加一个列里
str = context[0]
ip = re.split(r'[\[\]]',str)[1] #进行分割
with open(file, "w") as f:
f.write(ip)
return ip 
