機器人流程自動化(RPA),像人類工作者一樣,透過跨各種應用程式運行的軟體或硬體系統實現任務自動化。軟體或機器人可以學習具有多個步驟和應用程式的工作流程,例如獲取收到的表格、發送回執訊息、檢查表格的完整性、將表格歸檔到資料夾中以及使用表格名稱更新電子表格,提交日期等。 RPA軟體旨在減輕員工完成重複性簡單任務的負擔。
請確保本機已安裝對應用戶端,且rpa-client
與rpa-server
均已啟動。
當前系統支援以下客戶端:
AppId | Name |
---|---|
微信 | |
wecom | 企業微信 |
騰訊QQ | |
tim | TIM |
dingtalk | 釘釘 |
lark | 飛書 |
由於任務必須透過指定使用者去執行,所以在執行任務之前,需要確保使用者存在。
http://<host>:<port>/users
POST
JSON
Body
Property | Type | Required | Description |
---|---|---|---|
users | User[] | 必填 | 使用者物件數組。 |
└ id | String | 可選 | 用戶ID。為空時服務端會自動產生ID。 |
└ appId | String | 必填 | 關聯AppID。 |
└ account | String | 必填 | 用戶帳號,用於匹配客戶端。 |
└ nickname | String | 可選 | 使用者暱稱,用於展示。 |
└ realname | String | 可選 | 使用者真實名稱,用於展示。 |
└ company | String | 可選 | 用戶所屬公司名稱,用於展示。 |
注意,
企业微信
客戶端中無法直接取得目前登入人的account
,目前是透過${realname}_${company}
組合來匹配客戶端。
接口範例:
curl -X POST --location " http://localhost:8080/users "
-H " Content-Type: application/json "
-d " {
" users " : [
{
" id " : " uid " ,
" appId " : " wechat " ,
" account " : " account " ,
" nickname " : " nickname "
}
]
} "
insert into user (id, app_id, account, nickname, realname, company, status, created_time, updated_time)
values ( ' uid ' , ' wechat ' , ' account ' , ' nickname ' , ' realname ' , ' company ' , 1 , now(), null );
http://<host>:<port>/tasks
POST
JSON
Body
Property | Type | Required | Description |
---|---|---|---|
tasks | Task[] | 必填 | 任務對象數組。 |
└ id | String | 可選 | 任務ID。為空時服務端會自動產生ID。 |
└ userId | String | 必填 | 關聯用戶ID。 |
└ type | String | 必填 | 任務類型,參考任務類型字典表。 |
└ priority | Integer | 可選 | 任務優先級,數值越小越優先。為空時取預設配置的優先權。 |
└ data | String | 可選 | 任務數據,格式為JSON 字串。 |
└ scheduleTime | DateTime | 可選 | 任務執行時間,例如: 2022-01-01 10:00:00 。為空時會立即執行。 |
範例:
curl -X PATCH --location " http://localhost:8080/tasks "
-H " Content-Type: application/json "
-d " {
" tasks " : [
{
" id " : " tid " ,
" userId " : " uid " ,
" type " : " login " ,
" priority " : " 0 " ,
" data " : "" ,
" scheduleTime " : " 2022-01-01 10:00:00 " ,
}
]
} "
insert into task (id, user_id, app_id, type, priority, data, status, created_time, updated_time, schedule_time)
values ( ' tid ' , ' uid ' , ' wechat ' , ' login ' , 0 , null , 0 , now(), null , ' 2022-01-01 10:00:00 ' );
服務端提供了一個運行時的測試頁面,開發者可以用它在本地測試簡單任務。 開啟瀏覽器存取http://<host>:<port>/index.html
,然後選擇待測試的客戶端即可。
登入客戶端不需要參數
登出客戶端不需要參數
參數格式:
Property | Type | Required | Description |
---|---|---|---|
target | String | 必填 | 發送對象。 |
messages | Message[] | 必填 | 訊息對象數組。 |
└ type | String | 必填 | 訊息類型。 |
└ content | String | 必填 | 訊息內容,文字內容或文件地址。 |
訊息類型:
Code | Name | Description |
---|---|---|
text | TEXT | 文字 |
image | IMAGE | 圖片 |
video | VIDEO | 影片 |
file | FILE | 文件 |
參數範例:
{
"target" : " friend " ,
"messages" : [
{
"type" : " text " ,
"content" : " message "
},
{
"type" : " image " ,
"content" : " https://rpa.leego.io/image.png "
},
{
"type" : " video " ,
"content" : " https://rpa.leego.io/video.mp4 "
},
{
"type" : " file " ,
"content" : " https://rpa.leego.io/file.zip "
}
]
}
參數格式:
Property | Type | Required | Description |
---|---|---|---|
target | String | 必填 | 群名稱。 |
messages | Message[] | 必填 | 訊息對象數組。 |
└ type | String | 必填 | 訊息類型。 |
└ content | String | 必填 | 訊息內容,文字內容或文件地址。 |
訊息類型:
Code | Name | Description |
---|---|---|
text | TEXT | 文字 |
image | IMAGE | 圖片 |
video | VIDEO | 影片 |
file | FILE | 文件 |
mention | MENTION | 提醒 |
參數範例:
{
"target" : " group " ,
"messages" : [
{
"type" : " text " ,
"content" : " message "
},
{
"type" : " image " ,
"content" : " https://rpa.leego.io/image.png "
},
{
"type" : " video " ,
"content" : " https://rpa.leego.io/video.mp4 "
},
{
"type" : " file " ,
"content" : " https://rpa.leego.io/file.zip "
},
{
"type" : " mention " ,
"content" : " member "
}
]
}
登入客戶端不需要參數
登出客戶端不需要參數
參數格式:
Property | Type | Required | Description |
---|---|---|---|
target | String | 必填 | 發送對象。 |
messages | Message[] | 必填 | 訊息對象數組。 |
└ type | String | 必填 | 訊息類型。 |
└ content | String | 必填 | 訊息內容,文字內容或文件地址。 |
訊息類型:
Code | Name | Description |
---|---|---|
text | TEXT | 文字 |
image | IMAGE | 圖片 |
video | VIDEO | 影片 |
file | FILE | 文件 |
參數範例:
{
"target" : " friend " ,
"messages" : [
{
"type" : " text " ,
"content" : " message "
},
{
"type" : " image " ,
"content" : " https://rpa.leego.io/image.png "
},
{
"type" : " video " ,
"content" : " https://rpa.leego.io/video.mp4 "
},
{
"type" : " file " ,
"content" : " https://rpa.leego.io/file.zip "
}
]
}
參數格式:
Property | Type | Required | Description |
---|---|---|---|
target | String | 必填 | 群名稱。 |
messages | Message[] | 必填 | 訊息對象數組。 |
└ type | String | 必填 | 訊息類型。 |
└ content | String | 必填 | 訊息內容,文字內容或文件地址。 |
訊息類型:
Code | Name | Description |
---|---|---|
text | TEXT | 文字 |
image | IMAGE | 圖片 |
video | VIDEO | 影片 |
file | FILE | 文件 |
mention | MENTION | 提醒 |
參數範例:
{
"target" : " group " ,
"messages" : [
{
"type" : " text " ,
"content" : " message "
},
{
"type" : " image " ,
"content" : " https://rpa.leego.io/image.png "
},
{
"type" : " video " ,
"content" : " https://rpa.leego.io/video.mp4 "
},
{
"type" : " file " ,
"content" : " https://rpa.leego.io/file.zip "
},
{
"type" : " mention " ,
"content" : " member "
}
]
}
參數格式:
Property | Type | Required | Description |
---|---|---|---|
target | String | 必填 | 群名稱。 |
contacts | Contact[] | 必填 | 聯絡人物件數組。 |
└ target | String | 必填 | 用戶手機號碼或信箱。 |
└ reason | String | 可選 | 新增聯絡人備註。 |
參數範例:
{
"contacts" : [
{ "target" : " phone " },
{ "target" : " email " , "reason" : " reason " }
]
}
過於先進,不宜展示。
為了防止客戶端被多次啟動,開發者通常會使用建立互斥體(Mutex)物件的方式進行實作。互斥鎖是一種用於多執行緒程式設計中,保護共享資源不被多個執行緒或程序同時存取的機制。
HANDLE CreateMutexA (
[in, optional] LPSECURITY_ATTRIBUTES lpMutexAttributes,
[in] BOOL bInitialOwner,
[in, optional] LPCSTR lpName
);
[in, optional] lpMutexAttributes
指向SECURITY_ATTRIBUTES 結構的指標。如果此參數為NULL
,則句柄不能被子程序繼承。
結構的lpSecurityDescriptor
成員指定新互斥體的安全描述符。如果lpMutexAttributes
為NULL
,則互斥鎖將獲得預設的安全描述符。互斥鎖的預設安全描述符中的ACL
來自創建者的主要或模擬令牌。
[in] bInitialOwner
如果此值為TRUE
且呼叫者建立了互斥鎖,則呼叫執行緒將獲得互斥鎖物件的初始所有權。否則,呼叫執行緒不會獲得互斥鎖的所有權。若要確定呼叫者是否建立了互斥鎖,請參閱傳回值部分。
[in, optional] lpName
互斥對象的名稱。這個名稱僅限於MAX_PATH
個字元。名稱比較區分大小寫。
如果lpName
與現有的命名互斥物件的名稱匹配,則此函數要求MUTEX_ALL_ACCESS
存取權限。在這種情況下,將忽略bInitialOwner
參數,因為它已由建立過程設定。如果lpMutexAttributes
參數不是NULL,它決定句柄是否可以被繼承,但它的安全描述子成員被忽略。
如果lpName
為NULL
,則建立互斥物件時沒有名稱。
如果lpName
與現有事件、信號量、可等待計時器、作業或文件映射物件的名稱匹配,則函數將失敗並且GetLastError 函數傳回ERROR_INVALID_HANDLE
。這是因為這些物件共享相同的命名空間。
此名稱可以具有「全域」或「本機」前綴,以在全域或會話命名空間中明確建立物件。名稱的其餘部分可以包含除反斜線字元() 之外的任何字元。有關詳細信息,請參閱內核物件命名空間。使用終端服務會話實現快速使用者切換。核心物件名稱必須遵循為終端服務概述的準則,以便應用程式可以支援多個使用者。
該物件可以在私有命名空間中建立。有關詳細信息,請參閱物件命名空間。
如果函數成功,則傳回值是新建立的互斥物件的句柄(Handle)。
如果函數失敗,則傳回值為NULL
。若要取得擴充功能的錯誤訊息,請呼叫GetLastError 函數。
如果互斥鎖是命名互斥鎖且物件在此函數呼叫之前存在,則傳回值是現有物件的句柄,且GetLastError 函數傳回ERROR_ALREADY_EXISTS
。
Process Explorer 是Microsoft 官方提供的找出進程已開啟或載入的Handle
和DLL
資訊的工具。
Process Explorer 官方頁面:https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer
範例:
以WeChat 為例,先啟動WeChat,在Process Explorer 主介面中找到名為WeChat.exe
進程並選取。
然後在Lower Pane
介面中找到Type
為Mutant
且Name
為Sessions1BaseNamedObjects_WeChat_App_Instance_Identity_Mutex_Name
的Handle
。
右鍵點選Close Handle
關閉句柄後,即可啟動新程序。
handles = handler . find_handles ( process_ids = [ 10000 ], handle_names = [ r'Sessions1BaseNamedObjects_WeChat_App_Instance_Identity_Mutex_Name' ])
handler . close_handles ( handles )
參考原始碼:client/handler/handler.py
tscon
保持Windows遠端桌面關閉後仍可互動的方法使用遠端桌面連接到遠端電腦時,關閉遠端桌面會鎖定電腦並顯示登入畫面。在鎖定模式下,電腦沒有GUI
,因此任何目前運行或計劃的GUI
測試都將失敗。
為避免GUI
測試出現問題,可以使用tscon
實用程式來中斷與遠端桌面的連線。 tscon
將控制權傳回遠端電腦上的原始本機會話,繞過登入畫面。遠端電腦上的所有程式繼續正常運行,包括GUI
測試。
tscon
? tscon
是Windows系統提供的可用於連接到遠端桌面會話主機伺服器上的另一個會話的工具。
tscon
? tscon { < sessionID > | < sessionname > } [/dest: < sessionname > ] [/password: < pw > | /password: * ] [/v]
參數 | 描述 |
---|---|
<sessionID> | 指定要連線的會話的ID。如果使用可選/dest:<sessionname> 參數,也可以指定目前會話的名稱。 |
<sessionname> | 指定要連線的會話的名稱。 |
/dest: <sessionname> | 指定目前會話的名稱。當您連接到新會話時,此會話將斷開連接。您也可以使用此參數將另一個使用者的會話連接到不同的會話。 |
/password: <pw> | 指定擁有要連線到的會話的使用者的密碼。當連線使用者不擁有會話時,需要此密碼。 |
/password: * | 提示擁有您要連線的會話的使用者的密碼。 |
/v | 顯示有關正在執行的操作的資訊。 |
/? | 在命令提示字元處顯示幫助。 |
若要從遠端桌面斷開連接,請以管理員身分在遠端電腦上(在遠端桌面連線視窗中)執行下列命令,例如,透過命令列:
%windir% S ystem32 t scon.exe RDP-Tcp# # # NNN /dest:console
其中RDP-Tcp### NNN
是目前遠端桌面會話的ID
,例如RDP-Tcp#5
。您可以在Windows任務管理器的「使用者」標籤上的「會話」列中看到它。
您將看到您的遠端桌面服務工作階段已結束訊息,並且遠端桌面用戶端將關閉。但遠端電腦上的所有程式和測試將繼續正常運作。
提示:會話列預設隱藏。要顯示它,請右鍵單擊顯示CPU、記憶體等的行中的某處,然後在開啟的上下文選單中選擇會話。
您可以使用批次檔自動執行斷開程序。在遠端電腦上,執行以下操作:
for /f " skip=1 tokens=3 " %%s in ( ' query user %USERNAME% ' ) do (
%windir% S ystem32 t scon.exe %%s /dest:console
)
tscon
使遠端電腦保持解鎖狀態,這會降低系統安全性。測試運行結束後,您可以使用以下命令鎖定電腦:
Rundll32.exe user32.dll, LockWorkStation
如果遠端電腦上正在執行rdpclip.exe
進程,且當您從遠端會話斷開連線時剪貼簿不為空,則rdpclip.exe
進程可能會失敗。
為避免此問題,您可以在斷開會話之前終止rdpclip.exe
進程。
若需要拓展自動化功能或相容於不同版本的用戶端,您可以在rpa-client/app 模組中新增或編輯任務腳本。
專案中主要使用以下兩種方式實作:
pywinauto
是用於Microsoft Windows GUI 自動化的python 模組。在最簡單的情況下,它允許您將滑鼠和鍵盤操作發送到Windows 對話框和控件,但它支援更複雜的操作,例如獲取文字資料。
Airtest
是由網易遊戲推出的一個跨平台的、基於影像辨識的UI自動化測試框架,適用於遊戲和App,支援平台有Windows、Android和iOS。
請確保使用的作業系統為Windows 7 及以上,Python 的版本為3.7.0以上。
需要注意airtest 目前版本依賴pywinauto==0.6.3
,當前專案需要pywinauto==0.6.8
,在安裝依賴時請加上--no-deps
參數,或在安裝完依賴後手動執行一遍pip install pywinauto==0.6.8
。
git clone https://github.com/yihleego/robotic-process-automation.git
cd robotic-process-automation/rpa-client
pip install --no-deps -r requirements.txt
客戶端設定檔位於rpa-client/config.yml,開發者可以根據實際場景修改設定。
Property | Description | Default |
---|---|---|
server.host | 伺服器主機 | localhost |
server.port | 伺服器連接埠 | 18888 |
server.path | 伺服器路徑 | /rpa |
server.ssl | 是否啟用SSL | False |
app.size | 程式最大可運行數量 | 32 |
app.path. <appid> | 自訂程式路徑 | 從註冊表中獲取 |
airtest.cvstrategy | 影像辨識演算法 | [ tpl,sift,brisk ] |
airtest.timeout | 影像辨識演算法 | 20秒 |
airtest.timeout-tmp | 影像辨識演算法 | 3秒 |
logging.level | 日誌等級 | DEBUG |
logging.format | 日誌格式 | 預設格式 |
logging.filename | 日誌檔名 | ./logs/rpa-client.log |
運行rpa-client/main.py 即可。
請確保使用的Java 的版本為17及以上,服務執行時間依賴MySQL 和Redis,請務必在部署服務前安裝並啟動它們。
git clone https://github.com/yihleego/robotic-process-automation.git
cd robotic-process-automation/rpa-server
mvn clean install
Property | Description | Default |
---|---|---|
spring.datasource.driver-class-name | 資料來源驅動 | com.mysql.cj.jdbc.Driver |
spring.datasource.url | 資料來源URL | jdbc:mysql://localhost:3306/rpa |
spring.datasource.username | 資料來源使用者名稱 | |
spring.datasource.password | 資料來源密碼 | |
spring.data.redis.host | Redis主機 | localhost |
spring.data.redis.port | Redis埠 | 6379 |
spring.data.redis.password | Redis密碼 | |
spring.data.redis.database | Redis資料庫 | 0 |
上述配置可於application.properties 檔案中修改。
Property | Description | Default |
---|---|---|
rpa.websocket.port | WebSocket服務端口 | 18888 |
rpa.websocket.path | WebSocket服務路徑 | /rpa |
rpa.websocket.idle-timeout | WebSocket服務空閒逾時時間 | 5m |
rpa.converter.date-time-pattern | 全域日期時間格式 | yyyy-MM-dd HH:mm:ss |
rpa.converter.date-pattern | 全域器日期格式 | yyyy-MM-dd |
rpa.converter.time-pattern | 全局時間格式 | HH:mm:ss |
rpa.client.cache-key | 客戶端快取鍵格式 | rpa:client: <appid> : <account> |
rpa.client.cache-timeout | 客戶端快取逾時時間 | 5m |
詳情請見RpaProperties。
啟動服務前,請先在MySQL
實例中執行下列腳本
運行RpaApplication.java 即可。
$(".btn").click();
。判斷一個應用程式是否支援UIA 可以使用微軟官方提供的軟體Inspect, 可以從官網或這個倉庫下載:
範例中微信使用了UiaApp 模式,因為它是基於UIA 實現的; 而企業微信使用了AirApp 模式,它類似網頁中僅有存在一個Canvas,所有元素都是透過程式碼繪製渲染,所以只能透過圖像辨識定位。
下載Visual C++ Redistributable Packages for Visual Studio 2013 https://www.microsoft.com/zh-cn/download/confirmation.aspx?id=40784
請參考:2#issue
本項目僅供學習參考,請勿用於生產環境。
This project is under the MIT license. See the LICENSE file for details.