學(xué)校門戶網(wǎng)站建設(shè)的意義優(yōu)化王
說明:該篇博客是博主一字一碼編寫的,實(shí)屬不易,請尊重原創(chuàng),謝謝大家!
首先,今年比較忙沒有多余時(shí)間去實(shí)操創(chuàng)作分享文章給大家,那就給大家分享下博主在實(shí)際工作中的一點(diǎn)點(diǎn)內(nèi)容吧,就當(dāng)交流交流~
需求
敘述
目前公司有個(gè)跨平臺(tái)大項(xiàng)目正在內(nèi)測中,是基于QT框架研發(fā)的客戶端應(yīng)用程序
客戶端程序的更新不像web端程序只需要清理緩存(存在js更新時(shí))刷新即可更新至最新代碼,就需要服務(wù)端維護(hù)升級批次->客戶端檢測更新->拉取升級列表下載批次文件->替換程序目錄下的文件(數(shù)據(jù)庫增量升級以及腳本文件)
當(dāng)程序代碼打包至公司內(nèi)網(wǎng)升級目錄下,每次都需要去通知維護(hù)人,維護(hù)人則需要在升級平臺(tái)維護(hù)及開放程序版本批次,整個(gè)流程如下:
1、登錄進(jìn)入升級平臺(tái)
2、選擇項(xiàng)目
2.1 Windows64
2.2 Windows32
2.3 統(tǒng)信aarch64
2.4 統(tǒng)信amd64
2.5 統(tǒng)信arm64
2.6 銀河麒麟loongarch64
2.7 銀河麒麟arm64
2.8 銀河麒麟amd64
2.9 中標(biāo)麒麟arm64
2.10 中標(biāo)麒麟amd64
2.11 MacX86_64
2.12 MacArm64
3、新建批次
4、導(dǎo)入本地文件
5、上傳到下載服務(wù)器
6、升級說明
7、產(chǎn)品版本號和用戶顯示版本號配置
8、開放批次
8.1 內(nèi)測開放
8.2 正式開放
PS:由于是公司還未上線的項(xiàng)目,所以不能細(xì)致透露
痛點(diǎn)1:每次需要研發(fā)經(jīng)理通知(存在忘記通知或延遲通知)
痛點(diǎn)2:手動(dòng)維護(hù)繁瑣枯燥,批次版本信息容易維護(hù)錯(cuò)誤
痛點(diǎn)3:忘記或延遲通知相應(yīng)人員進(jìn)行測試
解決
敘述
與研發(fā)經(jīng)理進(jìn)行約定,每次程序打包生成到指定的共享目錄,編寫程序進(jìn)行10s檢測目錄下是否有批次版本升級文件產(chǎn)生,如果有則進(jìn)行記錄并自動(dòng)化進(jìn)行維護(hù)升級批次,開放批次后并下發(fā)通知消息到指定QQ群
解決痛點(diǎn)1:
通過last_state.cfg
配置文件存儲(chǔ)上一次(或第一次)目錄的狀態(tài),每個(gè)目錄記錄其最后一次修改時(shí)間,啟動(dòng)項(xiàng)目或項(xiàng)目運(yùn)行期間以此時(shí)間進(jìn)行判斷是否目錄有更新
# 要檢查的目錄列表
directories_to_check = [r"N:\windows\內(nèi)測\32", r"N:\windows\內(nèi)測\64", r"N:\windows\公測\32", r"N:\windows\公測\64", r"N:\uos\公測\aarch64"]last_state = {} # 上一次的目錄狀態(tài)字典upgrade_flag = None# 從配置中讀取上一次的目錄狀態(tài)
def read_last_state():global upgrade_flagif os.path.exists('last_state.cfg'):with open('last_state.cfg', 'r') as f:for line in f:path, last_time = line.strip().split('|')last_state[path] = float(last_time)upgrade_flag = Trueelse:upgrade_flag = False# 更新上一次的目錄狀態(tài)到配置
def update_last_state():global upgrade_flagupgrade_flag = Truewith open('last_state.cfg', 'w') as f:for path, last_time in last_state.items():f.write(f'{path}|{last_time}\n')# 循環(huán)判斷多個(gè)目錄下是否有新文件產(chǎn)生,并輸出文件名和目錄
def watch_dirs():while True:for directory_path in directories_to_check:for filename in os.listdir(directory_path):path = os.path.join(directory_path, filename)mtime = os.path.getmtime(path)if path not in last_state:new_directory_flag = Trueelse:cfg_mtime = float(last_state[path])if mtime > cfg_mtime:new_directory_flag = Trueelse:new_directory_flag = Falseif new_directory_flag:n_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")n_filename = "{%s}" % filenamef_path = r"{}\{}".format(directory_path, filename)if upgrade_flag:print(f'{n_time} 發(fā)現(xiàn)新目錄在 {directory_path} 中:{n_filename}')# 增量升級復(fù)制文件cp_file(f_path, filename)# 調(diào)用升級auto_update(f_path, filename)# 升級完成后獲取最新的目錄修改時(shí)間并賦值給對應(yīng)pathmtime = os.path.getmtime(path)last_state[path] = mtime # 更新目錄狀態(tài)update_last_state() # 更新目錄狀態(tài)到配置time.sleep(10) # 每10秒檢查一次
解決痛點(diǎn)2:
登錄升級平臺(tái),1選擇項(xiàng)目——2新增升級批次——3導(dǎo)入文件——4上傳至下載服務(wù)器——5版本配置——6升級說明——7開放批次,使用selenium框架進(jìn)行自動(dòng)化處理
def auto_update(f_path, batch):len_file = len(os.listdir(f_path))if len_file > 0:new_f_path = f_path.replace("\\", "_")file_path_list = new_f_path.split("_")os_name = file_path_list[1]env = file_path_list[2]frame_num = file_path_list[3]upgrade_str = random.choice(str_lst)if os_name == 'uos':os_name = "統(tǒng)信"os_type = os_name+frame_num# print(os_type)options = webdriver.EdgeOptions()options.add_experimental_option('detach', True) # 不自動(dòng)關(guān)閉瀏覽器driver = webdriver.Edge(options=options) # 引入edge驅(qū)動(dòng)driver.maximize_window()driver.get("http://xxxx")# 登錄平臺(tái)driver.find_element(by=By.XPATH, value='//*[@id="input_box"]/input').send_keys('yourname')driver.find_element(by=By.XPATH, value='//*[@id="login_box"]/div[2]/input').send_keys('yourpwd')driver.find_element(by=By.XPATH, value='//*[@id="login_box"]/button').click()time.sleep(1)# todo:切換項(xiàng)目名稱driver.find_element(by=By.XPATH, value='//*[@id="u20"]').click()time.sleep(1)ul = driver.find_element(by=By.XPATH, value='/html/body/div[5]/div/div/div/ul')all_project_list = ul.find_elements(by=By.XPATH, value='li')# print(all_project_list, type(all_project_list)) # 計(jì)算有多少個(gè)liindex = 0pro_num = len(all_project_list)for p_name in all_project_list:index+=1# print(index, p_name.text)if os_type in p_name.text.lower():x_path = '/html/body/div[5]/div/div/div/ul/li[{}]/span/a'.format(index)driver.find_element(by=By.XPATH, value=x_path).click()time.sleep(1)# list[-1].text # 用列表標(biāo)識(shí)符取最后一個(gè)li# todo:新增升級批次driver.find_element(by=By.CSS_SELECTOR, value='#u17_div > div > span > svg').click()time.sleep(0.5)y = batch.split(".")[2][:2]m = batch.split(".")[2][2:]u_m = batch.split(".")[2][2:].replace("0", "")d = int(batch.split(".")[-1][:2]) - 10if len(str(d)) == 1:u_d = "0{}".format(d)else:u_d = dnew_batch_day = "20{}.{}.{}".format(y, m, u_d)u_new_batch_day = "20{}.{}.{}".format(y, u_m, d)# print(batch, to_day, new_batch_day, m)u_batch = batch[-3:]if to_day != new_batch_day:b_xpath = '/html/body/div[last()]/div/div[2]/div/div[2]/div[2]/div/input'driver.find_element(by=By.XPATH, value=b_xpath).clear()time.sleep(0.5)driver.find_element(by=By.XPATH, value=b_xpath).send_keys(u_new_batch_day)u_batch_day = "{}.{}".format(new_batch_day, u_batch)else:u_batch_day = "{}.{}".format(to_day, u_batch)n_xpath = '/html/body/div[last()]/div/div[2]/div/div[2]/div[3]/button[2]/span'driver.find_element(by=By.XPATH, value=n_xpath).click()time.sleep(1)# todo:切換升級說明driver.find_element(by=By.XPATH, value='//*[@id="u27_div"]/ul/li[3]/span/div/span').click()time.sleep(0.5)driver.find_element(by=By.XPATH, value='//*[@id="u27_div"]/div[3]/textarea').send_keys(upgrade_str)time.sleep(0.5)# todo:切換版本配置driver.find_element(by=By.XPATH, value='//*[@id="u27_div"]/ul/li[2]/span/div/span').click()time.sleep(0.5)driver.find_element(by=By.XPATH, value='//*[@id="u27_div"]/div[2]/div[1]/input').send_keys(batch)time.sleep(0.5)driver.find_element(by=By.XPATH, value='//*[@id="u27_div"]/div[2]/div[2]/input').send_keys(u_batch_day)time.sleep(0.5)# todo:切換文件配置driver.find_element(by=By.XPATH, value='//*[@id="u27_div"]/ul/li[1]/span/div/span').click()# todo 導(dǎo)入文件driver.find_element(by=By.XPATH, value='//*[@id="u27_div"]/div[1]/div/div[1]/button[1]/span[2]').click()time.sleep(0.5)dr_xpath = '/html/body/div[last()]/div/div[2]/div/div[2]/div[2]/div/span/div[1]/span/div/button/span[2]'driver.find_element(by=By.XPATH, value=dr_xpath).click()time.sleep(1)# todo 上傳文件# 按shift以及松shift鍵win32api.keybd_event(16, 0, 0, 0)win32api.keybd_event(16, 0, win32con.KEYEVENTF_KEYUP, 0)time.sleep(0.5)autoit.send(f_path)time.sleep(1)win32api.keybd_event(13, 0, 0, 0)win32api.keybd_event(13, 0, win32con.KEYEVENTF_KEYUP, 0)win32api.keybd_event(13, 0, 0, 0)win32api.keybd_event(13, 0, win32con.KEYEVENTF_KEYUP, 0)time.sleep(1)# todo 計(jì)算打開彈窗居中的坐標(biāo),并移動(dòng)至此c_x, c_y = autoit.win_get_client_size("打開")m_x = int(int(center_x) - (int(c_x) / 2))m_y = int(int(center_y) - (int(c_y) / 2))autoit.win_move("打開", m_x, m_y)time.sleep(1)autoit.mouse_click("left", int(center_x), int(center_y))time.sleep(0.5)win32api.keybd_event(17, 0, 0, 0)win32api.keybd_event(65, 0, 0, 0)win32api.keybd_event(65, 0, win32con.KEYEVENTF_KEYUP, 0)win32api.keybd_event(17, 0, win32con.KEYEVENTF_KEYUP, 0)time.sleep(0.5)win32api.keybd_event(13, 0, 0, 0)win32api.keybd_event(13, 0, win32con.KEYEVENTF_KEYUP, 0)time.sleep(1)qr_xpath = "/html/body/div[last()]/div/div[2]/div/div[2]/div[3]/button[2]/span"driver.find_element(by=By.XPATH, value=qr_xpath).click()len_file = len(os.listdir(f_path))print("{}目錄文件個(gè)數(shù)為:{}個(gè)".format(batch, len_file))if 0 < len_file <= 20:print("開始導(dǎo)入文件,等待10秒....")time.sleep(10)else:print("開始導(dǎo)入文件,等待30秒....")time.sleep(30)driver.find_element(by=By.XPATH, value='//*[@id="table"]/div/div[1]/table/thead/tr[1]/th[1]/div/label/span/span').click()time.sleep(0.5)driver.find_element(by=By.XPATH, value='//*[@id="u27_div"]/div[1]/div/div[1]/button[2]/span[2]').click()time.sleep(0.5)driver.find_element(by=By.XPATH, value='//*[@id="tablefwq"]/div/div[1]/table/thead/tr[1]/th[1]/label/span/span').click()time.sleep(0.5)driver.find_element(by=By.CSS_SELECTOR, value='body > div:last-child > div > div.ant-modal-wrap > div > div.ant-modal-content > div.ant-modal-footer > button.ant-btn.ant-btn-primary > span').click()if 0 < len_file <= 20:print("開始上傳文件至下載服務(wù)器,等待15秒....")time.sleep(15)else:print("開始上傳文件至下載服務(wù)器,等待45秒....")time.sleep(45)# todo:下拉滾動(dòng)底部,開放版本driver.find_element(by=By.XPATH, value='//*[@id="u26_div"]/div[2]').click()time.sleep(0.2)win32api.keybd_event(35, 0, 0, 0)win32api.keybd_event(35, 0, win32con.KEYEVENTF_KEYUP, 0)time.sleep(0.2)driver.find_element(by=By.XPATH, value='//*/li[last()]/span/div/div/div/span[1]').click()time.sleep(0.5)driver.switch_to.default_content()time.sleep(0.5)driver.quit()else:print("警告!目錄:{} 下的升級文件為空,將不進(jìn)行升級調(diào)用!".format(f_path))
解決痛點(diǎn)3:
維護(hù)升級批次成功后,將向指定QQ群發(fā)送自定義消息,這里需要借助go-cqhttp框架,下載解壓后,按一下步驟進(jìn)行配置即可
- Step1:下載后解壓
go-cqhttp_windows_amd64.zip
,點(diǎn)擊運(yùn)行exe
- Step2:運(yùn)行成功后,會(huì)生成
go-cqhttp.bat
文件,再運(yùn)行這個(gè)批處理文件,出現(xiàn)如下窗口
- Step3:選擇
0
,回車;編輯生成配置文件config.yml
,切記只填寫qq號(密碼不填寫,選擇掃碼登錄,這樣更安全且不會(huì)出現(xiàn)錯(cuò)誤)
- Step4:編輯打開目錄下產(chǎn)生的
device.json
文件,修改其中protocol
的值為2
,否則一直登陸失敗
配置完成后,拿出你的手機(jī)打開QQ進(jìn)行掃碼登錄,登錄后控制臺(tái)日志出現(xiàn)警告不用管
接下來就是編寫一個(gè)def
方法來實(shí)現(xiàn)與go-cqhttp
框架的交互,其實(shí)原理就是監(jiān)聽本地5700 socket
消息,就跟以前飛書發(fā)消息回復(fù)消息是一樣原理
def send_msg(resp_dict):client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)ip = '127.0.0.1'client.connect((ip, 5700))msg_type = resp_dict['msg_type'] # 回復(fù)類型(群聊/私聊)number = resp_dict['number'] # 回復(fù)賬號(群號/好友號)msg = resp_dict['msg'] # 要回復(fù)的消息# 將字符中的特殊字符進(jìn)行url編碼msg = msg.replace(" ", "%20")msg = msg.replace("\n", "%0a")if msg_type == 'group':payload = "GET /send_group_msg?group_id=" + number + "&message=" + msg + " HTTP/1.1\r\nHost:" + ip + ":5700\r\nConnection: close\r\n\r\n"elif msg_type == 'private':payload = "GET /send_private_msg?user_id=" + number + "&message=" + msg + " HTTP/1.1\r\nHost:" + ip + ":5700\r\nConnection: close\r\n\r\n"new_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")print("{} 發(fā)送{}".format(new_time, payload))client.send(payload.encode("utf-8"))client.close()
最后在auto_update
方法中調(diào)用send_msg
方法即可
if env == "內(nèi)測":driver.find_element(by=By.CSS_SELECTOR, value='body > div:nth-last-child(2) > div > div > div > ul > li:nth-child(2) > span > a').click()msg = "內(nèi)測升級 {}_{}_{}".format(os_name, frame_num, batch)
else:driver.find_element(by=By.CSS_SELECTOR, value='body > div:nth-last-child(2) > div > div > div > ul > li:nth-child(3) > span > a').click()msg = "正式升級 {}_{}_{}".format(os_name, frame_num, batch)
resp_group_dict = {'msg_type': 'group', 'number': 'QQ群號', 'msg': msg}
send_msg(resp_group_dict)
效果截圖: