トップ回答者
powershellのIEを操作するスクリプトの中のgetElementByIdを使う箇所でエラーが起こる

質問
-
powershell3.0でIEを操作するスクリプトを作ったのですが、getElementByIdを使う箇所で起こるエラーの原因が分かりません。
以上です、よろしくお願い致します。
●ソースは以下の通りです。
#.NETクラスのSendkeyメソッドを呼び出す
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$ie = new-object -com InternetExplorer.Application
$ie.top=200
$ie.left=400
$ie.height=700
$ie.width=1000
$ie.visible=$true
[Microsoft.VisualBasic.Interaction]::AppActivate("Windows Internet Explorer")
#ログイン画面を表示
$ie.navigate("https://www.rakuten-card.co.jp/e-navi/?l-id=ichiba_mk_mtop_login")
#画面が変わるまで待機
While($ie.busy){Start-Sleep -milliseconds 100}
#ID、パスワードを入力
$doc = $ie.document
$txt_username = $doc.getElementByID("u")
$txt_username.value = "id"
$txt_passwd = $doc.getElementByID("p")
$txt_passwd.value = "password"
#ログインボタンをクリック
$btn_login = $doc.getElementByID("loginButton")
$btn_login.click()
#画面が変わるまで待機
While($ie.busy){Start-Sleep -milliseconds 100}
●エラーは以下の通りです。
"getElementById" のオーバーロードで、引数の数が "1" であるものが見つかりません。
発生場所 D:\Users\otochan\Documents\autologin.ps1:22 文字:1
+ $txt_username = $doc.getElementByID("u")
"getElementById" のオーバーロードで、引数の数が "1" であるものが見つかりません。
発生場所 D:\Users\otochan\Documents\autologin.ps1:24 文字:1
+ $txt_passwd = $doc.getElementByID("p")
"getElementById" のオーバーロードで、引数の数が "1" であるものが見つかりません。
発生場所 D:\Users\otochan\Documents\autologin.ps1:28 文字:1
+ $btn_login = $doc.getElementByID("loginButton")
IEが起動して目的のURLを開き終わるところまでは問題無く動いています。表示後の画面ソースで、間違いなくIDが"u"と"p"と"loginButton"の要素が存在している事は確認済みです。
getElementByIdの前に意図的に10秒程スリープを入れてもエラーが出ます。
しかし何故か会社のPCではエラー無く処理できます。
●環境は以下の通りです
OS:Windows7SP1(64bit)※会社PCは32bit
IE:10※会社PCも同じ
Powershell:3.0(Windows6.1-KB2506143-x64.msuで2.0からアップグレード)※会社PCも同じ
●他にやった事
環境の問題かと思い、念のためOSを入れ直して、Windows7SP1、IE8、Powershell2.0の環境でも実行してみましたが現象は変わりませんでした。- 編集済み むっくり 2013年9月9日 5:51
回答
-
> Variant getElementById ()
>
> と表示されました。これは問題無いと考えて良いのでしょうか???問題あると思われます。当方のWin8x64環境では正しく動作するのですが、getElementByIdメソッドのオーバーロードは以下のように表示されます。
OverloadDefinitions
-------------------
mshtml.IHTMLElement, Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a getElementById(string v)
mshtml.IHTMLElement, Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a DispHTMLDocument.getElementById(string v)
mshtml.IHTMLElement, Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a IHTMLDocument3.getElementById(string v)おそらくクラスのメソッド以外に、実装したインターフェースのメソッドも表示されてて分かりにくいですが、本質は、
getElementById(string v)
という部分で、getElementByIdメソッドは、「1個の文字列の引数を取るメソッド」であるという定義であることが示されています。
しかしながらむっくりさんが提示されたシグニチャは()の中が空です。つまり、getElementByIdメソッドは「引数なし(引数の数が0)のメソッド」と定義されていることになります。
これが「"getElementById" のオーバーロードで、引数の数が "1" であるものが見つかりません。」というエラーが発生する原因です。もちろんgetElementByIdは、IDとなる文字列を引数として1つ指定するとオブジェクトを返却するメソッドなので、引数なしというメソッド定義がおかしいことになります。
原因はよくわからないのですが、COMオブジェクトのメソッドの情報がうまくPowerShellの扱うオブジェクトにバインドされてないように思えます。
Win7 x64に特有の現象なのか、IEのオプションが影響しているのか、アンチウィルスソフト等が悪さをしているのか、申し訳ないですが私にはこれ以上のことは分かりません。
すべての返信
-
会社PCと自宅PCの違いといえばOSが32bitか64bitかの違いしかなさそうですから、まずは自宅PC(64bit)の32bit版PowerShellで動作するかどうかを確認してみてはいかがでしょうか。(当方、Win7 x64環境が今手元になくて確認できませんでした)
32bit版PowerShellのパスは"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe"になります。また、エラーの出る環境で、$doc.getElementByID と入力した場合、何が表示されますでしょうか。
メソッドに対し()を付けずに記述すると、メソッドのシグニチャ(オーバーロードのリスト)が表示されます。あと英語版MSDNフォーラムに、getElementByID, getElementsByTagName works in IE8, but not IE9というスレッドがありました。
この回答に、$element = [System.__ComObject].InvokeMember(“getElementById”,[System.Reflection.BindingFlags]::InvokeMethod, $null, $doc, $id)
のようにリフレクションを使ってメソッドを実行すればうまくいったとの記載があります。これを試してみるのはいかがでしょうか。
# どうもPowerShellでCOMオブジェクトのメソッドを実行するときは変なことになることが多い気がしてます。
-
牟田口様ありがとうございます。
助言に沿ってまず32bit版powershellを試してみましたが、結果は64bit版と全く同じでした。
>また、エラーの出る環境で、$doc.getElementByID と入力した場合、何が表示されますでしょうか。
についてですが、
OverloadDefinitions
-------------------
Variant getElementById ()と表示されました。これは問題無いと考えて良いのでしょうか???
もう一つの英語版の情報ですが、内容をある程度理解してから試そうと思い、まだ実行しておりません。
この部分の結果が出たらまた報告させて頂きたいと思います。
あと、同じスクリプトを、家にもう一台ある妻のVISTA(32bit)で動かしてみましたが、こちらの方も何の問題・エラーも無く正常動作しました。困ったものです。
># どうもPowerShellでCOMオブジェクトのメソッドを実行するときは変なことになることが多い気がしてます。
なるほど、そういうものなんですか(涙)
-
> Variant getElementById ()
>
> と表示されました。これは問題無いと考えて良いのでしょうか???問題あると思われます。当方のWin8x64環境では正しく動作するのですが、getElementByIdメソッドのオーバーロードは以下のように表示されます。
OverloadDefinitions
-------------------
mshtml.IHTMLElement, Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a getElementById(string v)
mshtml.IHTMLElement, Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a DispHTMLDocument.getElementById(string v)
mshtml.IHTMLElement, Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a IHTMLDocument3.getElementById(string v)おそらくクラスのメソッド以外に、実装したインターフェースのメソッドも表示されてて分かりにくいですが、本質は、
getElementById(string v)
という部分で、getElementByIdメソッドは、「1個の文字列の引数を取るメソッド」であるという定義であることが示されています。
しかしながらむっくりさんが提示されたシグニチャは()の中が空です。つまり、getElementByIdメソッドは「引数なし(引数の数が0)のメソッド」と定義されていることになります。
これが「"getElementById" のオーバーロードで、引数の数が "1" であるものが見つかりません。」というエラーが発生する原因です。もちろんgetElementByIdは、IDとなる文字列を引数として1つ指定するとオブジェクトを返却するメソッドなので、引数なしというメソッド定義がおかしいことになります。
原因はよくわからないのですが、COMオブジェクトのメソッドの情報がうまくPowerShellの扱うオブジェクトにバインドされてないように思えます。
Win7 x64に特有の現象なのか、IEのオプションが影響しているのか、アンチウィルスソフト等が悪さをしているのか、申し訳ないですが私にはこれ以上のことは分かりません。
-
牟田口さんこんにちは。
正常動作する会社のPCでgetElementByIdを実行したところ、牟田口さんの環境と同じような表示になりました。
時間があれば、問題のある環境にWindows7の32bit版を入れてみて試そうと思いますが、powershell以外の点で64bit版の7に何の不満も無く(むしろ調子が良い)ので、迷うところですが偶々見つけた牟田口さんのWSHに関するページに、WSHでIEを操作するサンプルもあったので、これも参考にして”枯れた”技術のWSHで作り直す事も候補として考えてみたいと思います。
今回は大変助かりました、ありがとうございます。
-
PowerShellでCOMオブジェクトを扱うのは、COM→.NET→PowerShellと多段階を経る必要がある分、どうしてもどこかで何か変なことになるケースが多い気がします。
その点、WSH + VBScriptはCOMの世界の住人なので、素直に扱えます。今でもCOMの絡む自動化はWSH + VBScriptがお勧めです。(JScriptはJavaScriptの世界に引きずられる分ちょっと面倒なことが多い)
WSHスクリプトをPowerShellスクリプト内で呼び出すことはもちろん可能なので、COMを扱う部分だけWSH、残りはPowerShellで作るという方法も有効かと思います。どうぞ、ご検討くださいませ。