JS執行器在UI自動化測試中的應用

前言

在進行UI自動化過程會遇到滾動條下拉、隱藏元素定位、只讀屬性元素的編輯、富文本處理等,此時可以使用JS執行器簡化我們的一些處理操作。

?

具體應用

JS執行器的使用步驟:

1.先寫個JS腳本,如果需要獲取操作后的值,JS腳本前面需要加return

2.使用webdriver的execute_script()方法執行腳本;方法中傳遞2個參數或1個參數;傳遞2個參數時,分別傳入JS腳本、要操作的頁面元素;傳遞1個參數時,傳入JS腳本,對整個webdriver做操作。

3.操作通過JS執行器注入了JS腳本的頁面元素或webdriver對象

?

接下來我們以百度、12306網站為例,演繹具體用法

1.通過JS腳本,獲取頁面元素的屬性值

from selenium import webdriverdriver = webdriver.Chrome()#創建瀏覽器對象
driver.maximize_window()#窗口最大化driver.get(r'https://www.baidu.com')#訪問百度
el = driver.find_element('id','su') #頁面的百度一下元素
'''
寫JS腳本,寫JS腳本的步驟:
js:定義一個變量名js,用于存放所寫的JS季報表
= :賦值
JS腳本全部用引號引起來,整個腳本就是一個字符串
arguments[0]:理解為占位符,代值被操作的元素或對象
.:連接被操作的元素對象與所做的具體操作
getAttribute():我們這里的舉例的操作為:獲取元素的某個屬性值
JS腳本最前面加上return,是因為我們要獲取對元素操作后的值
'''
js = "return arguments[0].getAttribute('value')" #JS腳本的意思為:返回某個元素的value屬性的值
value = driver.execute_script(js,el)#執行JS腳本,傳入的2個參數依次為:要執行的腳本、要操作的對象
print(value)#打印獲取到的值
driver.quit()#關閉瀏覽器

執行的結果:

2.通過JS腳本,獲取頁面元素的文本值

from selenium import webdriverdriver = webdriver.Chrome()#創建瀏覽器對象
driver.maximize_window()#窗口最大化driver.get(r'https://www.12306.cn/index/')#訪問12306#頁面的出發日期元素
el = driver.find_element('xpath','/html/body/div[3]/div[2]/div/div[1]/div/div[2]/div[1]/div[1]/div[2]/label') #
js = "return arguments[0].innerHTML" #JS腳本的意思為:返回某個元素的文本值
value = driver.execute_script(js,el)#執行JS腳本,傳入的2個參數依次為:要執行的腳本、要操作的對象
print(value)#打印獲取到的值
driver.quit()#關閉瀏覽器

?運行結果

3.通過JS腳本,刪除頁面元素的屬性值,然后對頁面元素進行操作

?

我們發現出發日期輸入框因為有readonly屬性,導致這個輸入框我們無法直接輸入日期,在實際的自動化操作中我們就只能通過點擊右邊的日歷控件,從而選擇日期,這樣操作就變得非常的復雜,現在我們通過執行JS腳本,刪除中個輸入框的readonly屬性,實現對這個輸入框直接輸入日期


from selenium import webdriver
from time import sleep
driver = webdriver.Chrome()#創建瀏覽器對象
driver.maximize_window()#窗口最大化driver.get(r'https://www.12306.cn/index/')#訪問12306#頁面的出發日期輸入框
el = driver.find_element('xpath','//input[@id="train_date" and @class="input"]')
js = "arguments[0].removeAttribute('readonly')" #JS腳本的意思為:移除某個元素的readonly屬性
driver.execute_script(js,el)#執行JS腳本,傳入的2個參數依次為:要執行的腳本、要操作的對象
sleep(1)#強制等待1秒
el.clear() #清空輸入框內容
el.send_keys("2021-07-11")#對輸入框進行輸入操作
sleep(3)
driver.quit()#關閉瀏覽器

?執行結果

4.通過JS腳本,修改頁面元素的屬性值

from selenium import webdriver
from time import sleepdriver = webdriver.Chrome()#創建瀏覽器對象
driver.maximize_window()#窗口最大化driver.get(r'https://www.baidu.com')#訪問百度
el = driver.find_element('id','su') #頁面的百度一下元素js = "return arguments[0].setAttribute('value','AAAAA')" #JS腳本的意思為:返回某個元素的value屬性的值
driver.execute_script(js,el)#執行JS腳本,傳入的2個參數依次為:要執行的腳本、要操作的對象
sleep(10)
driver.quit()#關閉瀏覽器

?執行結果

5.執行JS腳本,進行滾動條操作

from selenium import webdriver
from time import sleepdriver = webdriver.Chrome()#創建瀏覽器對象
driver.maximize_window()#窗口最大化
driver.implicitly_wait(30)driver.get(r'https://www.baidu.com')#訪問百度
driver.find_element('id','kw').send_keys("它石科技")
driver.find_element('id','su').click()
sleep(3)
js = "document.documentElement.scrollTop=1000" #向下滾動
driver.execute_script(js)#執行JS腳本
sleep(3)
js1 = "document.documentElement.scrollTop=0" #先上滑動
driver.execute_script(js1)#執行JS腳本
sleep(3)
js2 = "window.scrollTo(100,200)" #左右滑動
driver.execute_script(js2)
sleep(3)
js3 = "arguments[0].scrollIntoView()"
el = driver.find_element('xpath','//span[text()="百度熱搜"]')
sleep(1)
driver.execute_script(js3,el)
sleep(3)
driver.quit()#關閉瀏覽器

?

執行結果:

由于是動態的圖,這里就不截圖了,大家可以按照代碼自己嘗試

總結:

selenium底層就方式通過執行JS腳本來操作頁面元素的,所以當我們使用普通封裝的常規操作方法無法進行相關操作時,可以使用JS執行器來達到我們的操作目的。

3.logging模塊的封裝處理

具體封裝好的log.py文件代碼如下:

import logging
import os
import time
class Logging():
def make_log_dir(self,dirname='logs'): #創建存放日志的目錄,并返回目錄的路徑
now_dir = os.path.dirname(__file__)
father_path = os.path.split(now_dir)[0]
path = os.path.join(father_path,dirname)
path = os.path.normpath(path)
if not os.path.exists(path):
os.mkdir(path)
return path
def get_log_filename(self):#創建日志文件的文件名格式,便于區分每天的日志
filename = "{}.log".format(time.strftime("%Y-%m-%d",time.localtime()))
filename = os.path.join(self.make_log_dir(),filename)
filename = os.path.normpath(filename)
return filename
def log(self):#生成日志的主方法
logger = logging.getLogger()
logger.setLevel(logging.INFO)
if not logger.handlers: #作用:防止日志重打
sh = logging.StreamHandler()
fh =
logging.FileHandler(filename=self.get_log_filename(),mode='a',encoding="utf-8")
fmt = logging.Formatter("%(asctime)s-%(levelname)s-%(filename)s-
Line:%(lineno)d-Message:%(message)s")
sh.setFormatter(fmt=fmt)
fh.setFormatter(fmt=fmt)
logger.addHandler(sh)
logger.addHandler(fh)
return logger
if __name__ == '__main__':
#Logging().log().debug("1111111111111111111111")
Logging().log().info("222222222222222222222222")
Logging().log().error("附件為IP飛機外婆家二分IP文件放")

selenium中的非input型上傳

我們在之前的文章中介紹了有四種方式可以實現,接下來我們展開說明一下實現

win32gui

廢話不多說,上代碼先:

示例網址:http://www.sahitest.com/demo/php/fileUpload.htm

# -*- coding: utf-8 -*-
from selenium import webdriver
import win32gui
import win32con
import timedr = webdriver.Firefox()
dr.get('http://sahitest.com/demo/php/fileUpload.htm')
upload = dr.find_element_by_id('file')
upload.click()
time.sleep(1)# win32gui
dialog = win32gui.FindWindow('#32770', u'文件上傳')  # 對話框
ComboBoxEx32 = win32gui.FindWindowEx(dialog, 0, 'ComboBoxEx32', None) 
ComboBox = win32gui.FindWindowEx(ComboBoxEx32, 0, 'ComboBox', None)
Edit = win32gui.FindWindowEx(ComboBox, 0, 'Edit', None)  # 上面三句依次尋找對象,直到找到輸入框Edit對象的句柄
button = win32gui.FindWindowEx(dialog, 0, 'Button', None)  # 確定按鈕Buttonwin32gui.SendMessage(Edit, win32con.WM_SETTEXT, None, 'd:\\baidu.py')  # 往輸入框輸入絕對地址
win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button)  # 按buttonprint upload.get_attribute('value')
dr.quit()

結果:

baidu.py

在這里你需要一個非常重要的小工具:Spy++,百度一下有很多,當然你也可以用autoIT自帶的工具,不過沒有這個好用,建議去下一個吧。

而且,你得安裝pywin32的庫,你可以到這里找到對應你Python版本的庫,注意32位還是64位一定要和你安裝的Python版本對應。

安裝完成之后在【開始菜單Python的文件夾】里看到PyWin32的文檔【Python for?GitCode - 全球開發者的開源社區,開源代碼托管平臺 Documentation】,你能從中找到對應的方法API。

簡單介紹幾個用到的:

win32gui.FindWindow(lpClassName=None, lpWindowName=None):

自頂層窗口開始尋找匹配條件的窗口,并返回這個窗口的句柄。
lpClassName:類名,在Spy++里能夠看到
lpWindowName:窗口名,標題欄上能看到的名字
代碼示例里我們用來尋找上傳窗口,你可以只用其中的一個,用classname定位容易被其他東西干擾,用windowname定位不穩定,不同的上傳對話框可能window_name不同,怎么定位取決于你的情況。
win32gui.FindWindowEx(hwndParent=0, hwndChildAfter=0, lpszClass=None, lpszWindow=None)

搜索類名和窗體名匹配的窗體,并返回這個窗體的句柄。找不到就返回0。
hwndParent:若不為0,則搜索句柄為hwndParent窗體的子窗體。
hwndChildAfter:若不為0,則按照z-index的順序從hwndChildAfter向后開始搜索子窗體,否則從第一個子窗體開始搜索。
lpClassName:字符型,是窗體的類名,這個可以在Spy++里找到。
lpWindowName:字符型,是窗口名,也就是標題欄上你能看見的那個標題。
代碼示例里我們用來層層尋找輸入框和尋找確定按鈕
win32gui.SendMessage(hWnd, Msg, wParam, lParam)

hWnd:整型,接收消息的窗體句柄
Msg:整型,要發送的消息,這些消息都是windows預先定義好的,可以參見系統定義消息(System-Defined Messages)
wParam:整型,消息的wParam參數
lParam:整型,消息的lParam參數
代碼示例里我們用來向輸入框輸入文件地址以及點擊確定按鈕
至于win32api模塊以及其他的方法,這里不進行更多描述,想要了解的自行百度或看pywin32文檔。

SendKeys

首先要安裝SendKeys庫,可以用pip安裝

pip install SendKeys

代碼示例:

示例網址:http://www.sahitest.com/demo/php/fileUpload.htm

# -*- coding: utf-8 -*-
from selenium import webdriver
import win32gui
import win32con
import timedr = webdriver.Firefox()
dr.get('http://sahitest.com/demo/php/fileUpload.htm')
upload = dr.find_element_by_id('file')
upload.click()
time.sleep(1)# SendKeys
SendKeys.SendKeys('D:\\baidu.py')  # 發送文件地址
SendKeys.SendKeys("{ENTER}") # 發送回車鍵print upload.get_attribute('value')
dr.quit()

?

結果:

baidu.py
1
通過SendKeys庫可以直接向焦點里輸入信息,不過要注意在打開窗口是略微加一點等待時間,否則容易第一個字母send不進去(或者你可以在地址之前加一個無用字符),不過我覺得這種方法很不穩定,不推薦。

keybd_event

win32api提供了一個keybd_event()方法模擬按鍵,不過此方法比較麻煩,也不穩定,所以很不推薦,下面給出部分代碼示例,如果想要研究,可以自己研究研究

...# 先找一個input框,輸入想要上傳的文件的地址,剪切到剪貼板 
video.send_keys('C:\\Users\\Administrator\\Pictures\\04b20919fc78baf41fc993fd8ee2c5c9.jpg')
video.send_keys(Keys.CONTROL, 'a')  # selenium的send_keys(ctrl+a)
video.send_keys(Keys.CONTROL, 'x')  # (ctrl+x)
driver.find_element_by_id('uploadImage').click()  # 點擊上傳按鈕,打開上傳框# 粘貼(ctrl + v)
win32api.keybd_event(17, 0, 0, 0)  # 按下按鍵 ctrl
win32api.keybd_event(86, 0, 0, 0)  # 按下按鍵 v
win32api.keybd_event(86, 0, win32con.KEYEVENTF_KEYUP, 0)  # 升起按鍵 v
win32api.keybd_event(17, 0, win32con.KEYEVENTF_KEYUP, 0)  # 升起按鍵 ctrl
time.sleep(1)# 回車(enter)
win32api.keybd_event(13, 0, 0, 0)  # 按下按鍵 enter
win32api.keybd_event(13, 0, win32con.KEYEVENTF_KEYUP, 0)  # 升起按鍵 enter...

是不是很麻煩,當然,你甚至可以用按鍵把整個路徑輸入進去,不過,我想沒人愿意這么做的。而且在此過程中你不能隨意移動鼠標,不能使用剪貼板,太不穩定了,所以非常不建議你用這種辦法。

多文件上傳
接下來還有一種情況值得我們考慮,那就是多文件上傳。如何上傳多個文件,當然我們還是往輸入框里輸入文件路徑,所以唯一要搞清楚的就是多文件上傳時,文件路徑是怎么寫的。

我來告訴你吧,多文件上傳就是在文件路徑框里用引號括起單個路徑,然后用逗號隔開多個路徑,就是這么簡單,例如:
“D:\a.txt” “D:\b.txt”
但需要注意的是:只有多個文件在同一路徑下,才能這樣用,否則是會失敗的(下面的寫法是不可以的):
“C:\a.txt” “D:\b.txt”

接下里找一個例子試試:

# -*- coding: utf-8 -*-from selenium import webdriver
import win32gui
import win32con
import timedr = webdriver.Firefox()
dr.get('http://www.sucaijiayuan.com/api/demo.php?url=/demo/20150128-1')dr.switch_to.frame('iframe')  # 一定要注意frame
dr.find_element_by_class_name('filePicker').click()
time.sleep(1)dialog = win32gui.FindWindow('#32770', None)
ComboBoxEx32 = win32gui.FindWindowEx(dialog, 0, 'ComboBoxEx32', None)
ComboBox = win32gui.FindWindowEx(ComboBoxEx32, 0, 'ComboBox', None)
Edit = win32gui.FindWindowEx(ComboBox, 0, 'Edit', None)
button = win32gui.FindWindowEx(dialog, 0, 'Button', None)# 跟上面示例的代碼是一樣的,只是這里傳入的參數不同,如果愿意可以寫一個上傳函數把上傳功能封裝起來
win32gui.SendMessage(Edit, win32con.WM_SETTEXT, 0, '"d:\\baidu.py" "d:\\upload.py" "d:\\1.html"')
win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button)print dr.find_element_by_id('status_info').text
dr.quit()

結果:

選中3張文件,共1.17KB。
可見,多文件上傳并沒有那么復雜,也很簡單,唯一的區別就是輸入的參數不同而已。autoIT也可以實現,有興趣可以自己試試。

而且我們可以發現一點,就是上面的這個窗口的代碼跟之前示例中的基本是一樣,說明我們可以把上傳的部分抽出來,寫一個函數,這樣每次要上傳,直接去調用函數,傳入參數即可。

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/78606.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/78606.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/78606.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

解析Suna:全球首款開源通用AI智能體

導語: 嘿,哥們兒,最近 AI Agent 這塊兒挺火的,有個叫 Suna 的開源項目冒出來挺快!聽說只用了 3 周就開發出來了,但功能上感覺已經能跟那個商業版的 Manus掰掰手腕了。它能幫你搞定瀏覽器自動化、管文件、爬…

模板方法模式:定義算法骨架的設計模式

模板方法模式:定義算法骨架的設計模式 一、模式核心:模板方法定義算法骨架,具體步驟延遲到子類實現 在軟件開發中,經常會遇到這樣的情況:某個算法的步驟是固定的,但具體步驟的實現可能因不同情況而有所不…

淺談Java 內存管理:棧與堆,垃圾回收

在Java編程世界里,內存管理是一項極為關鍵的技能,它就像程序運行背后的“隱形守護者”,默默影響著程序的性能與穩定性。今天,咱們就來簡單學習一下Java內存管理中的兩大核心要點:棧與堆的內存分配機制,以及…

【WebGL小知識】WebGL平臺上不同Json的比較

今天來總結一下WebGL平臺上不同Json插件的差別,話不多說直接開始。 JsonUtility JsonUtility是Unity自帶的Json解析,無需另外安裝插件。 優點: Unity自帶,兼容性好,WebGL平臺可以使用輕量級,性能較好。 …

4.22tx視頻后臺開發一面

總時長大概在一個小時,主要提問C、操作系統、計網以及數據庫等方面,最后兩個算法編程題。 一上來先介紹項目 Linux下的mybash命令處理器和內存池 mybash可以再總結歸納一下,一上來有點緊張沒有條理 內存池是用邊界標識法寫的,…

從StandardMaterial和PBRMaterial到PBRMetallicRoughnessMaterial:Babylon.js材質轉換完全指南

在現代3D圖形開發中,基于物理的渲染(PBR)已成為行業標準。本文將深入探討如何在Babylon.js中將傳統StandardMaterial和PBRMaterial轉換為PBRMetallicRoughnessMaterial,并保持視覺一致性。 為什么需要轉換? PBRMetallicRoughnessMaterial作…

UEditor文檔在Servlet項目上的應用

UEditor 是一款功能強大的富文本編輯器,在項目中應用廣泛。 Ueditor使用 引入 UEditor 下載 UEditor:從 UEditor 官方網站(ueditor 官網)下載適合項目需求的版本。解壓文件:將下載的壓縮包解壓到項目的靜態資源目錄…

ThinkPHP快速使用手冊

目錄 介紹 安裝(windows環境) 安裝Composer 安裝ThinkPHP 目錄結構 配置文件 第一個接口(Controller層) Hello World 自定義Controller 請求參數 獲取查詢參數(Get請求) 獲取指定請求參數 獲取…

面向 C# 初學者的完整教程

🧱 一、項目結構說明 你的項目大致結構如下: TaskManager/ ├── backend/ │ ├── TaskManager.Core/ // 實體類和接口 │ ├── TaskManager.Infrastructure/ // 數據庫、服務實現 │ └── TaskManager.API/ // We…

Axios 的 GET 和 POST 請求:前端開發中的 HTTP 通信

🤍 前端開發工程師、技術日更博主、已過CET6 🍨 阿珊和她的貓_CSDN博客專家、23年度博客之星前端領域TOP1 🕠 牛客高級專題作者、打造專欄《前端面試必備》 、《2024面試高頻手撕題》、《前端求職突破計劃》 🍚 藍橋云課簽約作者、…

【前端】如何檢查內存泄漏

在實際的場景中,如果觀察到內存持續出現峰值,并且內存消耗一直沒有減少,那可能存在內存泄漏。 使用 Chrome DevTools 來識別內存圖和一些內存泄漏,我們需要關注以下兩個方面: ● 使用性能分析器可視化內存消耗&#xf…

JavaScript的JSON處理Map的弊端

直接使用 Map 會遇到的問題及解決方案 直接使用 Map 會導致數據丟失,因為 JSON.stringify 無法序列化 Map。以下是詳細分析及解決方法: 問題復現 // 示例代碼 const myMap new Map(); myMap.set(user1, { name: Alice }); myMap.set(user2, { name: B…

【數據結構】第五彈——Stack 和 Queue

文章目錄 一. 棧(Stack)1.1 概念1.2 棧的使用1.3 棧的模擬實現1.3.1 順序表結構1.3.2 進棧 壓棧1.3.3 刪除棧頂元素1.3.4 獲取棧頂元素1.3.5 自定義異常 1.4 棧的應用場景1.改變元素序列2. 將遞歸轉化為循環3. 四道習題 1.5 概念分區 二. 隊列(Queue)2.1 概念2.2 隊列的使用2.3…

第七屆能源系統與電氣電力國際學術會議(ICESEP 2025)

重要信息 時間:2025年6月20-22日 地點:中國-武漢 官網:www.icesep.net 主題 能源系統 節能技術、能源存儲技術、可再生能源、熱能與動力工程 、能源工程、可再生能源技術和系統、風力發…

深入解析C++ STL Stack:后進先出的數據結構

一、引言 在計算機科學中,棧(Stack)作為一種遵循后進先出(LIFO)?原則的數據結構,是算法設計和程序開發的基礎構件。C STL中的stack容器適配器以簡潔的接口封裝了底層容器的操作,為開發者提供了…

Golang | 自行實現并發安全的Map

核心思路,讀寫map之前加鎖!哈希思路,大map化分為很多個小map

Mac 「brew」快速安裝MySQL

安裝MySQL 在 macOS 上安裝 MySQL 環境可以通過Homebrew快速實現,以下是步驟指南: 方法 1:使用 Homebrew 安裝 MySQL 1. 安裝 Homebrew 如果尚未安裝 Homebrew,可以通過以下命令安裝: /bin/bash -c "$(curl -…

【數字孿生世界的搭建之旅:從0到1理解飛渡平臺】

數字孿生世界的搭建之旅:從0到1理解飛渡平臺 前言:數字分身的魔法 想象一下,如果你能在現實世界之外,創造一個物理世界的"分身",這個分身能完美復制現實中的一切變化,甚至可以預測未來可能發生…

【漏洞復現】Struts2系列

【漏洞復現】Struts2系列 1. 了解Struts21. Struts2 S2-061 RCE (CVE-2020-17530)1. 漏洞描述2. 影響版本3. 復現過程 1. 了解Struts2 Apache Struts2是一個基于MVC設計模式的Web應用框架,會對某些標簽屬性(比如 id)的…

[FPGA Video IP] Video Processing Subsystem

Xilinx Video Processing Subsystem IP (PG231) 詳細介紹 概述 Xilinx LogiCORE? IP Video Processing Subsystem (VPSS)(PG231)是一個高度可配置的視頻處理模塊,設計用于在單一 IP 核中集成多種視頻處理功能,包括縮放&#xf…