きっかけ
身近で「某社のRPAのソフトを契約して、事務系の業務を自動化するんだぁ」って話が複数聞こえてきて。。。
そんなん無くても、「VBScriptだけでもソコソコの作業は自動化できるよ」ってのが伝わらないので、自分の作業自動化用に作っていたVBScriptのClassを公開してみます。
概要
仕事で、PC(Windows)でやって大抵の作業は
- ブラウザの操作(ちゃんと制御できるのはIEのみですが)
- マウス操作
- キーボード入力
ができれば、ほぼいけます(ただし、「力業で何とか」の場合もありますが)。
あとは、
- エクセル操作
- ファイルの入出力
あたりでしょうか。
ちょっと特殊(?)なところで
- CSVにSQLを投げて検索、集計
ができれば、大丈夫かな。
あとは、その組み合わせで、日々の定型業務はこなせると思います。
で、「VBScriptでもClass作れるんじゃん」ってことを、恥ずかしながら最近知ったので、Class化して便利に使っている、今日この頃です。
Classファイル
IE関連
' IE関連のクラス
Class IeUtilClass
' 内部変数宣言 -------------------------------------------------------------
Private Ie
' コンストラクタ
Private Sub Class_Initialize()
Set Ie = CreateObject("InternetExplorer.Application")
End Sub
' デストラクタ
Private Sub Class_Terminate()
Set Ie = Nothing
End Sub
' Public関数 ---------------------------------------------------------------
' URLオープン
Public Sub Navigate(str)
Ie.Navigate(str)
End Sub
Public Sub Visible(bln)
Ie.Visible = bln
End Sub
Public Sub FullScreen(bln)
Ie.FullScreen = bln
End Sub
Public Sub Quit
Ie.Quit
End Sub
Public Sub WaitProc
Do While ie.Busy = True Or ie.readystate <> 4
Loop
End Sub
Public Function getElementById(id)
Set getElementById = Ie.document.getElementById(id)
End Function
Public Function GetElementsByName(name)
Set GetElementsByName = Ie.document.GetElementsByName(name)
End Function
Public Function GetElementsByClassName(name)
Set GetElementsByClassName = Ie.document.GetElementsByClassName(name)
End Function
Public Function GetElementsByTagName(name)
Set GetElementsByTagName = Ie.document.GetElementsByTagName(name)
End Function
End Class
マウス関連
以下のサイトを参考に(というか、ほぼそのまま)クラス化しました。
VBScriptでマウスポインタを動かしたりクリックしたり座標を取得したりするサンプル · GitHub
マウスを操作するには、WindowsのAPIをたたく必要がありますが、エクセルを使えば簡単なようです。
「まぁ、ほとんどの業務用のPCならExeclはあるでしょ」ってことで、APIたたくのにExcelを使って楽してます。
「エクセル使うのやだ」って方は・・・ググってください m(__)m
(そういうサンプルも見かけました)
' マウス関連のクラス
Class MouseUtilClass
' 内部変数宣言 -------------------------------------------------------------
Private Excel
Private SCREEN_X
Private SCREEN_Y
' Property宣言 -------------------------------------------------------------
' Private-----------------------------------------------
'キーコード
Private Property Get VK_SHIFT
VK_SHIFT = &H10
End Property
'マウス定数
Private Property Get MOUSEEVENTF_ABSOLUTE
MOUSEEVENTF_ABSOLUTE = &H8000&
End Property
Private Property Get MOUSE_MOVE
MOUSE_MOVE = &H1
End Property
Private Property Get MOUSEEVENTF_LEFTDOWN
MOUSEEVENTF_LEFTDOWN = &H2
End Property
Private Property Get MOUSEEVENTF_LEFTUP
MOUSEEVENTF_LEFTUP = &H4
End Property
' Private関数 --------------------------------------------------------------
' コンストラクタ
Private Sub Class_Initialize()
Dim items
Set items = CreateObject("WbemScripting.SWbemLocator").ConnectServer.ExecQuery("Select * From Win32_VideoController")
For Each item In items
SCREEN_X = item.CurrentHorizontalResolution
SCREEN_Y = item.CurrentVerticalResolution
Next
End Sub
' デストラクタ
Private Sub Class_Terminate()
Set Excel = Nothing
End Sub
' Public関数 ---------------------------------------------------------------
'クリック
Public Sub MouseClick
Dim dwFlags
dwFlags = MOUSEEVENTF_LEFTDOWN Or MOUSEEVENTF_LEFTUP
Call API_mouse_event(dwFlags, 0, 0, 0, 0)
WScript.Sleep 100
End Sub
'SHIFT+クリック
Public Sub MouseClickShift
Dim dwFlags
Call API_keybd_event(VK_SHIFT,0,1,0)
dwFlags = MOUSEEVENTF_LEFTDOWN Or MOUSEEVENTF_LEFTUP
Call API_mouse_event(dwFlags, 0, 0, 0, 0)
Call API_keybd_event(VK_SHIFT,0,3,0)
WScript.Sleep 100
End Sub
'ダブルクリック
Public Sub DoubleClick
MouseClick
MouseClick
End Sub
'マウスポインタ移動
Public Sub MouseMove(x, y)
Dim pos_x, pos_y, dwFlags
dwFlags = MOUSEEVENTF_ABSOLUTE Or MOUSE_MOVE
pos_x = Int(x * 65535 / SCREEN_X)
pos_y = Int(y * 65535 / SCREEN_Y)
Call API_mouse_event(dwFlags, pos_x, pos_y, 0, 0)
WScript.Sleep 100
End Sub
' マウスポインタの座標取得
Public Function GetMousePos()
GetMousePos = API_GetMessagePos
End Function
Public Function GetMousePosX()
Dim pos
pos = API_GetMessagePos
GetMousePosX = pos(0)
End Function
Public Function GetMousePosY()
Dim pos
pos = API_GetMessagePos
GetMousePosX = pos(1)
End Function
' Private関数 --------------------------------------------------------------
'************************
'APIを叩く処理
'************************
Private Sub API_mouse_event(dwFlags, dx, dy, dwData, dwExtraInfo)
Dim strFunction
Const API_STRING = "CALL(""user32"",""mouse_event"",""JJJJJj"", $1, $2, $3, $4, $5)"
strFunction = Replace(Replace(Replace(Replace(Replace(API_STRING, "$1", dwFlags), "$2", dx), "$3", dy), "$4", dwData), "$5", dwExtraInfo)
Call Excel.ExecuteExcel4Macro(strFunction)
End Sub
Private Sub API_keybd_event(bVk, bScan, dwFlags, dwExtraInfo)
Dim strFunction
Const API_STRING = "CALL(""user32"",""keybd_event"",""JJJJJ"", $1, $2, $3, $4)"
strFunction = Replace(Replace(Replace(Replace(API_STRING, "$1", bVk), "$2", bScan), "$3", dwFlags), "$4", dwExtraInfo)
Call Excel.ExecuteExcel4Macro(strFunction)
End Sub
Private Function API_GetMessagePos()
Dim ret, strHex, x, y
Dim strFunction
Const API_STRING = "CALL(""user32"",""GetMessagePos"",""J"")"
strFunction = API_STRING
ret = Excel.ExecuteExcel4Macro(strFunction)
strHex = Right("00000000" & Hex(ret), 8)
x = CLng("&H" & Right(strHex, 4))
y = CLng("&H" & Left(strHex, 4))
API_GetMessagePos = Array(x, y)
End Function
End Class
キーボード関連
Sendkeysは半角のみ(全角は未対応)なので、全角を投げたい場合はクリップボード経由で行うのですが、そこはSendkeys関数を宣言して、内部で「全角を含むかどうか」を判断し、Sendkeysでいくか、クリップボードを使うかを判断しています。
' キーボード関連のクラス
Class KeyboardUtilClass
' 内部変数宣言 -------------------------------------------------------------
Private wsh
' Private関数 --------------------------------------------------------------
' コンストラクタ
Private Sub Class_Initialize()
Set wsh = WScript.CreateObject("WScript.Shell")
End Sub
' デストラクタ
Private Sub Class_Terminate()
Set wsh = Nothing
End Sub
' Public関数 ---------------------------------------------------------------
'クリック
Public Sub Sendkeys(str)
If Len(str) = LenByte(str) Then
wsh.SendKeys str
Else
' 全角文字が含まれている場合は、クリップボード経由で
wsh.Run "cmd.exe /c echo " & str & "| clip", 0, true
wsh.SendKeys "^v"
End If
End Sub
' Private関数 --------------------------------------------------------------
Private Function LenByte(ByVal s)
Dim c, i, k
c = 0
For i = 0 To Len(s) - 1
k = Mid(s, i + 1, 1)
If (Asc(k) And &HFF00) = 0 Then
c = c + 1
Else
c = c + 2
End If
Next
LenByte = c
End Function
End Class
呼び出しサンプル
上記のクラスの呼び出しサンプルです。
呼び出し元のスクリプトで、クラスファイルを読み込む必要があるので、そのへんを参考にしてください。
操作の自動化をしていると、どうしても「マウスカーソルを特定の座標に移動させて、クリック」みたいなことが必要になります。
そんなとき、「ここの座標っていくつよ?」を調べるためのスクリプトです。
(カーソルを移動させるのはオマケ)
フォルダ構成が以下の場合のサンプルです。
VBScripts
│ 99.mousepos.vbs
│
└─lib
IeUtilClass.vbs
KeyboardUtilClass.vbs
MouseUtilClass.vbs
' マウス座標取得スクリプト
' ライブラリ読み込み
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")
' 実行ファイルパス取得
Dim myPath
myPath = fso.getParentFolderName(WScript.ScriptFullName)
' マウス関連クラス -------------------------------------
Dim libMouse
Set libMouse = fso.OpenTextFile(myPath & "\lib\MouseUtilClass.vbs")
ExecuteGlobal libMouse.ReadAll()
libMouse.Close
Set libMouse = Nothing
' メイン処理 -------------------------------------------------------------------
Dim mouseUtil
Set mouseUtil = New MouseUtilClass
Dim pos
WScript.Echo "3"
WScript.Sleep(1000)
WScript.Echo "2"
WScript.Sleep(1000)
WScript.Echo "1"
WScript.Sleep(1000)
pos = mouseUtil.GetMousePos()
WScript.Echo pos(0) & " / " & pos(1)
WScript.Sleep(1000)
WScript.Echo "Move to "
WScript.Sleep(1000)
Call mouseUtil.MouseMove(pos(0)+100,pos(1)+100)
' 解放
Set mouseUtil = Nothing
Set fso = Nothing
'終了
WScript.Quit
ひとまず
ここまで。
- ファイルの入出力
は、次の機会に。
ファイルの読み書きは、文字コードの問題があるので、クラス化しとくと便利ですね。
会社業務だと、
- エクセル操作
- データベース関係
- CSVにSQLを投げて検索、集計
- ネットワークドライブの接続・切断
あたりを使うこともありますね。
CSVにSQL投げて検索は地味に便利です。
でも、このへんはクラスにしてみましたが、あまり便利感がなかったのは、僕の作り方が悪かったのか・・・というところ。
(要望があれば、公開します)