今回が初めての投稿になります。
プログラミング&アウトプットど素人の投稿です。
エクセル内データを社内Webアプリに転記し他部署に申請書類を作る操作を自動化しました。
必要な操作は、
Internet Explorerの起動
→Webアプリの申請書類作成ページにジャンプ
→ログインID, パスワードの入力(ログイン済みの場合は省略)
→必要な項目にデータを転記
です。
まず、普通にCreateObjectを使ってInternet Explorerを扱おうとしましたが早速ダメでした。
Dim username, password As String
Dim ie As Object
Dim submitElm As HTMLFormElement
username = Application.InputBox("ログインIDを入力", Type:=2)
password = Application.InputBox("パスワードを入力", Type:=2)
Set ie = CreateObject("InternetExplorer.Application")
'社内WebアプリのURL
ie.Navigate "http://***"
'ユーザーIDとパスワードのinput要素のそれぞれのname属性値を使って見つける
'それぞれにユーザーが入力した値を入れる
ie.document.getElementsByName("_Account")(0).Value = username
ie.document.getElementsByName("Password")(0).Value = password
'submitボタンの操作
'DocumentクラスのFormsプロパティにコントロール名(今回は"LoginForm")を指定
Set submitElm = ie.document.forms("LoginForm")
submitElm.submit
色々調べてみると社内で使うようなイントラネットの場合、セキュリティレベルの問題が起きてダメみたいです。
こちらのサイトを参考にさせていただきました。
Default Integrity Level and Automation
UWSCでIE(オブジェクト)を保護モード整合性レベル中"Medium"で起動する方法
完全には理解できませんでしたが、ようはIEには複数のセキュリティレベル(LowとMediumと(Highも?))があって、オブジェクト生成時はLowだけどリンクの遷移などでページが切り替わった時に、イントラネットの場合はセキュリティレベルがMediumに切り替わる。このため新しいMediumのオブジェクトができているのに、VBA側のオブジェクトは古いLowのオブジェクトのままだから具合が悪い。
そんな感じでしょうか。
対策としては、初めからMediumでオブジェクトを作ってしまえ!ということのようです。そのためCreateObjectではなくGetObjectを使って以下のようにします。
Const IE_MEDIUM = "{D5E8041D-920F-45E9-B8FB-B1DEB82C6E5E}"
Dim ie As Object
Set ie = GetObject("new:" & IE_MEDIUM)
'社内アプリのURL
ie.navigate "http://***"
{D5E8041D-920F-45E9-B8FB-B1DEB82C6E5E}・・・?って感じですが、これは、レジストリに記載されている CLSID でIEのセキュリティレベルをMediumで扱うIDということらしい。
結局、以下のコードで無事に完成しました。
Dim inputValues(1 To 5) As String
Private Sub getValues()
Dim i As Integer
For i = 1 To 5
inputValues(i) = Cells(1, i).Value
Next i
End Sub
Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Sub operateIe()
Const IE_MEDIUM = "{D5E8041D-920F-45E9-B8FB-B1DEB82C6E5E}"
'エクセルの必要なセルから転記するデータを集計
Call getValues
Dim username, password As String
Dim ie As Object
Set ie = GetObject("new:" & IE_MEDIUM)
ie.Visible = False
'社内WebアプリのURL
ie.navigate "http://***"
Do While ie.readyState <> 4
Do While ie.Busy = True
Loop
Loop
Sleep 2000
'IEを使ってすでにWebアプリにログインしている場合エラーが発生するので
'その場合はlogin_errに飛ばす
On Error GoTo login_err:
'既にログインしている場合、inputboxでユーザーに入力を促す前にエラーを生じさせ
'login_errに飛んだ方が良いので先にログインID欄にa(適当な文字)を入れようとすることでわざとエラーを生じさせる
ie.document.getElementsByName("_Account")(0).Value = "a"
username = Application.InputBox("ログインIDを入力", Type:=2)
password = Application.InputBox("パスワードを入力", Type:=2)
ie.document.getElementsByName("_Account")(0).Value = username
ie.document.getElementsByName("Password")(0).Value = password
Dim submitElm As HTMLFormElement
Set submitElm = ie.document.forms("LoginForm")
submitElm.submit
Do While ie.readyState <> 4
Do While ie.Busy = True
Loop
Loop
Sleep 2000
'ログインIDやパスワードを間違えた場合、エラーとなり
'タイトルがエラーページとなるので、これを利用してSubを抜ける
If ie.document.getElementsByTagName("title")(0).innerText = "エラーページ" Then
MsgBox "IDまたはパスワードが違います" & vbLf & "再度試みてください"
ie.Quit
Exit Sub
End If
On Error GoTo 0
login_err:
'必要なデータを転記する
ie.document.getElementsByName("Subject")(0).Value = inputValues(1)
ie.document.getElementsByName("20001")(0).Value = inputValues(2)
ie.document.getElementsByName("20002")(0).Value = inputValues(3)
ie.document.getElementsByName("20003")(0).Value = inputValues(4)
ie.document.getElementsByName("20004")(0).Value = inputValues(5)
MsgBox "完了" & vbLf & "ブラウザを確認してください"
ie.Visible = True
End Sub
##まとめ
実際には転記したいデータがもう少し複雑だったのですが(エクセルのセルを扱う部分)、今回のアウトプットテーマとは関係なかったので単純化してあります。
また、私の場合、Sleepで2秒待機でちょうどうまく動きました。これは状況によると思います。