使用Selenium打开PNETLab拓扑并开启所有节点

在玩PNETLab模拟器实验遇到的小问题,从登陆PNETLab到能登陆拓扑里的设备这一段时间是很无聊且每次都是重复动作

以前做测试就点点点没觉得是什么问题,但是设备数量多的大型拓扑,那是一个超长等待时间

想过的方法是查查API,无功而返,而且也不熟

最后使用Selenium实现功能

环境说明

  • Selenium==4.22.0
  • Python==Python 3.10.13
  • PNETLab== 5.3.13
  • ChromeDriver==126.0.6478.126
  • PNETLab关闭验证码验证

效果展示

显示窗口执行(控制台同时输出)

pnetlabstartall-2

无显示窗口执行(控制台输出)

pnetlabstartall-4

脚本代码

就不过多文字描述了,代码里的注释有说明

Note1:PNETLab的打开速度和拓扑文件的载入速度有很多影响因素(电脑硬件,拓扑文件大小,镜像等)

Note2:如果你在本地运行代码后提示错误,大概率可以通过调整显式等待时间和隐式等待时间解决(PNETLab的版本也要考虑,有可能定位元素有变动)

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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
import time
import random


# 创建 ChromeOptions 对象
options = webdriver.ChromeOptions()
# 添加参数headless后不显示窗口
options.add_argument('--headless')
# 控制台不显示INFO:CONSOLE,默认0,显示与服务端的的交互内容
options.add_argument('--log-level=3')

# 4.6版本前需要指定路径,使用本地驱动
# 其实前后版本都可以使用本地驱动(本地好使,加载快,无须联网下载ChromeDriver)
# 指定浏览器驱动路径,以Chrome为例(与电脑安装的谷歌浏览器版本大版本号一致即可或添加参数忽略(自己查))
# 当前日期(20240704)使用最新版本selenium==4.22.0
# chromedriver_bin = 'D:/Plugs/ChromeDriver/126.0.6478.126/chrome-win64/chromedriver.exe'
chromedriver_bin = r'D:\Plugs\ChromeDriver\126.0.6478.126\chrome-win64\chromedriver.exe'
service = webdriver.ChromeService(executable_path=chromedriver_bin)
driver = webdriver.Chrome(service=service, options=options)

# 4.6版本之后使用默认的实例,使用如下代码(自动联网下载ChromeDriver)
# 当前日期(20240704)使用最新版本selenium==4.22.0
# service = Service()
# driver = webdriver.Chrome(options=options, service=service)

# selenium参数定义
# 显式等待设置,等待最多10秒钟,每0.5秒检查一次条件是否满足
# 该参数对需要控制的元素定位起作用
wait = WebDriverWait(driver, 10)

# 设置一个隐式等待时间,因为点击open后的loading时间不可预计
# 可能的因素有拓扑unl文件大小,电脑硬件配置
# 设置隐式等待时间为6秒,该参数全局作用,按需调整数值
driver.implicitly_wait(6)

# 本地PNETLab登陆参数定义
login_url = 'http://x.x.x.x/'
username = 'admin'
password = 'pnet'


# 自动登陆操作
def pnetlab_login():

# 打开PNETLab登陆页面登陆
driver.get(login_url)

# 定位用户名输入框并输入用户名
username_input = wait.until(EC.visibility_of_element_located((By.XPATH, '//input[@placeholder="Username"]')))
username_input.clear()
username_input.send_keys(username)

# 定位密码输入框并输入密码
password_input = wait.until(EC.visibility_of_element_located((By.XPATH, '//input[@placeholder="Password"]')))
password_input.clear()
password_input.send_keys(password)

# 定位登录按钮并点击
login_button = driver.find_element(By.XPATH, '//div[@class="button btn btn-info" and text()="Login"]')
login_button.click()

try:
# 使用显式等待来等待搜索框元素出现
search_element = wait.until(EC.visibility_of_element_located((By.XPATH, '//input[@placeholder="Search Labs"]')))
print("登录成功!")
return True
except Exception as e:
print("登录失败或者无法找到搜索框元素.\n", str(e))
return False


# 随机抽一个lab文件
def random_lab():
lab_names = ('H1 CFG SPOTO Ver_1.unl',
'H1 Plus CFG SPOTO Ver_1.unl',
'H2 CFG SPOTO CCIE RS Ver_1.unl',
'H2 Plus CFG SPOTO Ver_1.unl',
"H3 SPOTO CCIE RS Ver_1.unl")
chosen_lab = random.choice(lab_names)
return chosen_lab


def main():
try:
# 登陆
sign_in = pnetlab_login()
if not sign_in:
print('>>>登陆有问题')
return

# 随机抽
chosen_lab = random_lab()
print('-' * 50 + f'\n本次抽中的lab是:{chosen_lab[:-4]}')
# 搜索框输入lab文件名
search_element = wait.until(EC.visibility_of_element_located((By.XPATH, '//input[@placeholder="Search Labs"]')))
search_element.clear()
search_element.send_keys(chosen_lab)

# 等待第一个搜索结果可见并点击
time.sleep(1)
first_button = wait.until(
EC.visibility_of_element_located((By.XPATH, "//div[@id='search_lab_suggest']/div[@class='button'][1]")))
first_button.click()

# 等待第二个搜索结果可见并点击
# second_button = wait.until(
# EC.visibility_of_element_located((By.XPATH, "//div[@id='search_lab_suggest']/div[@class='button'][2]")))
# second_button.click()

# 点击open按钮
open_button = driver.find_element(By.CSS_SELECTOR, "div.box_flex > div.btn-info:nth-child(1)")
open_button.click()

# 等不到加载完成页面报错,调大隐式等待时间
# 触发左侧菜单的元素,左下角log图片class类
leftmenu_trigger = driver.find_element(By.CLASS_NAME, "logo_img")

# 创建 ActionChains 对象
actions = ActionChains(driver)

# 移动鼠标到左侧菜单触发元素上,触发菜单显示
actions.move_to_element(leftmenu_trigger).perform()

# 点击Setup Nodes
setup_nodes = driver.find_element(By.XPATH, '//span[text()="Setup Nodes"]')
setup_nodes.click()

# Start All Nodes
start_all = driver.find_element(By.CLASS_NAME,"action-nodesstart")
start_all.click()

# 查看已启动的IOL Nodes 的数值
# 移动鼠标到左侧菜单触发元素上,触发菜单显示
actions.move_to_element(leftmenu_trigger).perform()
# 点击System status
system_status = driver.find_element(By.XPATH, '//span[text()="System Status"]')
system_status.click()

print('-' * 50 + '\n正在启动设备\n')

# 30秒后获取已启动设备数值
# time.sleep(30)

# 循环获取启动的设备数值,间隔10秒获取一次,共5分钟
x = 1
while x < 30:
time.sleep(10)
started = wait.until(EC.presence_of_element_located((By.XPATH, "//td/strong[@style='color: red;']")))

# 打印已启动设备数值
print("已启动设备数:", started.text)
if int(started.text) >= 40:
break
x += 1
time.sleep(5)
print(f'设备启动完成,打开链接{login_url},开始实验\n' * 3 + '-' * 50)

# //////////////////////////////////////////////////////////////////////////////////
# # destroy lab 退出
# # 测试用,随后可能用不到
# # time.sleep(10)
# print('正在关闭设备\n')
# # 移动鼠标到左侧菜单触发元素上,触发菜单显示
# actions.move_to_element(leftmenu_trigger).perform()
# # 点击Destroy Lab
# destroy_lab = driver.find_element(By.XPATH, '//span[text()="Destroy Lab"]')
# destroy_lab.click()
#
# # 定位弹窗的 Destroy 按钮
# destroy_button = driver.find_element(By.CLASS_NAME, "swal2-confirm")
#
# # 定位弹窗的 Cancel 按钮
# # cancel_button = driver.find_element(By.CLASS_NAME, "swal2-cancel")
#
# # 二次确认点击
# destroy_button.click()
#
# # 循环获取启用的设备数值,间隔10秒获取一次,共5分钟
# x = 600
# while x > 0:
# time.sleep(10)
# started = WebDriverWait(driver, 10).until(
# EC.presence_of_element_located((By.XPATH, "//td/strong[@style='color: red;']"))
# )
#
# # 打印剩余启动设备数值
# print("剩余启动设备数:", started.text)
# if int(started.text) < 10:
# break
# x -= 1
#
# print('设备已关闭\n' * 3 + '-' * 50)
# time.sleep(10)
# //////////////////////////////////////////////////////////////////////////////////

except Exception as e:
print(e)
print('>>>OPS,FUCKED UP')
finally:
# 关闭浏览器驱动
driver.quit()


if __name__ == '__main__':
main()

最后

  • 忽略代码中变量名的命名拼写错误,词汇量紧张
  • 部分代码来自GPT,官网示例(注意看版本对应的示例)
  • 大部分时间都耗在定位元素了,pnet为了玩花样或是抄来不想改这html前端也是无限套壳
  • 有些是前端渲染代码是通过java函数生成的,这就有点不好玩了
  • 欢迎“来电”来函探讨。
2021-2022华为ICT大赛(全球)实验题研究 多子网分支的第3阶段分层DMVPN实验
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×