Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2ab6d04834 | |||
| ba91dbdf65 | |||
| ab74bafde1 | |||
| 709d647e94 | |||
| b55016ee07 | |||
| 107c85253a | |||
| 3030eaba40 | |||
| f8929fede9 | |||
| 5d4da12740 | |||
| 8dadb65432 | |||
| aa45f11ed7 | |||
| 08b885cbd0 | |||
| 37b718ef63 | |||
| 6baeb8c781 | |||
| f95f5653b4 | |||
| b245e58df9 |
@@ -0,0 +1,113 @@
|
||||
# Web Automation
|
||||
|
||||

|
||||
|
||||
### 開發環境
|
||||
* python 3.10.10
|
||||
* selenium 4.8.2 (python 套件)
|
||||
## 程式執行檔
|
||||
### terminal_main
|
||||
```
|
||||
$ python terminal_main.py
|
||||
```
|
||||
1. 在終端機上執行 terminal_main.py
|
||||
2. 輸入 START [Page_name] 進入網頁,'END' 離開網頁,指令反饋會即時顯示在終端機上
|
||||
3. 過程中開啟的視窗可以繼續操作
|
||||
4. 離開網頁後,輸入 'END_ALL' 結束程式
|
||||
5. 程式結束後輸出 commend_line/commend_line.txt 紀錄成功執行的指令,可做為 txtfile_main.py 的執行腳本。(以下文為例)
|
||||
```
|
||||
START Devices
|
||||
cleanConnect
|
||||
scanConnect/EE:3A
|
||||
END
|
||||
START TaskContent
|
||||
selectMode/Cycle/
|
||||
setEDCParameter/start/-1/
|
||||
setEDCParameter/stop/-0.5/
|
||||
addChart/test
|
||||
setChart/test/Time//EE:/I/0
|
||||
modeSwitch/start/
|
||||
IdleTillStop/1/EE
|
||||
selectMode/Idle/
|
||||
END
|
||||
END_ALL
|
||||
```
|
||||
### txtfile_main
|
||||
```
|
||||
$ python terminal_main.py
|
||||
$ python terminal_main.py > .\log\[logfile.txt] // 將輸出流程寫入指定 log 檔
|
||||
```
|
||||
1. 在終端機上執行 txtfile_main.py
|
||||
2. 程式會自動執行上一次 terminal_main.py 輸出的腳本
|
||||
|
||||
---
|
||||
## Devices
|
||||
1. 載入 [url] / admin / devices
|
||||
|
||||
### cleanConnect()
|
||||
```
|
||||
cleanConnect
|
||||
```
|
||||
* 清除所有與 Controller 連線的 Elite
|
||||
### scanConnect(set_ID)
|
||||
```
|
||||
scanConnect/[set_ID]
|
||||
```
|
||||
* 掃描並連線到 MAC 中包含 [set_ID] 字串的 Elite
|
||||
|
||||
|
||||
## TaskContent
|
||||
1. 載入 [url] / admin / task-content
|
||||
2. 紀錄並輸出以下參數 (重新載入會重置參數)
|
||||
* Device list: 列出已連線的 Elite 以及對照 MB 的代號
|
||||
* Chart list: 列出已存在的圖表,並為其命名
|
||||
(Elite 的預設圖表命名為 XX:XX_defult,其餘命名為chartX,名稱方便用作設定圖表參數時指定圖表)
|
||||
|
||||
### selectMode(mode_name, set_ID)
|
||||
```
|
||||
selectMode/[mode_name]/[set_ID]
|
||||
```
|
||||
1. 指定 MAC 包含 [set_ID] 的 Elite
|
||||
2. 選擇包含 [mode_name] 的 Mode
|
||||
* 如果有兩個 Elite/Mode 字串包含 [set_ID]/[mode_name],會跳出警告,並選擇第一個選項,允許空字串
|
||||
|
||||
### setEDCParameter(key_name, value, set_ID)
|
||||
```
|
||||
setEDCParmeter/[key_name]/[value]/[set_ID]
|
||||
```
|
||||
1. 指定 MAC 包含 [set_ID] 的 Elite
|
||||
2. 參數名稱包含 [key_name] 的項目輸入 [value],或選擇字串包含 [value] 的選項
|
||||
* 如果有兩個 Elite/參數名稱/選項名稱 字串包含 [set_ID]/[key_name]/[value],會跳出警告,並選擇第一個選項,允許空字串
|
||||
|
||||
### ModeSwitch(startOrStop, set_ID)
|
||||
```
|
||||
modeSwitch/['START'/'STOP']/[set_ID]
|
||||
```
|
||||
1. 指定 MAC 包含 [set_ID] 的 Elite
|
||||
2. 依照 [startOrStop] 點擊開始或結束,若在 [set_ID] 輸入'ALL',則點擊 START ALL 或 STOP ALL
|
||||
* 如果有兩個 Elite 字串包含 [set_ID],會跳出警告,並選擇第一個選項,允許空字串
|
||||
|
||||
### IdleTillStop(wait_sec, mac_ID)
|
||||
```
|
||||
IdleTillStop/[wait_sec]/[mac_ID]
|
||||
```
|
||||
1. 等待 [wait_sec] 秒,建議至少一秒
|
||||
2. 指定 MAC 包含 [set_ID] 的 Elite
|
||||
3. 暫停動作,直到指定 Elite 重新出現 START 按鍵
|
||||
|
||||
### addChart(set_chart_name)
|
||||
```
|
||||
addChart/[set_chart_name]
|
||||
```
|
||||
1. 新增一個圖表 (點擊 add chart),並命名為 [set_chart_name] (名稱方便設定圖表參數時指定圖表)
|
||||
|
||||
### setChart(set_chart_name, x_source, x_channel, y_source, y_channel, subplot)
|
||||
```
|
||||
setChart/[set_chart_name]/[x_source]/[x_channel]/[y_source]/[y_channel]/[subplot]
|
||||
```
|
||||
1. 以設定的圖表名稱 [set_chart_name] 指定圖表
|
||||
2. 依序設定 X_source/X_channel/Y_source/Y_channel/subplot
|
||||
1. 當 source 為 Time 時,忽略 channel
|
||||
2. source 可填 Elite MAC ID,會自動轉換為 MB 代號
|
||||
3. 回到顯示圖表狀態
|
||||
* 所有選項如果有兩個字串包含設定值,會跳出警告,並選擇第一個選項
|
||||
Binary file not shown.
@@ -0,0 +1,4 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
||||
@@ -0,0 +1,4 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.chrome.options import Options
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import Select
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.webdriver.support.wait import WebDriverWait
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
import time
|
||||
|
||||
WAITING_TIME = 20
|
||||
|
||||
def startDevicesPage(chrome, url, page_select, file, row_list = [] ):
|
||||
page_class = globals()[page_select]
|
||||
use_txt = True if len(row_list)>0 else False
|
||||
page = page_class(chrome, url)
|
||||
text_row = input(" >>> ").strip() if use_txt==False else row_list.pop(0)
|
||||
while text_row != 'END':
|
||||
print(text_row)
|
||||
text_row_split = text_row.split('/')
|
||||
try:
|
||||
func = getattr(page, text_row_split[0])
|
||||
func() if len(text_row_split)<=1 else func(*text_row_split[1:])
|
||||
file.write(" "+text_row+"\n")
|
||||
except Exception as e:
|
||||
print('*** ERROR:',e)
|
||||
if len(row_list)<1 and use_txt:
|
||||
print("*** WARNING: Commend line in txt didn't finish by 'END'.")
|
||||
break
|
||||
text_row = input(" >>> ").strip() if len(row_list)<1 else row_list.pop(0)
|
||||
|
||||
file.write(" END\n")
|
||||
return page
|
||||
|
||||
# def startDevicesPageTxt(chrome, url, page_select, row_list, file):
|
||||
# pass
|
||||
|
||||
class DevicesPage():
|
||||
|
||||
def __init__(self,chrome,url):
|
||||
chrome.get(url + "#/admin/devices")
|
||||
WebDriverWait(chrome, WAITING_TIME).until(EC.presence_of_element_located((By.CSS_SELECTOR,'h5.mt-0')))
|
||||
WebDriverWait(chrome, WAITING_TIME).until(EC.invisibility_of_element_located((By.CLASS_NAME, 'orbit')))
|
||||
self._chrome = chrome
|
||||
|
||||
def cleanConnect(self):
|
||||
while click_by_item_text(self._chrome, By.CLASS_NAME, 'va-button__content', 'DISCONNECT',error_mes=False):
|
||||
click_by_item_text(self._chrome, By.CLASS_NAME, 'va-button__content','Confirm')
|
||||
WebDriverWait(self._chrome, 10).until(EC.invisibility_of_element_located((By.CLASS_NAME, 'orbit')))
|
||||
|
||||
def scanConnect(self, set_ID):
|
||||
test_div = False
|
||||
while True:
|
||||
while test_div == False :
|
||||
click_by_item_text(self._chrome, By.CLASS_NAME,'va-button__content','SCAN')
|
||||
WebDriverWait(self._chrome, 10).until(EC.invisibility_of_element_located((By.CLASS_NAME, 'orbit')))
|
||||
test_div = select_div(self._chrome, 'div.va-item-label--caption', set_ID,3,error_mes=False)
|
||||
click_by_item_text(test_div, By.CLASS_NAME,'va-button__content', 'CONNECT', key_like = False)
|
||||
WebDriverWait(self._chrome, 10).until(EC.invisibility_of_element_located((By.CLASS_NAME, 'orbit')))
|
||||
if click_by_item_text(test_div, By.CLASS_NAME,'va-button__content', 'DISCONNECT',click = False):
|
||||
break
|
||||
|
||||
class TaskContentPage():
|
||||
def __init__(self, chrome, url):
|
||||
chrome.get(url + "#/admin/task-content")
|
||||
chrome.implicitly_wait(1)
|
||||
WebDriverWait(chrome, WAITING_TIME).until(EC.presence_of_element_located((By.CSS_SELECTOR,'h5.mt-0')))
|
||||
WebDriverWait(chrome, WAITING_TIME).until(EC.invisibility_of_element_located((By.CLASS_NAME, 'orbit')))
|
||||
self._chrome = chrome
|
||||
mac_list =[ i.find_element(By.XPATH, './../..').text for i in chrome.find_elements(By.CSS_SELECTOR,'div.va-item-label--caption')]
|
||||
self._mac_list = {i.split('\n')[1]:i.split('\n')[0][1] for i in mac_list}
|
||||
chart_list = [i.find_element(By.XPATH, './../..').text.split('\n') for i in chrome.find_elements(By.CSS_SELECTOR,'h5.mt-0')[1:]]
|
||||
self._chart_list = {i[0]: (i[1].split(" | ") if len(i)>1 else False) for i in chart_list}
|
||||
# print(self._chart_list)
|
||||
self._call_chart_list = {self._chart_list[i][1][-5:]+'_default' if self._chart_list[i] else i :i for i in self._chart_list}
|
||||
print('Device list:', self._mac_list)
|
||||
print('Chart list:', self._call_chart_list)
|
||||
# print(self._mac_list)
|
||||
# print([i.text for i in chrome.find_elements(By.CSS_SELECTOR, 'div.va-tree-category')])
|
||||
|
||||
def selectMode(self, mode_name, set_ID):
|
||||
Devices_mac = select_div(self._chrome,'div.va-item-label--caption', set_ID, 6)
|
||||
click_by_item_text(Devices_mac, By.CSS_SELECTOR,'label.va-select__label','WORKING MODE')
|
||||
Drop_list = Devices_mac.find_element(By.CLASS_NAME,'va-dropdown__content')
|
||||
click_by_item_text(Drop_list, By.CSS_SELECTOR,'span',mode_name)
|
||||
|
||||
def setEDCParameter(self, key_name, value, set_ID):
|
||||
# print(test.text)
|
||||
Devices_mac = select_div(self._chrome, 'div.va-item-label--caption', set_ID, 6)
|
||||
mode_par_div = click_by_item_text(Devices_mac, By.CSS_SELECTOR, 'div.va-tree-category', key_name)
|
||||
input_feild = click_by_item_text(mode_par_div, By.CLASS_NAME,'va-input__container__input','')
|
||||
if input_feild:
|
||||
input_feild.send_keys(Keys.CONTROL + "a")
|
||||
input_feild.send_keys(Keys.DELETE)
|
||||
input_feild.send_keys(value)
|
||||
else:
|
||||
button = click_by_item_text(mode_par_div, By.CSS_SELECTOR,'div.va-button__content__title',value)
|
||||
# print(input_feild.get_attribute('value'))
|
||||
click_by_item_text(Devices_mac, By.CSS_SELECTOR,'div.va-tree-category__header-label',key_name)
|
||||
|
||||
def modeSwitch(self, startOrStop, set_ID):
|
||||
if set_ID == 'ALL':
|
||||
click_by_item_text(self._chrome, By.CLASS_NAME, 'va-button__content__title', startOrStop.upper()+' ALL')
|
||||
return True
|
||||
Devices_mac = select_div(self._chrome,'div.va-item-label--caption', set_ID, 6)
|
||||
if click_by_item_text(Devices_mac, By.CLASS_NAME, 'va-button__content__title', startOrStop.upper()) == False:
|
||||
print('*** WARNING: Devices',set_ID,'already'+startOrStop.lower()+'.')
|
||||
|
||||
def IdleTillStop(self, wait_sec, mac_ID):
|
||||
time.sleep(int(wait_sec))
|
||||
Devices_mac = select_div(self._chrome, 'div.va-item-label--caption', mac_ID, 3)
|
||||
WebDriverWait(Devices_mac,100).until(EC.text_to_be_present_in_element((By.CLASS_NAME, 'va-button__content__title'),'START'))
|
||||
|
||||
def addChart(self, set_chart_name):
|
||||
click_by_item_text(self._chrome, By.CLASS_NAME, 'va-button__content__title', 'ADD CHART')
|
||||
chart_list = self._chrome.find_elements(By.CSS_SELECTOR,'h5.mt-0')[-1].text
|
||||
self._call_chart_list[set_chart_name] = chart_list
|
||||
print('Chart list: ',self._call_chart_list)
|
||||
|
||||
def setChart(self, set_chart_name, x_source, x_channel, y_source, y_channel, subplot):
|
||||
source_value = {'X': x_source,'Y': y_source}
|
||||
channel_value = {'X': x_channel,'Y': y_channel}
|
||||
chart_name = self._call_chart_list[[i for i in self._call_chart_list if set_chart_name in i][0]]
|
||||
chart_card = click_by_item_text(self._chrome, By.CSS_SELECTOR, 'div.va-card', chart_name, click = False)
|
||||
click_by_item_text(chart_card, By.CSS_SELECTOR, 'div.va-tab__content', 'SOURCE')
|
||||
for i in ['X','Y']:
|
||||
source_div = click_by_item_text(chart_card, By.CSS_SELECTOR, 'div.va-dropdown', i + ' SOURCE')
|
||||
check_mac = check_complete(source_value[i], list(self._mac_list))
|
||||
click_by_item_text(source_div, By.CSS_SELECTOR, 'li.va-select__option', list(self._mac_list.values())[check_mac] if check_mac!=-1 else source_value[i])
|
||||
print(source_div.text.split('\n'))
|
||||
if source_div.text.split('\n')[1].strip() not in 'Time':
|
||||
channel_div = click_by_item_text(chart_card, By.CSS_SELECTOR, 'div.va-dropdown', i + ' CHANNEL')
|
||||
click_by_item_text(channel_div, By.CSS_SELECTOR, 'li.va-select__option',channel_value[i] )
|
||||
subplot_div = click_by_item_text(chart_card, By.CSS_SELECTOR, 'div.va-dropdown', 'SUBPLOT')
|
||||
click_by_item_text(subplot_div, By.CSS_SELECTOR, 'li.va-select__option',subplot)
|
||||
click_by_item_text(chart_card, By.CLASS_NAME, 'va-button__content__title','Add')
|
||||
click_by_item_text(chart_card, By.CSS_SELECTOR, 'div.va-tab__content', 'CHART')
|
||||
# print(source_div.text)
|
||||
|
||||
def click_by_item_text (chrome, item, item_name, text, click=True, key_like = True, error_mes = True):
|
||||
button = chrome.find_elements(item,item_name)
|
||||
button_list = [i.text for i in button]
|
||||
button_search = [i for i in range(len(button_list)) if text == button_list[i]]
|
||||
button_search = [i for i in range(len(button_list)) if text in button_list[i]] if (len(button_search) <1 and key_like) else button_search
|
||||
|
||||
if len(button_search) <1:
|
||||
if error_mes:
|
||||
print('*** ERROR: Found no button include keyword',text + '.')
|
||||
return False
|
||||
else:
|
||||
if click:
|
||||
button[button_search[0]].click()
|
||||
if len(button_search)>1 and error_mes:
|
||||
print('*** WARNING: Found more than one button include keyword',text + '.',[button_list[i] for i in button_search])
|
||||
print('*** Clicked the first option.')
|
||||
elif len(button_search)>1 and error_mes:
|
||||
print('*** WARNING: Found more than one button include keyword.',[button_list[i] for i in button_search])
|
||||
return button[button_search[0]]
|
||||
|
||||
def select_div(chrome,css_name, text, path_num, error_mes=False):
|
||||
Elite_mac = click_by_item_text(chrome,By.CSS_SELECTOR, css_name, text, click=False, error_mes= error_mes)
|
||||
if Elite_mac==False:
|
||||
return False
|
||||
Devices_mac = Elite_mac.find_element(By.XPATH, '.'+'/..'*path_num)
|
||||
return Devices_mac
|
||||
|
||||
def check_complete(value, LIST, key_like = True):
|
||||
return_list = [i for i in range(len(LIST)) if value == LIST[i]]
|
||||
return_list = [i for i in range(len(LIST)) if value in LIST[i]] if (len(return_list) <1 and key_like) else return_list
|
||||
if len(return_list)>1:
|
||||
print('*** WARNING: Found more than one item include keyword',value+'.',[LIST[i] for i in return_list])
|
||||
return return_list[0] if len(return_list)>0 else -1
|
||||
@@ -0,0 +1,28 @@
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.chrome.options import Options
|
||||
import selen_func, time, sys, inspect
|
||||
|
||||
set_ID = 'A4:DA:32:D4:EE:3A'
|
||||
url = 'http://192.168.2.1/'
|
||||
|
||||
if __name__ == '__main__':
|
||||
options = Options()
|
||||
options.add_argument("--disable-notifications")
|
||||
options.add_experimental_option('excludeSwitches', ['enable-logging'])
|
||||
chrome = webdriver.Chrome('./chromedriver', chrome_options=options)
|
||||
|
||||
classes = [cls_name for cls_name, cls_obj in inspect.getmembers(sys.modules['selen_func']) if inspect.isclass(cls_obj) and cls_obj.__module__.find('selen_func')>=0]
|
||||
print(classes)
|
||||
page_select = input('>>> ').strip()
|
||||
with open('commend_line/commend_line.txt','w')as f:
|
||||
while page_select != 'END_ALL':
|
||||
page_sel_split = page_select.split(' ')
|
||||
class_index = selen_func.check_complete(page_sel_split[1],classes) if len(page_sel_split)>1 else -1
|
||||
if page_sel_split[0] == 'START' and class_index != -1:
|
||||
f.write('START '+classes[class_index]+'\n')
|
||||
print('START',classes[class_index])
|
||||
DevicesPage_Test = selen_func.startDevicesPage(chrome, url, classes[class_index] ,f)
|
||||
else:
|
||||
print("*** ERROR: Didn't find the corresponding page.")
|
||||
page_select = input('>>> ').strip()
|
||||
f.write("END_ALL\n")
|
||||
@@ -0,0 +1,47 @@
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.chrome.options import Options
|
||||
import selen_func, time, sys, inspect
|
||||
|
||||
set_ID = 'A4:DA:32:D4:EE:3A'
|
||||
url = 'http://192.168.2.1/'
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
txt_name = 'commend_line/commend_line'
|
||||
file = open(txt_name+'.txt','r')
|
||||
lines_raw = file.readlines()
|
||||
Line = []
|
||||
line_temp = []
|
||||
|
||||
for i in lines_raw:
|
||||
if i[0] != ' ':
|
||||
if len(line_temp)>0:
|
||||
Line.append(line_temp)
|
||||
Line.append(i.strip())
|
||||
else:
|
||||
line_temp.append(i.strip())
|
||||
|
||||
options = Options()
|
||||
options.add_argument("--disable-notifications")
|
||||
options.add_experimental_option('excludeSwitches', ['enable-logging'])
|
||||
chrome = webdriver.Chrome('./chromedriver', chrome_options=options)
|
||||
chrome.maximize_window()
|
||||
|
||||
classes = [cls_name for cls_name, cls_obj in inspect.getmembers(sys.modules['selen_func']) if inspect.isclass(cls_obj) and cls_obj.__module__.find('selen_func')>=0]
|
||||
|
||||
page_select = Line.pop(0)
|
||||
with open('commend_line/commend_line_txt.txt','w')as f:
|
||||
while page_select != 'END_ALL':
|
||||
page_sel_split = page_select.split(' ')
|
||||
class_index = selen_func.check_complete(page_sel_split[1],classes) if len(page_sel_split)>1 else -1
|
||||
if page_sel_split[0] == 'START' and class_index != -1:
|
||||
f.write('START '+classes[class_index]+'\n')
|
||||
print('START',classes[class_index])
|
||||
DevicesPage_Test = selen_func.startDevicesPage(chrome, url, classes[class_index], f, row_list = Line.pop(0))
|
||||
if len(Line)>0:
|
||||
page_select = Line.pop(0)
|
||||
else:
|
||||
print("Txt file didn't end with 'END_ALL'.")
|
||||
break
|
||||
f.write("END_ALL\n")
|
||||
a = input(">")
|
||||
Reference in New Issue
Block a user