python pywinauto使用過(guò)程及問(wèn)題小結(jié)
1- pywinauto 中的uia是什么意思?
在
pywinauto
庫(kù)中,uia
指的是UI Automation,這是Windows操作系統(tǒng)提供的一種技術(shù)框架,用于實(shí)現(xiàn)用戶界面(UI)的自動(dòng)化測(cè)試和輔助功能訪問(wèn)。UI Automation是微軟從Windows Vista開(kāi)始引入的核心技術(shù),旨在為所有UI元素提供一致的編程接口,無(wú)論這些元素是由何種技術(shù)(如Win32、WPF、UWP等)實(shí)現(xiàn)的。在
pywinauto
中,通過(guò)指定backend="uia"
,用戶可以選擇使用UI Automation作為底層引擎來(lái)與應(yīng)用程序的UI元素進(jìn)行交互。這為自動(dòng)化測(cè)試提供了更廣泛的支持,尤其是在處理現(xiàn)代Windows應(yīng)用(尤其是使用WPF和UWP技術(shù)構(gòu)建的應(yīng)用)時(shí)更為有效。UI Automation后端相比傳統(tǒng)的win32
后端,提供了更豐富和高級(jí)的元素屬性、控制模式(Control Patterns)以及事件支持,使得自動(dòng)化腳本可以更加靈活和強(qiáng)大。使用UI Automation后端,開(kāi)發(fā)者可以更容易地定位和操作UI元素,如獲取元素的屬性、模擬鼠標(biāo)和鍵盤(pán)操作、監(jiān)聽(tīng)UI事件等,這對(duì)于創(chuàng)建復(fù)雜的自動(dòng)化測(cè)試場(chǎng)景尤其有用。
2-pywinauto 中main_window.child_window()方法及參數(shù)詳細(xì)介紹
在pywinauto
中,child_window()
方法是用于定位父窗口中的一個(gè)特定子窗口或控件。這對(duì)于自動(dòng)化測(cè)試中準(zhǔn)確地找到并操作特定的UI元素至關(guān)重要。下面是對(duì)child_window()
方法及其參數(shù)的詳細(xì)說(shuō)明:
基本用法
child_window()
方法屬于窗口對(duì)象,用于在當(dāng)前窗口的所有子窗口中搜索符合指定條件的第一個(gè)子窗口?;菊Z(yǔ)法如下:
Python
1parent_window.child_window(arguments)
其中,parent_window
是你已經(jīng)獲取到的窗口對(duì)象,arguments
是用于篩選子窗口的一系列關(guān)鍵字參數(shù)。
參數(shù)詳解
child_window()
方法接受多個(gè)關(guān)鍵字參數(shù)來(lái)精確地定位子窗口,常見(jiàn)的參數(shù)包括但不限于:
- title: 字符串,控件的標(biāo)題或文本。
- class_name: 字符串,控件的類名。
- control_type: 字符串,控件的類型(僅在UIA backend下有效)。
- auto_id: 字符串,控件的自動(dòng)化ID(AutomationId)。
- name: 字符串,控件的名稱屬性,可能與標(biāo)題或自動(dòng)化ID不同。
- backend: 字符串,指定后端類型,如
'win32'
或'uia'
,默認(rèn)自動(dòng)選擇。 - process: 整數(shù),指定目標(biāo)窗口所在的進(jìn)程ID。
- enabled: 布爾值,是否只查找啟用的控件。
- visible: 布爾值,是否只查找可見(jiàn)的控件。
- top_level_only: 布爾值,是否只在頂級(jí)窗口中查找。
- found_index: 整數(shù),當(dāng)找到多個(gè)匹配項(xiàng)時(shí),可以選擇特定索引的匹配項(xiàng)。
- control_id: 整數(shù),控件的ID(Windows API中的控件ID)。
- handle: 整數(shù)或
ctypes.c_void_p
,直接指定控件的句柄。 - regex_title: 正則表達(dá)式對(duì)象或字符串,用于匹配標(biāo)題的正則表達(dá)式。
- regex_class_name: 同上,但用于匹配類名的正則表達(dá)式。
- best_match: 字符串,用于
best_match()
邏輯,嘗試匹配最接近的控件。
示例
假設(shè)你想在記事本應(yīng)用的主窗口中找到名為“文件”(File)的菜單項(xiàng),可以這樣做:
Python
from pywinauto import Application app = Application(backend="uia").start("notepad.exe") main_window = app.window(title="無(wú)標(biāo)題 - 記事本") # 使用class_name和title定位子窗口 menu_item = main_window.child_window(class_name="MenuItem", title="文件")
注意事項(xiàng)
- 參數(shù)組合:通常,為了精確匹配,你需要結(jié)合多個(gè)參數(shù)一起使用。比如,同時(shí)使用
class_name
和title
可以更準(zhǔn)確地定位目標(biāo)控件。 - 性能考量:如果條件設(shè)置得過(guò)于寬泛,可能會(huì)導(dǎo)致搜索緩慢或找到錯(cuò)誤的控件。盡量使用具體的屬性來(lái)縮小搜索范圍。
- 異常處理:如果找不到匹配的子窗口,
child_window()
會(huì)拋出異常??梢允褂胻ry-except結(jié)構(gòu)來(lái)妥善處理這種情況。
通過(guò)靈活運(yùn)用child_window()
方法及其參數(shù),你可以高效地定位并操作UI自動(dòng)化中的各種元素。
3-child_window() / children() / descendants()方法介紹
如果要獲取父窗口下的所有直接子窗口(而不只是單個(gè)子窗口),可以使用children()
方法,它會(huì)返回一個(gè)包含所有直接子元素的列表。此元素定位方式,需要window類型為: WindowSpecification
例如:
Python
all_direct_children = parent_window.children()
而如果你需要遞歸地獲取所有子孫窗口(子窗口以及子窗口的子窗口等),可以使用descendants()
方法, 此元素定位的方式,需要window類型為:UiaWrapper:
Python
all_descendants = parent_window.descendants()
總結(jié)來(lái)說(shuō),parent_window.child_window()
是用于定位單個(gè)滿足特定條件的子窗口,而不是獲取所有子內(nèi)容。 若要獲取所有子內(nèi)容,請(qǐng)根據(jù)需要使用children()
或descendants()
。
4-pywinauto打開(kāi)程序時(shí),程序啟動(dòng)的比較慢,或點(diǎn)擊按鈕彈窗比較慢,或者打開(kāi)新窗口窗口渲染的比較慢,怎么添加合理的等待時(shí)間
在使用pywinauto
進(jìn)行自動(dòng)化操作時(shí),合理地添加等待時(shí)間是非常重要的,尤其是在程序啟動(dòng)慢、按鈕點(diǎn)擊后彈窗延遲或新窗口渲染速度較慢的情況下。這能確保腳本在繼續(xù)執(zhí)行下一步操作前,等待相關(guān)的UI元素準(zhǔn)備就緒。以下是幾種添加等待時(shí)間的方法:
1. 顯式等待(推薦)
使用wait
方法是最靈活且推薦的等待方式,它允許你指定等待的條件和超時(shí)時(shí)間。
等待窗口可見(jiàn):
Python
app.Window(title="窗口標(biāo)題").wait("visible", timeout=10)
等待控件可用:
Python
app.Dialog.child_window(title="按鈕標(biāo)題", control_type="Button").wait("enabled", timeout=20)
2. 靜態(tài)等待(time.sleep)
雖然不如顯式等待靈活,但在某些簡(jiǎn)單場(chǎng)景下可以使用time.sleep
來(lái)簡(jiǎn)單地暫停腳本執(zhí)行。
Python
import timetime.sleep(5) # 等待5秒
3. 動(dòng)態(tài)等待
對(duì)于某些不確定何時(shí)完成的操作,可以在循環(huán)中結(jié)合檢查條件和短暫停頓來(lái)實(shí)現(xiàn)動(dòng)態(tài)等待。
Python
import time timeout = 30 # 總超時(shí)時(shí)間 interval = 1 # 檢查間隔 start_time = time.time() while time.time() - start_time < timeout: if app.Window(title="窗口標(biāo)題").exists(): break time.sleep(interval) else: raise TimeoutError("窗口未在指定時(shí)間內(nèi)出現(xiàn)")
4. 使用backend的特性
某些后端(如uia
)提供了更高級(jí)的等待邏輯,例如在啟動(dòng)應(yīng)用程序時(shí)可以利用Application().start(..., timeout=...)
來(lái)指定啟動(dòng)超時(shí)時(shí)間。
5-pywinauto 打開(kāi)的app有多個(gè)不同的窗口時(shí),怎么定位具體的某個(gè)窗口
在pywinauto
中,如果一個(gè)應(yīng)用程序打開(kāi)了多個(gè)不同的窗口,要定位到具體的某個(gè)窗口,你可以根據(jù)窗口的特征來(lái)精確篩選。以下是一些常用的篩選方法:
1. 根據(jù)窗口標(biāo)題(Title)
窗口標(biāo)題通常是區(qū)分不同窗口最直觀的屬性。你可以使用窗口標(biāo)題的精確文本或正則表達(dá)式來(lái)定位窗口。
Python
specific_window = app.window(title="窗口的精確標(biāo)題") # 或者使用正則表達(dá)式來(lái)模糊匹配 specific_window = app.window(title_re="窗口標(biāo)題的一部分.*")
2. 結(jié)合類名(Class Name)
如果多個(gè)窗口的標(biāo)題相似,但類名不同,你可以結(jié)合類名一起篩選。
Python
specific_window = app.window(title="窗口標(biāo)題", class_name="窗口類名")
3. 控件類型(Control Type)和自動(dòng)化ID(Automation ID)
在使用UIA后端時(shí),如果窗口內(nèi)有特定類型的控件或者控件具有唯一的Automation ID,也可以作為定位依據(jù)。
Python
# 假設(shè)窗口內(nèi)有特定的控件類型或ID specific_window = app.window(control_type="Window", automation_id="特定的自動(dòng)化ID")
4. 使用子窗口或后代窗口
如果需要定位的窗口是另一個(gè)窗口的子窗口或后代,可以先定位到父窗口,再通過(guò)child_window()
或descendants()
方法找到目標(biāo)窗口。
Python
parent_window = app.window(title="父窗口標(biāo)題") specific_child_window = parent_window.child_window(title="子窗口標(biāo)題") # 或者遍歷所有后代窗口找到匹配的 specific_descendant_window = parent_window.descendants(title="后代窗口標(biāo)題")[0] # 注意這會(huì)返回一個(gè)列表
5. 通過(guò)句柄(Handle)
如果你已經(jīng)知道了窗口的句柄,可以直接通過(guò)句柄連接到窗口。
Python
from pywinauto.windows import win32functions handle = win32functions.FindWindowEx(None, None, "窗口類名", "窗口標(biāo)題") specific_window = app.window(handle=handle)
注意事項(xiàng)
- 在使用
wait
方法確保窗口已經(jīng)加載和可見(jiàn),特別是在定位動(dòng)態(tài)彈出的窗口時(shí),這可以避免因窗口未準(zhǔn)備好而導(dǎo)致的錯(cuò)誤。 - 當(dāng)有多個(gè)窗口匹配相同的篩選條件時(shí),考慮使用更具體的篩選條件或結(jié)合多個(gè)屬性來(lái)定位。
- 如果窗口是在不同進(jìn)程中創(chuàng)建的,可能需要使用
Application.connect()
方法來(lái)單獨(dú)連接到那個(gè)窗口。
6-pywinauto 中element_info 和BaseWrapper的用法
在pywinauto
中,element_info
和BaseWrapper
是兩個(gè)核心概念,它們?cè)谧詣?dòng)化測(cè)試和界面操作中扮演著重要角色。
element_info (pywinauto.element_info.ElementInfo
)
element_info
是一個(gè)底層的、面向元素信息的抽象類,它提供了對(duì)UI元素屬性的訪問(wèn)和描述,但不直接支持操作。它是一個(gè)輕量級(jí)的包裝,用于存儲(chǔ)和傳遞關(guān)于UI元素的信息,如類名、標(biāo)題、位置等,而不涉及實(shí)際的UI操作。element_info
是所有控件信息的基礎(chǔ),無(wú)論控件是通過(guò)哪個(gè)后端(如win32
, uia
)來(lái)識(shí)別的。
當(dāng)你使用pywinauto
的方法(如child_window()
)來(lái)定位一個(gè)元素時(shí),實(shí)際上就是在創(chuàng)建或查找一個(gè)element_info
對(duì)象。element_info
對(duì)象可以被用來(lái)創(chuàng)建更高級(jí)的包裝對(duì)象,如BaseWrapper
。
BaseWrapper (pywinauto.base_wrapper.BaseWrapper
)
BaseWrapper
是基于element_info
的更高層次的包裝,它不僅包含了元素的信息,還提供了對(duì)元素進(jìn)行操作的方法,如點(diǎn)擊、發(fā)送文本、獲取屬性等。當(dāng)你需要與UI元素進(jìn)行交互時(shí),比如點(diǎn)擊一個(gè)按鈕或填寫(xiě)一個(gè)文本框,你應(yīng)該使用BaseWrapper
對(duì)象。
BaseWrapper
是element_info
的直接擴(kuò)展,它將底層的元素信息轉(zhuǎn)換為可操作的對(duì)象。這意味著,你可以通過(guò)BaseWrapper
直接執(zhí)行如.click()
, .set_text()
, .texts()
, .exists()
等操作,使得自動(dòng)化腳本編寫(xiě)更為直觀和便利。
使用示例
假設(shè)你要操作一個(gè)按鈕,可以按照以下步驟:
Python
from pywinauto import Application app = Application().start("your_app.exe") main_win = app.window(title="Main Window Title") # 使用child_window()方法找到一個(gè)按鈕,得到的是一個(gè)BaseWrapper實(shí)例 button = main_win.child_window(title="Click Me", control_type="Button") # 然后,你可以直接調(diào)用BaseWrapper的方法來(lái)操作這個(gè)按鈕 button.click()
在這個(gè)過(guò)程中,雖然沒(méi)有直接使用element_info
,但實(shí)際上child_window()
內(nèi)部處理了從element_info
到BaseWrapper
的轉(zhuǎn)換,讓你能夠直接與UI元素進(jìn)行交互。
7-pywinauto 的BaseWrapper類還有哪些方法,詳細(xì)說(shuō)明
根據(jù)搜索到的內(nèi)容總結(jié)如下
pywinauto
的BaseWrapper
類提供了許多方法來(lái)操作和查詢UI元素。這些方法覆蓋了從基本的屬性訪問(wèn)到復(fù)雜的UI交互,下面是BaseWrapper
類中一些常用方法的概覽和簡(jiǎn)要說(shuō)明:
常用屬性和方法 .window_text()
: 獲取控件的文本內(nèi)容。
.texts()
: 返回一個(gè)包含控件所有文本內(nèi)容的列表,適用于包含多行文本的控件。.class_name()
: 返回控件的類名。.control_type()
: 使用UIA后端時(shí),返回控件的類型。.enabled()
: 檢查控件是否啟用。.visible()
: 檢查控件是否可見(jiàn)。.rectangle()
: 獲取控件的矩形區(qū)域,包括坐標(biāo)和大小。.set_focus()
: 將焦點(diǎn)設(shè)置到控件上。.click_input()
: 模擬鼠標(biāo)點(diǎn)擊控件。.double_click_input()
: 雙擊控件。.right_click_input()
: 右鍵點(diǎn)擊控件。.drag_drop(target)
: 拖拽控件到指定的目標(biāo)。.type_keys(keys, with_spaces=True, set_foreground=True)
: 向控件發(fā)送鍵盤(pán)輸入。.set_text(text)
: 設(shè)置文本控件的內(nèi)容。.texts()
: 獲取控件的所有文本內(nèi)容,適用于可能有多行文本的控件。
控件定位和操作擴(kuò)展
.child_window(**kwargs)
: 在當(dāng)前控件的子控件中查找并返回匹配條件的BaseWrapper
對(duì)象。.descendants(**kwargs)
: 返回當(dāng)前控件的所有子孫控件的列表,這些控件滿足給定的篩選條件。.parent()
: 返回當(dāng)前控件的直接父控件的BaseWrapper
對(duì)象。.top_parent()
: 返回當(dāng)前控件的最頂級(jí)父控件的BaseWrapper
對(duì)象。 屬性獲取與設(shè)置.get_properties()
: 獲取控件的所有屬性信息。.set_property(name, value)
: 設(shè)置控件的屬性值。 圖像操作.capture_as_image()
: 截取控件的圖像,返回一個(gè)PIL圖像對(duì)象。 其他.wait('exists', timeout=timedelta(seconds=5))
: 等待控件存在,直到超時(shí)。.wait('visible', timeout=timedelta(seconds=5))
: 等待控件變得可見(jiàn)。.wait_not('visible', timeout=timedelta(seconds=5))
: 等待控件不再可見(jiàn)。
以上只列出了部分方法,實(shí)際上BaseWrapper
類包含更多功能,涵蓋了大多數(shù)自動(dòng)化測(cè)試和UI操作的需求。具體的使用方法和參數(shù)細(xì)節(jié),建議參考pywinauto
的官方文檔或直接查看源代碼注釋,以獲取最全面和最新的信息。
- 嘗試顯式類型轉(zhuǎn)換:如果適用,可以嘗試將找到的元素轉(zhuǎn)換為具體的控件類型,然后調(diào)用
.click_input()
方法。
Python
from pywinauto.controls.win32_controls import ButtonWrapper button = ButtonWrapper(element) button.click_input()
如果以上方法都不能解決問(wèn)題,建議查閱 pywinauto
的官方文檔或訪問(wèn)其GitHub頁(yè)面查看是否有相關(guān)的問(wèn)題報(bào)告或更新日志。同時(shí),確保你的Python環(huán)境是最新的,并考慮升級(jí) pywinauto
到最新穩(wěn)定版。
8-pywinauto 都可以轉(zhuǎn)換成什么控件類型Wrapper
pywinauto
提供了一系列針對(duì)不同控件類型的Wrapper類,這些類封裝了對(duì)特定類型控件的操作方法,使得自動(dòng)化操作更加直觀和方便。以下是部分常用的控件類型及其對(duì)應(yīng)的Wrapper類:
Button - ButtonWrapper
用于操作按鈕,支持點(diǎn)擊等操作。
Edit - EditWrapper
用于編輯框,支持文本的設(shè)置、獲取等操作。
ComboBox - ComboBoxWrapper
用于組合框(下拉列表),支持選擇項(xiàng)、獲取選項(xiàng)列表等。
ListBox - ListBoxWrapper
用于列表框,支持選擇項(xiàng)、獲取項(xiàng)列表等。
CheckBox - CheckBoxWrapper
用于復(fù)選框,支持勾選、取消勾選及狀態(tài)檢查。
RadioButton - RadioButtonWrapper
用于單選按鈕,支持選擇及狀態(tài)檢查。
Menu - MenuWrapper
用于菜單項(xiàng),支持展開(kāi)菜單、選擇菜單項(xiàng)等。
TreeView - TreeViewWrapper
用于樹(shù)狀視圖控件,支持節(jié)點(diǎn)的展開(kāi)、選擇等。
TabItem - TabWrapper
用于選項(xiàng)卡控件中的單個(gè)選項(xiàng)卡。
Dialog - DialogWrapper
對(duì)話框窗口的特殊處理,雖然也是窗口,但可能包含特定于對(duì)話框的操作方法。
Window - WindowWrapper
通用窗口類,幾乎所有窗口都可以用這個(gè)類來(lái)操作,但針對(duì)特定控件類型使用特定的Wrapper會(huì)更方便。
請(qǐng)注意,直接將element_info
轉(zhuǎn)換為特定的Wrapper類(如從element_info
到ButtonWrapper
)并不總是直接支持,通常你不需要手動(dòng)進(jìn)行這樣的轉(zhuǎn)換。當(dāng)你通過(guò)正確的篩選條件使用child_window()
等方法時(shí),pywinauto
會(huì)自動(dòng)為你提供最適合的Wrapper實(shí)例。如果需要更具體的控件操作,可以通過(guò)訪問(wèn)BaseWrapper
實(shí)例的屬性或方法來(lái)實(shí)現(xiàn),因?yàn)榇蠖鄶?shù)Wrapper類都是從BaseWrapper
繼承而來(lái),已經(jīng)包含了基礎(chǔ)的交互方法。
在實(shí)際使用中,直接利用child_window()
方法根據(jù)控件的屬性(如標(biāo)題、類名、控制類型等)來(lái)定位并操作控件即可,大多數(shù)情況下無(wú)需關(guān)心底層的Wrapper類轉(zhuǎn)換。如果需要更高級(jí)或特定的功能,查閱pywinauto
的文檔或源碼,了解特定Wrapper類的使用方法會(huì)更有幫助。
9-pywinauto打印獲取的windows對(duì)象,一個(gè)是加了等待,一個(gè)是沒(méi)加等待。
獲取的window對(duì)象使用print(window),打印出來(lái)分別是uiawrapper.UIAWrapper - 'New mail', Dialog,另一個(gè)是<pywinauto.application.WindowSpecification object at 0x0000016B0DE556A0> 有什么區(qū)別
在使用pywinauto
時(shí),你觀察到的區(qū)別反映了兩種不同狀態(tài)的窗口對(duì)象處理方式。
未使用等待(直接獲?。?/p>
Python
window = app.window(title="New mail") print(window)
輸出類似于 <pywinauto.application.WindowSpecification object at 0x0000016B0DE556A0>
,這表明你獲得的是一個(gè)WindowSpecification
對(duì)象。這個(gè)對(duì)象實(shí)際上是一個(gè)窗口的描述符或者說(shuō)規(guī)范,它定義了你要找的窗口應(yīng)該滿足的條件(在這個(gè)例子中是標(biāo)題為"New mail"的窗口)。但是,此時(shí)pywinauto
尚未實(shí)際找到并實(shí)例化這個(gè)窗口,這意味著打印出來(lái)的信息是一個(gè)內(nèi)存地址,代表了這個(gè)待查找窗口描述的實(shí)例。
使用等待后獲取
Python
window = app.window(title="New mail").wait('visible') print(window)
或者
Python
window = app.window(title="New mail").wait('exists', timeout=10)
輸出為 uiawrapper.UIAWrapper - 'New mail', Dialog
,這表示你成功獲取到了一個(gè)實(shí)際的UI元素對(duì)象,它已經(jīng)不是一個(gè)簡(jiǎn)單的查找規(guī)范,而是窗口實(shí)際存在的、可操作的對(duì)象。uiawrapper.UIAWrapper
是pywinauto
內(nèi)部用于包裝UIA(UI Automation)元素的類,這意味著窗口不僅被找到了,而且已經(jīng)準(zhǔn)備好了進(jìn)行進(jìn)一步的交互操作,比如點(diǎn)擊、輸入文本等。
區(qū)別總結(jié)
- 未使用等待:你得到的是一個(gè)窗口的查找描述符,它定義了要找什么,但不代表窗口已被找到或?qū)嵗?/li>
- 使用等待:你得到的是一個(gè)實(shí)際的UI元素對(duì)象,它代表了已經(jīng)找到的窗口,可以直接用于執(zhí)行各種操作。
在實(shí)際應(yīng)用中,使用等待(如.wait('visible')
或.wait('exists')
)通常更為推薦,因?yàn)樗_保了操作不會(huì)在窗口還沒(méi)準(zhǔn)備好時(shí)進(jìn)行,提高了腳本的穩(wěn)定性和可靠性。
10-我的pywinauto程序,Application.start()后,還需要執(zhí)行application.connect() 后的app ,才能正常使用。否則此app獲得的windows不可用,為什么?
在pywinauto
中,理論上,一旦你使用Application.start()
方法啟動(dòng)了一個(gè)應(yīng)用程序,它應(yīng)該自動(dòng)連接到這個(gè)新啟動(dòng)的應(yīng)用實(shí)例,并且你能夠直接通過(guò)返回的app
實(shí)例進(jìn)行窗口和控件的查找及操作,無(wú)需再次調(diào)用app.connect()
。
如果遇到必須先執(zhí)行app.connect()
后才能正常使用app
獲得的窗口或控件,這可能由幾個(gè)原因引起:
- 啟動(dòng)時(shí)間問(wèn)題:應(yīng)用程序可能需要一段時(shí)間才能完全初始化其窗口和UI元素。即便
start()
方法在內(nèi)部嘗試連接,但如果UI還未完全加載,后續(xù)立即進(jìn)行窗口或控件查找可能失敗。此時(shí),手動(dòng)調(diào)用connect()
給予額外的時(shí)間緩沖,可能恰好讓UI準(zhǔn)備就緒。 - 后臺(tái)啟動(dòng)或隱藏窗口:某些應(yīng)用程序可能在啟動(dòng)時(shí)沒(méi)有立即顯示窗口,或者窗口最小化到托盤(pán)/后臺(tái)運(yùn)行,導(dǎo)致初次連接時(shí)無(wú)法正確識(shí)別窗口。稍后調(diào)用
connect()
可能窗口已變?yōu)榭梢?jiàn)或可交互狀態(tài)。 - UI自動(dòng)化框架的兼容性或bug:盡管少見(jiàn),但不同版本的
pywinauto
或目標(biāo)應(yīng)用程序的UI框架(如WPF、UWP等)可能存在兼容性問(wèn)題,導(dǎo)致自動(dòng)連接行為不如預(yù)期。 - 多實(shí)例問(wèn)題:如果你的應(yīng)用程序允許或意外啟動(dòng)了多個(gè)實(shí)例,
start()
可能連接到了不同的實(shí)例,而你期望操作的窗口位于另一個(gè)實(shí)例中。再次手動(dòng)指定連接條件確保連接到正確的窗口實(shí)例。
解決方法建議:
- 增加啟動(dòng)后等待:在
start()
后,加入適當(dāng)?shù)牡却龝r(shí)間(如time.sleep()
),讓?xiě)?yīng)用程序有足夠的時(shí)間初始化窗口和UI元素。 - 精確連接:確保
connect()
時(shí)使用足夠的參數(shù)(如窗口標(biāo)題、類名等)來(lái)精確匹配你想要連接的窗口,避免連接到錯(cuò)誤的實(shí)例或窗口。 - 檢查
pywinauto
版本:確保你使用的pywinauto
版本是最新的,以獲取最佳的兼容性和穩(wěn)定性。 - 日志和調(diào)試:使用
pywinauto
的日志功能或打印調(diào)試信息,檢查啟動(dòng)和連接過(guò)程中可能出現(xiàn)的任何異?;蚓?,幫助定位問(wèn)題所在。
如果問(wèn)題持續(xù),考慮查看pywinauto
的官方文檔或社區(qū),可能有針對(duì)特定應(yīng)
用或類似問(wèn)題的解決方案。
我的問(wèn)題其實(shí)應(yīng)該是兼容問(wèn)題,我增加start()后的等待時(shí)間,無(wú)效。
必須使用Application.connect()命令,重新獲取app后,只有的操作才有效。
app = Application(backend="uia").start(outlook_path, timeout=30) # 等待也是必須的 time.sleep(15) # 必須使用connect()重新生成 app = Application(backend="uia").connect(class_name="Olk Host") print("outlook第一次啟動(dòng),打開(kāi)outlook成功!, app=", app)
11-Application(backend="uia").start()參數(shù)中有timeout參數(shù)嗎?
沒(méi)有。
因?yàn)樵跇?biāo)準(zhǔn)的pywinauto
文檔和通常的使用中,直接的start()
方法調(diào)用并不直接接受一個(gè)timeout
參數(shù)用于等待應(yīng)用程序啟動(dòng)完成。
通常,如果你想控制應(yīng)用程序啟動(dòng)后的等待邏輯或處理超時(shí),你需要采取一些額外的步驟,而不是直接通過(guò)start()
方法的timeout
參數(shù)(因?yàn)檫@個(gè)參數(shù)在標(biāo)準(zhǔn)用法中不存在)。以下是一些建議:
- 手動(dòng)等待:在
start()
調(diào)用之后,你可以使用time.sleep()
或更復(fù)雜的邏輯來(lái)等待一段預(yù)估的合理時(shí)間,確保應(yīng)用程序有足夠的時(shí)間啟動(dòng)并加載完畢。 - 動(dòng)態(tài)等待窗口:利用
pywinauto
的等待機(jī)制,比如top_window()
或wait()
方法,來(lái)動(dòng)態(tài)等待直到應(yīng)用程序的某個(gè)窗口變得可用或滿足特定條件。例如,如果你知道應(yīng)用程序啟動(dòng)后主窗口的標(biāo)題,可以這樣做:
Python
app = Application(backend="uia").start("your_app_path") main_window = app.window(title="Your Main Window Title").wait("visible", timeout=30)
這里,timeout=30
就是等待窗口變?yōu)榭梢?jiàn)的最大時(shí)間,單位為秒。
異常處理:在嘗試訪問(wèn)應(yīng)用程序窗口或執(zhí)行操作時(shí),使用try-except結(jié)構(gòu)來(lái)捕獲可能的超時(shí)或失敗異常,從而實(shí)現(xiàn)間接的超時(shí)控制。
自定義邏輯:根據(jù)應(yīng)用程序的具體行為,你可能需要更定制化的邏輯來(lái)確定何時(shí)應(yīng)用程序已成功啟動(dòng)并準(zhǔn)備好進(jìn)行自動(dòng)化操作,這可能涉及檢查特定進(jìn)程的狀態(tài)、窗口屬性變化等。
綜上所述,雖然直接在Application.start()
方法中設(shè)置timeout
參數(shù)不是標(biāo)準(zhǔn)用法,但通過(guò)上述方法你可以有效地控制和管理應(yīng)用程序啟動(dòng)后的等待邏輯及超時(shí)處理。
12-Application(backend="uia").connect()參數(shù)中有timeout參數(shù)嗎?
沒(méi)有。
但pywinauto
提供了靈活的等待和超時(shí)控制機(jī)制來(lái)確保連接操作不會(huì)無(wú)限期地阻塞。
自動(dòng)化等待與超時(shí)控制
雖然直接在connect()
方法簽名中沒(méi)有公開(kāi)timeout
參數(shù),但pywinauto
的wait
系列方法和自動(dòng)化操作通常允許你指定一個(gè)超時(shí)限制,例如在嘗試連接到一個(gè)窗口時(shí):
Python
app = Application(backend="uia") main_window = app.window(title="Your App Title").wait("exists", timeout=30)
在這個(gè)例子中,wait("exists", timeout=30)
是嘗試等待窗口存在最多30秒。如果窗口在指定時(shí)間內(nèi)變得可訪問(wèn),則繼續(xù)執(zhí)行;如果超時(shí),則會(huì)拋出異常,允許你的腳本據(jù)此作出反應(yīng)。
定制等待邏輯
對(duì)于更復(fù)雜的場(chǎng)景,你可能需要自定義等待邏輯,比如檢查窗口是否不僅存在還滿足其他條件(如“visible”、“enabled”等),并結(jié)合自定義的循環(huán)和超時(shí)處理。
總結(jié)
盡管Application(backend="uia").connect()
直接調(diào)用時(shí)不帶有一個(gè)明確的timeout
參數(shù),pywinauto
提供的wait
方法和自動(dòng)化操作的靈活性讓你能夠有效控制連接和等待窗口出現(xiàn)的時(shí)間限制,實(shí)現(xiàn)類似超時(shí)處理的邏輯。通過(guò)這種方式,確保了自動(dòng)化腳本既能夠穩(wěn)健地等待必要的窗口準(zhǔn)備就緒,又能避免不必要的阻塞。
13-彈窗操作
在pywinauto
中,當(dāng)需要連接并操作一個(gè)應(yīng)用程序新彈出的窗口時(shí),通常需要先確保新窗口已經(jīng)出現(xiàn),然后通過(guò)窗口的標(biāo)題或其他屬性來(lái)定位并操作它。以下是處理新彈窗的基本步驟:
1. 等待彈窗出現(xiàn)
使用pywinauto
的等待功能確保彈窗已經(jīng)打開(kāi)。這可以通過(guò)循環(huán)檢查窗口是否存在,或者使用更高級(jí)的等待方法來(lái)實(shí)現(xiàn)。
Python
from pywinauto import Application from pywinauto.timings import wait_until_passes app = Application().connect(title="主應(yīng)用程序的標(biāo)題") # 首先連接到主應(yīng)用程序 def is_popup_opened(): try: app.window(title="彈窗的標(biāo)題") return True except Exception: return False # 等待彈窗出現(xiàn),最多等待10秒 wait_until_passes(10, 1, is_popup_opened)
2. 定位并操作彈窗
一旦確認(rèn)彈窗已經(jīng)打開(kāi),就可以通過(guò)其標(biāo)題或其它屬性來(lái)定位并進(jìn)行操作。
Python
popup_window = app.window(title="彈窗的標(biāo)題") # 例如,點(diǎn)擊彈窗上的一個(gè)按鈕 button_on_popup = popup_window.child_window(title="按鈕的標(biāo)題或自動(dòng)化ID", control_type="Button") button_on_popup.click()
3. 異常處理和重試機(jī)制
在實(shí)際操作中,可能需要添加適當(dāng)?shù)漠惓L幚磉壿?,以防窗口?biāo)題變化或打開(kāi)速度過(guò)慢等情況。
4. 關(guān)閉彈窗
如果操作完成后需要關(guān)閉彈窗,可以調(diào)用窗口的關(guān)閉方法:
Python
popup_window.close()
注意事項(xiàng):
- 確保窗口標(biāo)題是唯一的,或者足夠精確以避免誤操作其他窗口。
- 使用
control_type
、class_name
等屬性可以幫助更精確地定位控件。 - 如果彈窗屬于同一個(gè)應(yīng)用程序,通常不需要再次調(diào)用
Application().connect()
,直接在已連接的應(yīng)用實(shí)例上操作即可。 - 根據(jù)彈窗出現(xiàn)的時(shí)機(jī)和應(yīng)用的具體行為,可能需要微調(diào)等待邏輯。
14-AttributeError: 'UIAWrapper' object has no attribute 'print_control_identifiers'
在pywinauto
中,如果你遇到AttributeError: 'UIAWrapper' object has no attribute 'print_control_identifiers'
錯(cuò)誤,這意味著你嘗試在一個(gè)基于UIA(UI Automation)的控件上使用了print_control_identifiers
方法,但這個(gè)方法實(shí)際上并不直接存在于UIAWrapper
對(duì)象中。
print_control_identifiers
方法主要用于經(jīng)典的Windows應(yīng)用程序自動(dòng)化(win32應(yīng)用程序),它在Win32Window
對(duì)象中可用。然而,對(duì)于基于UI Automation(UIA)的應(yīng)用,如現(xiàn)代的UWP應(yīng)用或使用了UIA框架構(gòu)建的桌面應(yīng)用,直接使用print_control_identifiers
會(huì)報(bào)錯(cuò)。
對(duì)于UIAWrapper對(duì)象,你可以使用.legacy_properties()
方法來(lái)獲取控件的部分信息,但這通常不如print_control_identifiers
那樣詳盡。
解決方案:
- 檢查應(yīng)用類型:確認(rèn)你的應(yīng)用是否是現(xiàn)代UIA應(yīng)用還是傳統(tǒng)的win32應(yīng)用。如果是UIA應(yīng)用,繼續(xù)閱讀下文。
- 使用UIA屬性:對(duì)于UIAWrapper對(duì)象,你可以利用
.properties
屬性來(lái)查看控件的屬性。例如:
Python
1control = app.window(title="Your Window Title").child_window(auto_id="Your Control AutoId") 2print(control.properties)
這將打印出控件的屬性字典,其中包含了控制類型、名稱、位置等信息。
自定義打印函數(shù):如果需要類似print_control_identifiers
的詳細(xì)輸出,你可能需要自己編寫(xiě)一個(gè)函數(shù)來(lái)遍歷.properties
或使用UIA的其他方法來(lái)獲取更詳細(xì)的控件信息。
降級(jí)為win32:在某些情況下,如果應(yīng)用同時(shí)支持UIA和win32,你可以嘗試降級(jí)到win32模式來(lái)使用print_control_identifiers
。但這取決于應(yīng)用的具體實(shí)現(xiàn)和支持情況,且不是所有UIA應(yīng)用都能這么做。
記住,UI Automation和經(jīng)典Windows應(yīng)用程序自動(dòng)化在pywinauto
中有一些差異,因此在處理不同類型的窗口和控件時(shí),要相應(yīng)地調(diào)整你的方法。
15-AttributeError: 'UIAWrapper' object has no attribute 'child_window'
UIAWrapper 窗口類型, 定位元素需要使用如下方法定位:ele = setWindow.descendants(title="Remove")[0]
當(dāng)你在使用pywinauto
遇到AttributeError: 'UIAWrapper' object has no attribute 'child_window'
錯(cuò)誤時(shí),這意味著你嘗試在一個(gè)基于UIA(UI Automation)的控件(UIAWrapper
對(duì)象)上調(diào)用了child_window
方法,但這個(gè)方法在UIAWrapper對(duì)象中并不可用。
UIAWrapper對(duì)象主要對(duì)應(yīng)于使用UI Automation技術(shù)的應(yīng)用程序,與傳統(tǒng)的Win32應(yīng)用程序使用的API有所不同。在UIAWrapper上,直接查找子窗口或控件的方法不是child_window
,而是使用更符合UIA查詢方式的屬性和方法。
解決方案:
- 使用
.descendants
方法:對(duì)于UIAWrapper對(duì)象,可以使用.descendants
方法來(lái)查找所有子孫控件,然后通過(guò)條件過(guò)濾找到目標(biāo)控件。
Python
controls = window.descendants(control_type="ControlType") # 替換"ControlType"為實(shí)際控件類型,如"Button", "Edit",
直接屬性訪問(wèn):如果已知某些屬性(如 name
, control_type
等),可以直接通過(guò)屬性篩選。
Python
target_control = window.child_window(auto_id="目標(biāo)控件的AutomationId")
注意:上述child_window
方法是針對(duì)經(jīng)典的win32應(yīng)用程序,對(duì)于UIA,你應(yīng)該使用更符合其查詢機(jī)制的方法,如.descendants
或直接屬性篩選。
構(gòu)造查詢條件:使用更復(fù)雜的查詢條件來(lái)精確定位控件,例如使用.filter()
方法。
Python
1from pywinauto.controls.uia_controls import UIAWrapper 2control = UIAWrapper(handle=你的窗口句柄).filter(control_type="ControlType")[0] # 替換"ControlType"和條件
確保理解你的應(yīng)用是基于UI Automation還是傳統(tǒng)的Win32,然后選擇相應(yīng)的API和方法來(lái)操作和查找控件。對(duì)于UIA應(yīng)用,利用.descendants
和屬性篩選通常是最直接有效的方式。
16-pywinauto,已經(jīng)找到窗口了,但使用window的方法print_control_identifiers()方法,會(huì)提示匹配到多個(gè)元素呢?There are 5 elements that match the criteria {'backend': 'uia', 'process': 22188}
當(dāng)您已經(jīng)成功定位到一個(gè)窗口,但在嘗試使用 window.print_control_identifiers()
方法時(shí)遇到提示匹配到多個(gè)元素,這通常意味著您調(diào)用 print_control_identifiers()
的對(duì)象實(shí)際上是一個(gè)窗口集合或者是基于某些寬泛條件的窗口規(guī)范(WindowSpecification
),而不是一個(gè)特定的窗口實(shí)例。
為了解決這個(gè)問(wèn)題,確保您在調(diào)用 print_control_identifiers()
之前,已經(jīng)準(zhǔn)確地指定了一個(gè)唯一的窗口。這里有幾個(gè)步驟可以幫助您:
- 重新檢查定位窗口的代碼:確認(rèn)您是否確實(shí)已經(jīng)通過(guò)足夠精確的條件定位到單一窗口。比如,使用窗口的標(biāo)題、類名、進(jìn)程ID等屬性來(lái)精確篩選。
- 使用更具體的選擇器:如果可能,增加篩選條件,比如使用正則表達(dá)式匹配窗口標(biāo)題 (
title_re
) 或是直接使用窗口的自動(dòng)化ID (auto_id
)。 - 確保調(diào)用鏈正確:如果通過(guò)一系列操作到達(dá)某個(gè)窗口,確認(rèn)每一步都正確返回了預(yù)期的窗口對(duì)象。有時(shí),錯(cuò)誤的調(diào)用順序可能導(dǎo)致返回的是窗口集合而非單個(gè)窗口。
- 檢查是否使用了模糊匹配:避免使用可能匹配到多個(gè)窗口的過(guò)于寬泛的條件,如只使用
backend
和process
作為篩選條件。 - 顯式地獲取窗口實(shí)例:在確定了窗口后,可以嘗試顯式地通過(guò)索引或其他方法獲取具體的窗口實(shí)例。例如,如果您知道目標(biāo)窗口是匹配條件下的第一個(gè),可以嘗試:
Python
specific_window = windows[0] # 假設(shè)'windows'是一個(gè)包含多個(gè)匹配窗口的列表 specific_window.print_control_identifiers()
- 使用
top_level_only=False
:如果目標(biāo)窗口不是頂級(jí)窗口,嘗試設(shè)置top_level_only=False
來(lái)搜索所有級(jí)別的窗口,然后進(jìn)一步篩選。 - 調(diào)試與分析:如果以上方法都無(wú)法解決問(wèn)題,可以先使用
print_control_identifiers()
的depth=-1
參數(shù)來(lái)打印所有窗口的信息,幫助您識(shí)別哪些窗口與您的預(yù)期不符,并據(jù)此調(diào)整選擇條件。
確保每個(gè)步驟都盡可能具體和精確,以避免匹配到多個(gè)窗口的情況發(fā)生。
17-pywinauto, 使用Desktop(backend="uia")獲取窗口
注意點(diǎn)1: Desktop(backend="uia").windows()/window(),兩個(gè)方法,只能查詢所有的主窗口,不支持查詢主窗口下都子窗口。 注意點(diǎn)2: 使用Desktop(backend="uia").windows()/window(),如果條件不能定位到窗口的情況下。 Desktop(backend="uia").windows()方法,結(jié)果返回空列表。 如下: wins = Desktop(backend="uia").windows(title="Work or school account", class_name="Windows.UI.Core.CoreWindow") print(wins) 結(jié)果:[] Desktop(backend="uia").window()方法,結(jié)果返回WindowSpecification對(duì)象。 如下: win = Desktop(backend="uia").window(title="Work or school account", class_name="Windows.UI.Core.CoreWindow") print(win) 結(jié)果:<pywinauto.application.WindowSpecification object at 0x000001524BE87790>,不能使用返回的window()的返回值做判斷。 注意點(diǎn)3: 如果窗口類型為:WindowSpecification,使用parent_window.child_window() 方式查詢窗口元素。 如果窗口類型為:UIAWrapper,使用parent_window.parent_window.descendants() 方式查詢窗口元素。
18-pywinauto ,通過(guò)元素的 element.rectangle() 方法,使用pyautogui,移動(dòng)鼠標(biāo)到元素位置,實(shí)現(xiàn)。
具體寫(xiě)法如下:
# 假設(shè)你想對(duì)窗口內(nèi)的某個(gè)元素進(jìn)行操作,首先找到該元素 element = main_window.child_window(title="Your Element Title", control_type="ControlTypeHere") # 請(qǐng)?zhí)鎿Q為實(shí)際的標(biāo)題和控件類型 # 獲取元素的矩形信息 element_rectangle = element.rectangle() # 使用 pyautogui 將鼠標(biāo)移動(dòng)到該位置 x, y = element_rectangle.left + (element_rectangle.width() // 2), element_rectangle.top + (element_rectangle.height() // 2) pyautogui.moveTo(x, y) # 移動(dòng)到元素中心位置,也可以直接移到左上角,去掉加法部分即可
注意:element_rectangle.width 和element_rectangle.height返回的類型都是method;計(jì)算位置坐標(biāo)是應(yīng)使用element_rectangle.width() 和element_rectangle.height()形式。
否則報(bào)錯(cuò):TypeError: unsupported operand type(s) for //: 'method' and 'int'(不支持這兩兩種類型使用//語(yǔ)法計(jì)算)
19-編碼過(guò)程中,注意循環(huán)引用問(wèn)題
E ImportError: cannot import name 'assertTrue' from partially initialized module 'assertTool' (most likely due to a circular import) --很可能是循環(huán)導(dǎo)入
問(wèn)題:“文件a” 導(dǎo)入了 “文件b” 中的方法;“文件b” 也導(dǎo)入了“文件a”中的方法,導(dǎo)致循環(huán)導(dǎo)入問(wèn)題。
20-pywinauot, 定位uiaWrapper 元素時(shí),增加等待有時(shí)候不能解決問(wèn)題。但是窗口最大化后,就能查找到元素了。
可能的原因:窗口布局變化
應(yīng)用程序窗口在最大化之前和之后,其內(nèi)部元素的布局可能會(huì)有細(xì)微的變化。這種布局變化可能會(huì)影響到元素的可訪問(wèn)性或者導(dǎo)致元素的屬性(如坐標(biāo)位置)發(fā)生變化。最大化窗口可能使得元素穩(wěn)定地出現(xiàn)在預(yù)期的位置或狀態(tài),從而變得可被pywinauto
識(shí)別。
21-pywinauto + pytest 執(zhí)行的測(cè)試用例時(shí),提示錯(cuò)誤: Windows fatal exception: code 0x8001010d。 但是如果把此用例的內(nèi)容,都放到一個(gè)文件中執(zhí)行,不通過(guò)pytest,就沒(méi)有這個(gè)錯(cuò)誤提示。應(yīng)該怎么解決
錯(cuò)誤代碼 0x8001010d
通常與COM(Component Object Model)錯(cuò)誤相關(guān),特別是“RPC服務(wù)器不可用”或“接口調(diào)用中出現(xiàn)錯(cuò)誤”。在使用pywinauto
進(jìn)行GUI自動(dòng)化測(cè)試時(shí)遇到這個(gè)問(wèn)題,可能的原因有幾個(gè)方面,尤其是在結(jié)合pytest
使用時(shí),可能與測(cè)試環(huán)境的初始化、資源釋放、并發(fā)執(zhí)行測(cè)試等方面有關(guān)。以下是一些可能的解決方案:
- 確保單例模式: 確保在整個(gè)測(cè)試套件中,對(duì)應(yīng)用程序?qū)嵗氖褂檬菃卫?,避免多個(gè)測(cè)試用例同時(shí)操作同一個(gè)應(yīng)用程序?qū)嵗@可能導(dǎo)致資源沖突??梢栽?code>conftest.py中使用
fixture
來(lái)管理應(yīng)用實(shí)例的生命周期。 - 資源清理: 確保每個(gè)測(cè)試用例結(jié)束后,正確地關(guān)閉和清理所有打開(kāi)的窗口和資源。使用
try...finally
塊或者pytest.fixture
的yield
語(yǔ)句來(lái)確保即使測(cè)試失敗也能執(zhí)行清理操作。 - 并發(fā)執(zhí)行問(wèn)題: 如果你的測(cè)試套件配置為并行執(zhí)行(pytest默認(rèn)可能不會(huì),但通過(guò)
-n NUM
參數(shù)可以設(shè)置),那么可能需要禁用并行執(zhí)行,因?yàn)槟承〨UI操作或COM對(duì)象可能不支持多線程或并發(fā)訪問(wèn)。可以在運(yùn)行pytest時(shí)加上-n 1
參數(shù)來(lái)禁用并行執(zhí)行。 - COM對(duì)象生命周期管理: 確保所有的COM對(duì)象在使用完畢后都被適當(dāng)釋放。在
pywinauto
中,通常這會(huì)自動(dòng)處理,但如果涉及到自定義COM調(diào)用,請(qǐng)確保遵循正確的釋放流程。 - 增加異常處理: 在測(cè)試代碼中增加對(duì)特定異常的捕獲和處理邏輯,尤其是與COM相關(guān)的異常,可以幫助診斷問(wèn)題所在??梢試L試捕獲并打印詳細(xì)的錯(cuò)誤信息,以便于進(jìn)一步分析。
- 檢查環(huán)境差異: 確認(rèn)直接運(yùn)行文件和通過(guò)pytest運(yùn)行時(shí)的環(huán)境(如環(huán)境變量、權(quán)限等)是否一致。有時(shí)候,環(huán)境差異也會(huì)導(dǎo)致此類問(wèn)題。
如果以上建議不能解決問(wèn)題,可能需要更詳細(xì)的日志來(lái)定位問(wèn)題??紤]在pytest
運(yùn)行時(shí)增加日志級(jí)別(通過(guò)-vvv
參數(shù)或配置logging模塊),并查看是否有其他相關(guān)的警告或錯(cuò)誤信息輸出,這有助于更準(zhǔn)確地定位問(wèn)題所在。
- 使用Python pyWinAuto庫(kù)自動(dòng)化Windows任務(wù)的示例代碼
- Python基于pywinauto實(shí)現(xiàn)的自動(dòng)化采集任務(wù)
- python使用pywinauto驅(qū)動(dòng)微信客戶端實(shí)現(xiàn)公眾號(hào)爬蟲(chóng)
- python+pywinauto+lackey實(shí)現(xiàn)PC端exe自動(dòng)化的示例代碼
- PythonPC客戶端自動(dòng)化實(shí)現(xiàn)原理(pywinauto)
- python自動(dòng)化工具之pywinauto實(shí)例詳解
相關(guān)文章
Python Web服務(wù)器Tornado使用小結(jié)
最近在做一個(gè)網(wǎng)站的后端開(kāi)發(fā)。因?yàn)槌跗谥挥形乙粋€(gè)人做,所以技術(shù)選擇上很自由。在 web 服務(wù)器上我選擇了 Tornado。雖然曾經(jīng)也讀過(guò)它的源碼,并做過(guò)一些小的 demo,但畢竟這是第一次在工作中使用,難免又發(fā)現(xiàn)了一些值得分享的東西2014-05-05Python中sorted()函數(shù)之排序的利器詳解
sorted()函數(shù)是Python中的內(nèi)置函數(shù),用于對(duì)可迭代對(duì)象進(jìn)行排序,下面這篇文章主要給大家介紹了關(guān)于Python中sorted()函數(shù)之排序的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-08-08python將txt等文件中的數(shù)據(jù)讀為numpy數(shù)組的方法
今天小編就為大家分享一篇python將txt等文件中的數(shù)據(jù)讀為numpy數(shù)組的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-12-12python實(shí)現(xiàn)從ftp上下載文件的實(shí)例方法
在本篇文章里小編給大家整理了關(guān)于python實(shí)現(xiàn)從ftp上下載文件的實(shí)例方法,需要的朋友們可以參考下。2020-07-07