Thư viện Python là một dự án nguồn mở để tự động hóa các ứng dụng GUI trên máy tính để bàn trên Windows. Trong hai năm qua, các tính năng chính mới đã xuất hiện trong đó:
- Hỗ trợ công nghệ MS UI Automation. Giao diện vẫn như cũ và hiện tại nó hỗ trợ: WinForms, WPF, Qt5, Windows Store (UWP), v.v. - hầu hết mọi thứ có trên Windows.
- Hệ thống phụ trợ/plugin (hiện tại có hai trong số đó: mặc định
"win32"và mới"uia"). Sau đó, chúng tôi tiến tới đa nền tảng một cách suôn sẻ. - Móc Win32 cho chuột và bàn phím (phím nóng theo tinh thần pyHook).
Chúng tôi cũng sẽ đưa ra một cái nhìn tổng quan ngắn gọn về những gì có sẵn trong nguồn mở dành cho tự động hóa máy tính để bàn (mà không giả vờ là một so sánh nghiêm túc).
Bài viết này là bản sao một phần của báo cáo từ hội nghị Ngày SQA 20 ở Minsk ( и ), một phần phiên bản tiếng Nga cho pywinauto.
- Các cách tiếp cận chính
- Công nghệ trợ năng cơ bản dành cho máy tính để bàn
Hãy bắt đầu với tổng quan ngắn gọn về nguồn mở trong lĩnh vực này. Đối với các ứng dụng GUI trên máy tính để bàn, mọi thứ phức tạp hơn một chút so với web có Selenium. Dưới đây là các cách tiếp cận chính:
phương pháp tọa độ
Mã hóa cứng các điểm nhấp chuột, chúng tôi hy vọng sẽ có lượt truy cập thành công.
[+] Đa nền tảng, dễ triển khai.
[+] Thật dễ dàng để “ghi-phát lại” các bản ghi thử nghiệm.
[-] Không ổn định nhất khi thay đổi độ phân giải màn hình, chủ đề, phông chữ, kích thước cửa sổ, v.v.
[-] Cần có những nỗ lực hỗ trợ rất lớn; việc tạo lại các bài kiểm tra từ đầu hoặc kiểm tra thủ công thường dễ dàng hơn.
[-] Chỉ tự động hóa các hành động; có các phương pháp khác để xác minh và truy xuất dữ liệu.
Công cụ (đa nền tảng): , , và nhiều người khác. Thông thường, các công cụ phức tạp hơn sẽ bao gồm chức năng này (không phải lúc nào cũng đa nền tảng).
Điều đáng nói là phương pháp tọa độ có thể bổ sung cho các phương pháp khác. Ví dụ: đối với đồ họa tùy chỉnh, bạn có thể nhấp vào tọa độ tương đối (từ góc trên bên trái của cửa sổ/phần tử chứ không phải toàn bộ màn hình) - điều này thường khá đáng tin cậy, đặc biệt nếu bạn tính đến chiều dài/chiều rộng của toàn bộ phần tử (khi đó độ phân giải màn hình khác nhau sẽ không bị ảnh hưởng).
Một tùy chọn khác: chỉ phân bổ một máy có cài đặt ổn định để thử nghiệm (không phải đa nền tảng, nhưng trong một số trường hợp thì tốt).
Nhận dạng hình ảnh tham khảo
[+] Đa nền tảng[+-] Tương đối đáng tin cậy (tốt hơn phương pháp tọa độ), nhưng vẫn cần một số thủ thuật.
[-+] Tương đối chậm, bởi vì Yêu cầu tài nguyên CPU cho các thuật toán nhận dạng.
[-] Nhận dạng văn bản (OCR), theo quy định, không được áp dụng => không thể lấy được dữ liệu văn bản. Theo những gì tôi biết, các giải pháp OCR hiện tại không đáng tin cậy cho loại nhiệm vụ này và không được sử dụng rộng rãi (chào mừng bạn nhận xét nếu điều này chưa xảy ra).
Công cụ: , (Python thuần túy, tương thích với Sikuli), .
Công nghệ tiếp cận
[+] Phương pháp đáng tin cậy nhất, bởi vì cho phép bạn tìm kiếm bằng văn bản, bất kể nó được hệ thống hoặc khung hiển thị như thế nào.[+] Cho phép bạn trích xuất dữ liệu văn bản => dễ dàng xác minh kết quả kiểm tra hơn.
[+] Theo quy định, nhanh nhất, bởi vì hầu như không tiêu tốn tài nguyên CPU.
[-] Thật khó để tạo ra một công cụ đa nền tảng: hoàn toàn tất cả các thư viện nguồn mở đều hỗ trợ một hoặc hai công nghệ trợ năng. Windows/Linux/MacOS không được hỗ trợ đầy đủ bởi bất kỳ ai ngoại trừ những ứng dụng trả phí như TestComplete, UFT hoặc Squish.
[-] Về nguyên tắc, công nghệ như vậy không phải lúc nào cũng có sẵn. Ví dụ: kiểm tra màn hình tải bên trong VirtualBox - điều này không thể thực hiện được nếu không nhận dạng hình ảnh. Nhưng trong nhiều trường hợp cổ điển, phương pháp tiếp cận vẫn có thể áp dụng được. Điều này sẽ được thảo luận thêm.
Công cụ: trong C#, trong C# (tương thích với Selenium), trong C# (tương thích với Appium), , (Tương thích với LDTP) , trong Ruby, (Dự án thử nghiệm máy tính để bàn Linux) và phiên bản Windows của nó .
LDTP có lẽ là công cụ nguồn mở đa nền tảng duy nhất (chính xác hơn là một nhóm thư viện) dựa trên các công nghệ trợ năng. Tuy nhiên, nó không phổ biến lắm. Bản thân tôi chưa sử dụng nhưng theo đánh giá thì giao diện của nó không tiện lợi nhất. Nếu bạn có phản hồi tích cực, xin vui lòng chia sẻ nó trong phần bình luận.
Kiểm tra cửa sau (hay còn gọi là xe đạp trong nhà)
Đối với các ứng dụng đa nền tảng, bản thân các nhà phát triển thường tạo ra một cơ chế nội bộ để đảm bảo khả năng kiểm thử. Ví dụ: họ tạo một máy chủ TCP dịch vụ trong ứng dụng, kiểm tra kết nối với nó và gửi lệnh văn bản: nhấp vào cái gì, lấy dữ liệu ở đâu, v.v. Đáng tin cậy, nhưng không phổ quát.
Công nghệ trợ năng cơ bản dành cho máy tính để bàn
API Win32 cũ tốt
Hầu hết các ứng dụng Windows được viết trước khi phát hành WPF và sau đó là Windows Store đều được xây dựng trên API Win32 theo cách này hay cách khác. Cụ thể là MFC, WTL, C++ Builder, Delphi, VB6 - tất cả các công cụ này đều sử dụng API Win32. Ngay cả Windows Forms phần lớn cũng tương thích với API Win32.
Công cụ: (tương tự VB) và trình bao bọc Python , (ngôn ngữ riêng, có giao diện IDispatch COM), (Trăn) (Ruby) (Hồng ngọc).
Tự động hóa giao diện người dùng của Microsoft
Ưu điểm chính: Công nghệ MS UI Automation hỗ trợ phần lớn các ứng dụng GUI trên Windows với một số ít trường hợp ngoại lệ. Vấn đề: Nó không dễ học hơn API Win32 nhiều. Nếu không thì sẽ không có ai làm giấy gói cho nó.
Trên thực tế, đây là một tập hợp các giao diện COM tùy chỉnh (chủ yếu UIAutomationCore.dll) và cũng có trình bao bọc .NET ở dạng namespace System.Windows.Automation. Nhân tiện, nó có một lỗi đã được giới thiệu do đó một số thành phần giao diện người dùng có thể bị bỏ sót. Vì vậy, tốt hơn hết bạn nên sử dụng trực tiếp UIAutomationCore.dll (nếu bạn đã nghe nói về UiaComWrapper trong C# thì chính là nó).
Các loại giao diện COM:
(1) IUknown cơ bản - “gốc rễ của mọi tội ác”. Mức độ thấp nhất, không bao giờ thân thiện với người dùng.
(2) IDispatch và các dẫn xuất (ví dụ: Excel.Application), có thể được sử dụng trong Python bằng gói win32com.client (có trong pyWin32). Lựa chọn thuận tiện và đẹp nhất.
(3) Giao diện tùy chỉnh mà gói Python của bên thứ ba có thể hoạt động .
Công cụ: trong C#, 0.6.0+ trong C#, (mã nguồn của họ cho trình bao bọc C trên UIAutomationCore.dll không được tiết lộ), trong Ruby.
AT-SPI
Mặc dù thực tế là hầu hết tất cả các trục của họ Linux đều được xây dựng trên Hệ thống X Window (trong Fedora 25, chữ “X” đã được đổi thành Wayland), “X” cho phép bạn chỉ vận hành các cửa sổ cấp cao nhất và chuột/ bàn phím. Để phân tích chi tiết các nút, hộp danh sách, v.v., có công nghệ AT-SPI. Các trình quản lý cửa sổ phổ biến nhất có cái gọi là daemon đăng ký AT-SPI, cung cấp GUI tự động cho các ứng dụng (ít nhất là hỗ trợ Qt và GTK).
Công cụ: .
Theo tôi, pyatspi2 chứa quá nhiều phụ thuộc như PyGObject. Bản thân công nghệ này có sẵn dưới dạng thư viện động thông thường libatspi.so. Đây là một . Đối với thư viện pywinauto, chúng tôi dự định triển khai hỗ trợ AT-SPI theo cách này: thông qua tải libatspi.so và mô-đun ctypes. Có một vấn đề nhỏ chỉ xảy ra khi sử dụng phiên bản bắt buộc, vì đối với các ứng dụng GTK+ và Qt, chúng hơi khác nhau một chút. Có thể dự kiến sẽ phát hành pywinauto 0.7.0 với sự hỗ trợ đầy đủ của Linux vào nửa đầu năm 2018.
API trợ năng của Apple
MacOS có ngôn ngữ tự động hóa riêng, AppleScript. Tất nhiên, để triển khai những thứ như thế này trong Python, bạn cần sử dụng các hàm từ ObjectiveC. Có vẻ như bắt đầu từ MacOS 10.6, gói pyobjc đã được bao gồm trong Python được cài đặt sẵn. Điều này cũng sẽ giúp việc liệt kê các phần phụ thuộc để hỗ trợ trong tương lai trong pywinauto dễ dàng hơn.
Công cụ: Ngoài ngôn ngữ Apple Script, điều đáng chú ý là , hay còn gọi là pyatom. Nó có giao diện tương thích với LDTP nhưng cũng là một thư viện độc lập. Nó có , được viết bởi học sinh của tôi. Có một vấn đề đã biết: thời gian linh hoạt không hoạt động (các phương pháp waitFor*). Nhưng nhìn chung, không phải là một điều xấu.
Cách bắt đầu với pywinauto
Bước đầu tiên là trang bị cho mình một trình kiểm tra đối tượng GUI (được gọi là công cụ Gián điệp). Nó sẽ giúp bạn nghiên cứu ứng dụng từ bên trong: cấu trúc phân cấp của các phần tử, những thuộc tính nào có sẵn. Các thanh tra trang web nổi tiếng nhất:
- Gián điệp ++ - đi kèm với Visual Studio, bao gồm Express hoặc Community Edition. Sử dụng API Win32. Bản sao của anh ấy cũng được biết đến Thông tin cửa sổ AutoIt.
- Kiểm tra.exe - được bao gồm trong SDK Windows. Nếu bạn đã cài đặt nó thì trên Windows 64-bit bạn có thể tìm thấy nó trong thư mục
C:Program Files (x86)Windows Kits<winver>binx64. Trong chính trình kiểm tra, bạn cần chọn một chế độ Tự động hóa giao diện người dùng thay vì MS AA (Trợ năng tiếp cận chủ động, tiền thân của Tự động hóa giao diện người dùng).
Sau khi kiểm tra kỹ lưỡng ứng dụng, chúng tôi chọn phần phụ trợ mà chúng tôi sẽ sử dụng. Chỉ cần chỉ định tên của phần phụ trợ khi tạo đối tượng Ứng dụng là đủ.
- phụ trợ =”win32″ — mặc dù được sử dụng theo mặc định nhưng vẫn hoạt động tốt với MFC, WTL, VB6 và các ứng dụng cũ khác.
- phụ trợ=”uia” — phần phụ trợ mới cho MS UI Automation: hoạt động hoàn hảo với WPF và WinForms; cũng tốt cho các ứng dụng Delphi và Windows Store; hoạt động với Qt5 và một số ứng dụng Java. Và nói chung, nếu Inspection.exe nhìn thấy các phần tử và thuộc tính của chúng thì phần phụ trợ này là phù hợp. Về nguyên tắc, hầu hết các trình duyệt cũng hỗ trợ Tự động hóa giao diện người dùng (theo mặc định là Mozilla và Chrome cần được cung cấp phím dòng lệnh khi khởi động
--force-renderer-accessibilityđể xem các thành phần trên các trang trong Inspection.exe). Tất nhiên, việc cạnh tranh với Selenium trong lĩnh vực này là khó có thể xảy ra. Chỉ là một cách khác để làm việc với trình duyệt (có thể hữu ích cho trường hợp sản phẩm chéo).
Điểm đầu vào cho tự động hóa
Ứng dụng này đã được nghiên cứu rộng rãi. Đã đến lúc tạo một đối tượng Ứng dụng và chạy nó hoặc đính kèm vào một đối tượng đang chạy. Đây không chỉ là bản sao của một lớp tiêu chuẩn subprocess.Popen, cụ thể là một đối tượng đầu vào giới hạn tất cả hành động của bạn trong phạm vi ranh giới của quy trình. Điều này rất hữu ích nếu một số phiên bản của ứng dụng đang chạy nhưng bạn không muốn chạm vào phần còn lại.
from pywinauto.application import Application
app = Application(backend="uia").start('notepad.exe')
# Опишем окно, которое хотим найти в процессе Notepad.exe
dlg_spec = app.UntitledNotepad
# ждем пока окно реально появится
actionable_dlg = dlg_spec.wait('visible')Nếu bạn muốn quản lý nhiều ứng dụng cùng một lúc, lớp này sẽ giúp bạn Desktop. Ví dụ: trong máy tính trên Win10, hệ thống phân cấp của các phần tử được trải rộng trên một số quy trình (không chỉ calc.exe). Vì vậy không có đối tượng Desktop không đủ.
from subprocess import Popen
from pywinauto import Desktop
Popen('calc.exe', shell=True)
dlg = Desktop(backend="uia").Calculator
dlg.wait('visible')Đối tượng gốc (Application hoặc Desktop) là nơi duy nhất bạn cần chỉ định phần phụ trợ. Mọi thứ khác rõ ràng rơi vào khái niệm “đặc tả->trình bao bọc”, sẽ được thảo luận sau.
Thông số kỹ thuật cửa sổ/phần tử
Đây là khái niệm cốt lõi mà giao diện pywinauto được xây dựng. Bạn có thể mô tả một cửa sổ/phần tử một cách đại khái hoặc chi tiết hơn, ngay cả khi nó chưa tồn tại hoặc đã đóng. Đặc tả cửa sổ (đối tượng Đặc điểm kỹ thuật cửa sổ) lưu trữ các tiêu chí để tìm kiếm một cửa sổ hoặc phần tử thực.
Ví dụ về đặc tả cửa sổ chi tiết:
>>> dlg_spec = app.window(title='Untitled - Notepad')
>>> dlg_spec
<pywinauto.application.WindowSpecification object at 0x0568B790>
>>> dlg_spec.wrapper_object()
<pywinauto.controls.win32_controls.DialogWrapper object at 0x05639B70>Việc tìm kiếm cửa sổ tự xảy ra bằng cách gọi phương thức .wrapper_object(). Nó trả về một “trình bao bọc” nhất định cho một cửa sổ/phần tử thực hoặc ném ElementNotFoundError (đôi khi ElementAmbiguousError, nếu tìm thấy một số phần tử, tức là bạn cần làm rõ tiêu chí tìm kiếm). “Trình bao bọc” này đã biết cách thực hiện một số hành động với một phần tử hoặc nhận dữ liệu từ phần tử đó.
Python có thể ẩn cuộc gọi .wrapper_object(), do đó mã cuối cùng trở nên ngắn hơn. Chúng tôi khuyên bạn chỉ nên sử dụng nó cho mục đích gỡ lỗi. Hai dòng tiếp theo thực hiện chính xác điều tương tự:
dlg_spec.wrapper_object().minimize() # debugging
dlg_spec.minimize() # productionCó nhiều tiêu chí tìm kiếm cho một đặc tả cửa sổ. Đây chỉ la một vai vi dụ:
# могут иметь несколько уровней
app.window(title_re='.* - Notepad$').window(class_name='Edit')
# можно комбинировать критерии (как AND) и не ограничиваться одним процессом приложения
dlg = Desktop(backend="uia").Calculator
dlg.window(auto_id='num8Button', control_type='Button')Danh sách tất cả các tiêu chí có thể có trong tài liệu hàm .
Sự kỳ diệu của việc truy cập theo thuộc tính và khóa
Python giúp dễ dàng tạo các thông số kỹ thuật của cửa sổ và nhận dạng các thuộc tính đối tượng một cách linh hoạt (bên trong, phương thức này bị ghi đè __getattribute__). Tất nhiên, các hạn chế tương tự được áp dụng đối với tên thuộc tính cũng như đối với tên của bất kỳ biến nào (bạn không thể chèn dấu cách, dấu phẩy hoặc các ký tự đặc biệt khác). May mắn thay, pywinauto sử dụng thuật toán tìm kiếm được gọi là “kết hợp tốt nhất” có khả năng chống lại lỗi chính tả và các biến thể nhỏ.
app.UntitledNotepad
# то же самое, что
app.window(best_match='UntitledNotepad')Nếu bạn vẫn cần chuỗi Unicode (ví dụ: đối với tiếng Nga), dấu cách, v.v., bạn có thể truy cập bằng phím (như thể đó là một từ điển thông thường):
app['Untitled - Notepad']
# то же самое, что
app.window(best_match='Untitled - Notepad')Năm quy tắc cho tên ma thuật
Làm thế nào để tìm ra tên ma thuật tiêu chuẩn? Những cái được gán cho phần tử trước khi tìm kiếm. Nếu bạn chỉ định một tên đủ giống với tiêu chuẩn thì phần tử sẽ được tìm thấy.
- Theo tiêu đề (văn bản, tên):
app.Properties.OK.click() - Theo văn bản và theo loại phần tử:
app.Properties.OKButton.click() - Theo loại và số lượng:
app.Properties.Button3.click()(tênButton0иButton1liên kết với phần tử đầu tiên được tìm thấy,Button2- đến thứ hai, và sau đó theo thứ tự - đây là cách nó xảy ra trong lịch sử) - Theo văn bản tĩnh (trái hoặc trên cùng) và theo loại:
app.OpenDialog.FileNameEdit.set_text("")(hữu ích cho các phần tử có văn bản động) - Theo loại và theo văn bản bên trong:
app.Properties.TabControlSharing.select("General")
Thông thường hai hoặc ba quy tắc được áp dụng cùng một lúc, hiếm khi nhiều hơn. Để kiểm tra tên cụ thể nào có sẵn cho từng thành phần, bạn có thể sử dụng phương thức print_control_identifiers(). Nó có thể in một cây gồm các phần tử ra màn hình và ra tệp. Đối với mỗi phần tử, tên ma thuật tiêu chuẩn của nó sẽ được in. Bạn cũng có thể sao chép và dán các thông số kỹ thuật chi tiết hơn của các phần tử con từ đó. Kết quả trong script sẽ như thế này:
app.Properties.child_window(data-gt-translate-attributes='["title"]' title="Contains:", auto_id="13087", control_type="Edit")Bản thân cây nguyên tố thường là một tấm khăn lau chân khá lớn.
>>> app.Properties.print_control_identifiers()
Control Identifiers:
Dialog - 'Windows NT Properties' (L688, T518, R1065, B1006)
[u'Windows NT PropertiesDialog', u'Dialog', u'Windows NT Properties']
child_window(data-gt-translate-attributes='["title"]' title="Windows NT Properties", control_type="Window")
|
| Image - '' (L717, T589, R749, B622)
| [u'', u'0', u'Image1', u'Image0', 'Image', u'1']
| child_window(auto_id="13057", control_type="Image")
|
| Image - '' (L717, T630, R1035, B632)
| ['Image2', u'2']
| child_window(auto_id="13095", control_type="Image")
|
| Edit - 'Folder name:' (L790, T596, R1036, B619)
| [u'3', 'Edit', u'Edit1', u'Edit0']
| child_window(data-gt-translate-attributes='["title"]' title="Folder name:", auto_id="13156", control_type="Edit")
|
| Static - 'Type:' (L717, T643, R780, B658)
| [u'Type:Static', u'Static', u'Static1', u'Static0', u'Type:']
| child_window(data-gt-translate-attributes='["title"]' title="Type:", auto_id="13080", control_type="Text")
|
| Edit - 'Type:' (L790, T643, R1036, B666)
| [u'4', 'Edit2', u'Type:Edit']
| child_window(data-gt-translate-attributes='["title"]' title="Type:", auto_id="13059", control_type="Edit")
|
| Static - 'Location:' (L717, T669, R780, B684)
| [u'Location:Static', u'Location:', u'Static2']
| child_window(data-gt-translate-attributes='["title"]' title="Location:", auto_id="13089", control_type="Text")
|
| Edit - 'Location:' (L790, T669, R1036, B692)
| ['Edit3', u'Location:Edit', u'5']
| child_window(data-gt-translate-attributes='["title"]' title="Location:", auto_id="13065", control_type="Edit")
|
| Static - 'Size:' (L717, T695, R780, B710)
| [u'Size:Static', u'Size:', u'Static3']
| child_window(data-gt-translate-attributes='["title"]' title="Size:", auto_id="13081", control_type="Text")
|
| Edit - 'Size:' (L790, T695, R1036, B718)
| ['Edit4', u'6', u'Size:Edit']
| child_window(data-gt-translate-attributes='["title"]' title="Size:", auto_id="13064", control_type="Edit")
|
| Static - 'Size on disk:' (L717, T721, R780, B736)
| [u'Size on disk:', u'Size on disk:Static', u'Static4']
| child_window(data-gt-translate-attributes='["title"]' title="Size on disk:", auto_id="13107", control_type="Text")
|
| Edit - 'Size on disk:' (L790, T721, R1036, B744)
| ['Edit5', u'7', u'Size on disk:Edit']
| child_window(data-gt-translate-attributes='["title"]' title="Size on disk:", auto_id="13106", control_type="Edit")
|
| Static - 'Contains:' (L717, T747, R780, B762)
| [u'Contains:1', u'Contains:0', u'Contains:Static', u'Static5', u'Contains:']
| child_window(data-gt-translate-attributes='["title"]' title="Contains:", auto_id="13088", control_type="Text")
|
| Edit - 'Contains:' (L790, T747, R1036, B770)
| [u'8', 'Edit6', u'Contains:Edit']
| child_window(data-gt-translate-attributes='["title"]' title="Contains:", auto_id="13087", control_type="Edit")
|
| Image - 'Contains:' (L717, T773, R1035, B775)
| [u'Contains:Image', 'Image3', u'Contains:2']
| child_window(data-gt-translate-attributes='["title"]' title="Contains:", auto_id="13096", control_type="Image")
|
| Static - 'Created:' (L717, T786, R780, B801)
| [u'Created:', u'Created:Static', u'Static6', u'Created:1', u'Created:0']
| child_window(data-gt-translate-attributes='["title"]' title="Created:", auto_id="13092", control_type="Text")
|
| Edit - 'Created:' (L790, T786, R1036, B809)
| [u'Created:Edit', 'Edit7', u'9']
| child_window(data-gt-translate-attributes='["title"]' title="Created:", auto_id="13072", control_type="Edit")
|
| Image - 'Created:' (L717, T812, R1035, B814)
| [u'Created:Image', 'Image4', u'Created:2']
| child_window(data-gt-translate-attributes='["title"]' title="Created:", auto_id="13097", control_type="Image")
|
| Static - 'Attributes:' (L717, T825, R780, B840)
| [u'Attributes:Static', u'Static7', u'Attributes:']
| child_window(data-gt-translate-attributes='["title"]' title="Attributes:", auto_id="13091", control_type="Text")
|
| CheckBox - 'Read-only (Only applies to files in folder)' (L790, T825, R1035, B841)
| [u'CheckBox0', u'CheckBox1', 'CheckBox', u'Read-only (Only applies to files in folder)CheckBox', u'Read-only (Only applies to files in folder)']
| child_window(data-gt-translate-attributes='["title"]' title="Read-only (Only applies to files in folder)", auto_id="13075", control_type="CheckBox")
|
| CheckBox - 'Hidden' (L790, T848, R865, B864)
| ['CheckBox2', u'HiddenCheckBox', u'Hidden']
| child_window(data-gt-translate-attributes='["title"]' title="Hidden", auto_id="13076", control_type="CheckBox")
|
| Button - 'Advanced...' (L930, T845, R1035, B868)
| [u'Advanced...', u'Advanced...Button', 'Button', u'Button1', u'Button0']
| child_window(data-gt-translate-attributes='["title"]' title="Advanced...", auto_id="13154", control_type="Button")
|
| Button - 'OK' (L814, T968, R889, B991)
| ['Button2', u'OK', u'OKButton']
| child_window(data-gt-translate-attributes='["title"]' title="OK", auto_id="1", control_type="Button")
|
| Button - 'Cancel' (L895, T968, R970, B991)
| ['Button3', u'CancelButton', u'Cancel']
| child_window(data-gt-translate-attributes='["title"]' title="Cancel", auto_id="2", control_type="Button")
|
| Button - 'Apply' (L976, T968, R1051, B991)
| ['Button4', u'ApplyButton', u'Apply']
| child_window(data-gt-translate-attributes='["title"]' title="Apply", auto_id="12321", control_type="Button")
|
| TabControl - '' (L702, T556, R1051, B962)
| [u'10', u'TabControlSharing', u'TabControlPrevious Versions', u'TabControlSecurity', u'TabControl', u'TabControlCustomize']
| child_window(auto_id="12320", control_type="Tab")
| |
| | TabItem - 'General' (L704, T558, R753, B576)
| | [u'GeneralTabItem', 'TabItem', u'General', u'TabItem0', u'TabItem1']
| | child_window(data-gt-translate-attributes='["title"]' title="General", control_type="TabItem")
| |
| | TabItem - 'Sharing' (L753, T558, R801, B576)
| | [u'Sharing', u'SharingTabItem', 'TabItem2']
| | child_window(data-gt-translate-attributes='["title"]' title="Sharing", control_type="TabItem")
| |
| | TabItem - 'Security' (L801, T558, R851, B576)
| | [u'Security', 'TabItem3', u'SecurityTabItem']
| | child_window(data-gt-translate-attributes='["title"]' title="Security", control_type="TabItem")
| |
| | TabItem - 'Previous Versions' (L851, T558, R947, B576)
| | [u'Previous VersionsTabItem', u'Previous Versions', 'TabItem4']
| | child_window(data-gt-translate-attributes='["title"]' title="Previous Versions", control_type="TabItem")
| |
| | TabItem - 'Customize' (L947, T558, R1007, B576)
| | [u'CustomizeTabItem', 'TabItem5', u'Customize']
| | child_window(data-gt-translate-attributes='["title"]' title="Customize", control_type="TabItem")
|
| TitleBar - 'None' (L712, T521, R1057, B549)
| ['TitleBar', u'11']
| |
| | Menu - 'System' (L696, T526, R718, B548)
| | [u'System0', u'System', u'System1', u'Menu', u'SystemMenu']
| | child_window(data-gt-translate-attributes='["title"]' title="System", auto_id="MenuBar", control_type="MenuBar")
| | |
| | | MenuItem - 'System' (L696, T526, R718, B548)
| | | [u'System2', u'MenuItem', u'SystemMenuItem']
| | | child_window(data-gt-translate-attributes='["title"]' title="System", control_type="MenuItem")
| |
| | Button - 'Close' (L1024, T519, R1058, B549)
| | [u'CloseButton', u'Close', 'Button5']
| | child_window(data-gt-translate-attributes='["title"]' title="Close", control_type="Button")Trong một số trường hợp, việc in toàn bộ cây có thể chậm (ví dụ: trong iTunes có tới ba nghìn phần tử trên một tab!), nhưng bạn có thể sử dụng tùy chọn depth (chiều sâu): depth=1 - chính phần tử đó, depth=2 - chỉ có con ngay lập tức, v.v. Nó cũng có thể được chỉ định trong thông số kỹ thuật khi tạo child_window.
Ví dụ
Chúng tôi liên tục bổ sung . Trong số những cái gần đây, đáng chú ý là tính năng tự động hóa của bộ phân tích mạng WireShark (đây là một ví dụ điển hình về ứng dụng Qt5; mặc dù tác vụ này có thể được giải quyết mà không cần GUI, vì có scapy.Sniffer từ gói Python ). Ngoài ra còn có một ví dụ về tự động hóa MS Paint với thanh công cụ Ribbon.
Một ví dụ tuyệt vời khác được viết bởi một sinh viên của tôi: (nó sẽ chuyển đến kho lưu trữ chính sau đó một chút).
Và tất nhiên, một ví dụ về đăng ký các sự kiện bàn phím (phím nóng) và chuột:
.
Sự nhìn nhận
Đặc biệt cảm ơn những người không ngừng giúp đỡ phát triển dự án. Đối với tôi và Đây là một sở thích lâu dài. Hai sinh viên của tôi tại UNN gần đây đã bảo vệ bằng cử nhân về chủ đề này. đã đóng góp lớn vào việc hỗ trợ MS UI Automation và gần đây đã bắt đầu tạo một trình tạo mã tự động dựa trên nguyên tắc “phát lại bản ghi” dựa trên các thuộc tính văn bản (đây là tính năng phức tạp nhất), cho đến nay chỉ dành cho phần phụ trợ “uia”. đang phát triển một chương trình phụ trợ mới cho Linux dựa trên AT-SPI (mô-đun mouse и keyboard dựa trên - đã có trong phiên bản 0.6.x).
Vì tôi đã dạy một khóa học đặc biệt về tự động hóa bằng Python được một thời gian nên một số sinh viên thạc sĩ sẽ làm bài tập về nhà, triển khai các tính năng hoặc ví dụ nhỏ về tự động hóa. Một số điều mấu chốt ở giai đoạn nghiên cứu cũng từng được sinh viên phát hiện. Mặc dù đôi khi bạn phải giám sát chặt chẽ chất lượng của mã. Máy phân tích tĩnh (QuantifiedCode, Codacy và Landscape) và kiểm tra tự động trên đám mây (dịch vụ AppVeyor) với phạm vi bao phủ mã khoảng 95% giúp ích rất nhiều cho việc này.
Cũng xin cảm ơn tất cả những người đã để lại đánh giá, phát hiện lỗi và gửi yêu cầu kéo!
Tôi là người nước ngoài
Chúng tôi theo dõi các câu hỏi (gần đây xuất hiện ) Và . có .
Chúng tôi cập nhật hàng tháng . Xét về số lượng sao trên GitHub, chỉ có Autohotkey (họ có cộng đồng rất lớn và lịch sử lâu đời) và PyAutoGUI là đang phát triển nhanh hơn (phần lớn là do sự phổ biến của cuốn sách của tác giả Al Sweigart: “Automate the Boring Stuff with Python” và những thứ khác).
Nguồn: www.habr.com
