VBAによるIE操作についてご存知の方にお尋ねします。以下のコードを試しているのですが、フォームを指定したらタグが抜き出せるのに、指定しなければタグが抜き出せません。ドキュメント中のエレメントが多すぎるからでしょうか?


1:Debug.Print objIE.Document.forms("hoge").all.tags("b").Length →5と出力
2:Debug.Print objIE.Document.all.Length →2500と出力 
3:Debug.Print objIE.Document.all.tags("b").length →エラーを起こす

よろしくお願いします。

回答の条件
  • 1人5回まで
  • 13歳以上
  • 登録:2010/10/07 05:40:08
  • 終了:2010/10/11 14:52:26

ベストアンサー

id:Silvanus No.4

Silvanus回答回数174ベストアンサー獲得回数672010/10/08 09:43:07

ポイント40pt

doxasさんがご指摘の様に、On Error GoToの行の先頭にアポストロフィ(')を挿入し、

エラー処理を無効化してから実行して、エラーメッセージを報告していただかないと

なかなか問題の本質を把握できません。

また、以下のコードを実行して、そのページの内部の構造が

きちんと列挙されるかどうか確認されてみては?

Option Explicit

Sub Enumerate_objAppIE_Document_All()

Dim iCount1 As Integer

Dim objAppIE As Object

Set objAppIE = CreateObject("InternetExplorer.application")

objAppIE.Visible = True

objAppIE.Navigate "http://XXX.YYY/"

While objAppIE.ReadyState <> 4

While objAppIE.Busy = True

DoEvents

Wend

Wend

Sheets.Add

ActiveSheet.Name = "Report" & Format(Rnd() * 10000, "0")

Cells(1, 1).Value = "Num"

Cells(1, 2).Value = "Type"

Cells(1, 3).Value = "Tag"

Cells(1, 4).Value = "OuterHTML"

Columns(1).ColumnWidth = 10

Columns(2).ColumnWidth = 20

Columns(3).ColumnWidth = 10

Columns(4).ColumnWidth = 100

For iCount1 = 0 To objAppIE.Document.All.Length - 1

Cells(iCount1 + 2, 1) = iCount1

Cells(iCount1 + 2, 2) = "'" & TypeName(objAppIE.Document.All(iCount1))

Cells(iCount1 + 2, 3) = "'" & objAppIE.Document.All(iCount1).TagName

Cells(iCount1 + 2, 4) = "'" & Left(objAppIE.Document.All(iCount1).OuterHTML, 100)

Next

End Sub

id:ReoReo7

ありがとうございます。プログラムを実行してみたところ、できました!

実行には2分ほどかかりました。NUM=2331程度でした。

内部の構造の取得には問題ないようですね・・・。


複数ある"B"タグの中から、所望の"B"タグの中身(innerText)を取り出したかったのですが、まず"B"要素を取り出したくてもできなくて困っていました。

そこで、違う回避策を見つけました。このほうが実行も早そうです。

objIE.Document.all.tags("b").length

ではなくて、所望の"B"タグの直前(タグ数で10個以内)にある、「DIV ID="hoge"」や「SCRIPT NAME="hoge2"」のように、ユニークなIDまたは名前のついている要素を

Dim i as Long

i = objIE.Document.all.Item("hoge").sourceindex

のように取得して、

Dim j as Long

For j = i to i + 10

If objIE.Document.all.Item(j).nodeName = "B" then

msgbox "望みの'B'タグの中身は" & objIE.Document.all.Item(j).innerText & "です。"

End If

Next

として取得することで解決している状態です。

まだ、そもそも何でエラーしたのかは分かっていませんが。。

2010/10/09 13:47:18

その他の回答(3件)

id:doxas No.1

doxas回答回数13ベストアンサー獲得回数42010/10/07 12:13:55

ポイント20pt

ソースコードが一部しか記載されていないですし、情報が少なすぎます。

もう少し細かく開示していただければ、解決のお手伝いができるかもしれません。

まずエラーが起きるということですが、どのような内容のエラーが起きるのでしょうか。

また、データ取得の対象となるHTMLソースには、どのくらいの<b>要素があるのでしょう。

全体が2500だからそれ以下だとは思いますが、もう少し情報をいただけませんか。

普通に考えると ReoReo7 さんが示してくれたコードでうまくいくはずですね。

現状ではそれ以上のことが言えません。

id:ReoReo7

ありがとうございます。

その "b" の要素を一つ一つ取り出そうとしたのですが、うまくいきませんでした。

数えてみたら100くらいだと思います。

「普通に考えると ReoReo7 さんが示してくれたコードでうまくいくはずですね。」

↑コードの誤りそのものでは無いということですね。ありがとうございます。

多分全体の数が大きすぎるのかな?

あと、エラーの捕捉の方法が分かりません。

objIEはIEオブジェクトを格納しており、これはある会員制サイトのページを表示しています。

On Error GoTo myFail

Debug.Print objIE.Document.forms("hoge").all.tags("b").Length '←1

Debug.Print objIE.Document.all.Length '←2

Debug.Print objIE.Document.all.tags("b").Length '←3

Debug.Print " "

myFailコロン

で、F8を押しながら一つ一つ実行していくと、←3の時点でmyFailへ移動します。

2010/10/07 21:35:20
id:a-kuma3 No.2

a-kuma3回答回数4363ベストアンサー獲得回数18002010/10/07 12:17:12

ポイント20pt

エラーの内容をさらすと、答えがつきやすいんじゃないかな。

とりあえず、length の頭が L になってないのを、候補に挙げておこう。

id:ReoReo7

エラーの内容の捕捉ができたら補足します!Lは単純に質問時のミスでした。

2010/10/07 21:35:49
id:doxas No.3

doxas回答回数13ベストアンサー獲得回数42010/10/07 21:57:22

ポイント20pt

こんばんは。回答者1です。

On Error GoTo~ の記述がありますので、これだとエラーメッセージは表示されずに、指定されている myFail へ処理が移ってしまいますね。エラーの内容を得る方法はいくつかありますが、この On Error GoTo~ の一行を無効化しておけばエラーメッセージが出るはずです。

F8を押しながらステップ実行しているのであれば、オブジェクト(IEやそれに付随するオブジェクト)が破棄されてしまっているなどの、参照系のエラーではないと思いますが、なんでしょうね……想像がつきません。

もし、可能であればローカルウィンドウを活用して、オブジェクトの中身を参照してみると原因がわかるかもしれません。手元にExcelがないので記憶に頼るかたちになりますが、VBEの表示メニューのなかに、ローカルウィンドウというのがあるはずですので、それを表示しておき、同様にF8でステップ実行してみてください。ローカルウィンドウのなかにオブジェクトの詳細な情報が表示されるはずです。

他に有効なデバッグ手段としては、オブジェクト変数をもうひとつ用意して、そちらにまずデータを取得してみる方法が考えられます。

Dim objTAG_B As Object 'オブジェクト変数をひとつ新しく宣言

'------------------------
'中略
'------------------------

Set objTAG_B = objIE.Document.all.tags("b") 'オブジェクト変数にエレメントコレクションを取得

上記のようにオブジェクト変数に一度データを取得することができると、ローカルウィンドウから目的の情報を探しやすくなるでしょう。

ただし、一度オブジェクト変数を経由しているとは言え、<b>タグのエレメントコレクションを取得しようとしている処理自体は ReoReo7 さんが先に掲示してくれたコードと同じです。つまり先ほどのエラーの原因がわからないと(解決しないと)、オブジェクト変数(objTAG_B)にオブジェクトを得ることができないはずです。

とにかくエラーの内容、これがわからないことにはどうにも難しいです。

id:ReoReo7

ありがとうございます。

エラーコード取得はまだできていませんが、先にローカルウィンドウでのオブジェクトの展開を試してみました。

オブジェクトの構造は、objIE-Document-allの下にItem(*)があるのですが、これがItem(256)までしか表示されていません。つまり、エレメントの下のコマンドが使えるのは256個以下の数字のみということになりそうです。

つまり、Debug.Print objIE.Document.all.Lengthは2500個あっても出力できるが、その下位エレメントであるobjIE.Document.all.tags("b")というのは、allの数が256を超えた時点でtags()コマンドが使用不可になるらしいのです。

ありがとうございました。必要に応じてもう少し掘り下げてみます。

追記(10月9日):

Dim objTAG_B as Object

Set objTAG_B = objAppIE.Document.all.tags("b")

debug.print objAppIE.Document.all.tags("b").Length

を、4の回答者Silvanusさんの示すプログラムのURLの値を所望のアドレスに変えてobjAppIEを取得後、試しましたが、コメント欄に示すエラーが出ます。また、URLをwww.google.co.jpで試したところ、

Debug.Print objAppIE.document.all.Length '106を出力

Set objButton = objAppIE.document.all.tags("b") '実行可能

Debug.Print objAppIE.document.all.tags("b").Length '2を出力

となり、大丈夫でした。このエラーの原因は分かりませんが、ページのDocument.All.Lengthで示されるエレメント数が256を超えていることと何か関係あるのでしょうか。

2010/10/09 13:58:12
id:Silvanus No.4

Silvanus回答回数174ベストアンサー獲得回数672010/10/08 09:43:07ここでベストアンサー

ポイント40pt

doxasさんがご指摘の様に、On Error GoToの行の先頭にアポストロフィ(')を挿入し、

エラー処理を無効化してから実行して、エラーメッセージを報告していただかないと

なかなか問題の本質を把握できません。

また、以下のコードを実行して、そのページの内部の構造が

きちんと列挙されるかどうか確認されてみては?

Option Explicit

Sub Enumerate_objAppIE_Document_All()

Dim iCount1 As Integer

Dim objAppIE As Object

Set objAppIE = CreateObject("InternetExplorer.application")

objAppIE.Visible = True

objAppIE.Navigate "http://XXX.YYY/"

While objAppIE.ReadyState <> 4

While objAppIE.Busy = True

DoEvents

Wend

Wend

Sheets.Add

ActiveSheet.Name = "Report" & Format(Rnd() * 10000, "0")

Cells(1, 1).Value = "Num"

Cells(1, 2).Value = "Type"

Cells(1, 3).Value = "Tag"

Cells(1, 4).Value = "OuterHTML"

Columns(1).ColumnWidth = 10

Columns(2).ColumnWidth = 20

Columns(3).ColumnWidth = 10

Columns(4).ColumnWidth = 100

For iCount1 = 0 To objAppIE.Document.All.Length - 1

Cells(iCount1 + 2, 1) = iCount1

Cells(iCount1 + 2, 2) = "'" & TypeName(objAppIE.Document.All(iCount1))

Cells(iCount1 + 2, 3) = "'" & objAppIE.Document.All(iCount1).TagName

Cells(iCount1 + 2, 4) = "'" & Left(objAppIE.Document.All(iCount1).OuterHTML, 100)

Next

End Sub

id:ReoReo7

ありがとうございます。プログラムを実行してみたところ、できました!

実行には2分ほどかかりました。NUM=2331程度でした。

内部の構造の取得には問題ないようですね・・・。


複数ある"B"タグの中から、所望の"B"タグの中身(innerText)を取り出したかったのですが、まず"B"要素を取り出したくてもできなくて困っていました。

そこで、違う回避策を見つけました。このほうが実行も早そうです。

objIE.Document.all.tags("b").length

ではなくて、所望の"B"タグの直前(タグ数で10個以内)にある、「DIV ID="hoge"」や「SCRIPT NAME="hoge2"」のように、ユニークなIDまたは名前のついている要素を

Dim i as Long

i = objIE.Document.all.Item("hoge").sourceindex

のように取得して、

Dim j as Long

For j = i to i + 10

If objIE.Document.all.Item(j).nodeName = "B" then

msgbox "望みの'B'タグの中身は" & objIE.Document.all.Item(j).innerText & "です。"

End If

Next

として取得することで解決している状態です。

まだ、そもそも何でエラーしたのかは分かっていませんが。。

2010/10/09 13:47:18
  • id:Silvanus
    どの様なエラーメッセージが出たのか、どこのページを対象に解析をかけているのか、
    何を目的にこの様なことをしようとしているのか、等々、
    付記しておけば回答を得られやすくなると思うのですが…。
  • id:ReoReo7
    エラーを捕捉できました。
    実行時エラー438
    オブジェクトは、このプロパティまたはメソッドをサポートしていません。
    でした。
  • id:Silvanus
    済みません…ギブアップです…。対象が会員制サイトである以上、
    我々が直接検証する訳にはいかないですしね…。
    一度ならずお役に立てませず申し訳ございませんでした…。
  • id:ardarim
    all.tagsはIE固有なので、標準の同等機能として以下ではどうでしょう?
    objIE.Document.GetElementsByTagName("b").Length
    動き方が違う可能性は考えられます。
  • id:ReoReo7
    ありがとうございます。
    質問期限が迫っているので、ひとまずポイント配分し、その後の経過はコメントに示そうと思います。
  • id:ReoReo7
    今回はデバッグに有効な道筋を示すヒントとなるプログラムを提供してくれた方にいるか賞差し上げましたが、回答者様、コメントを下さった方全員に感謝しております。
  • id:doxas
    ardarimさんがコメント欄にて示してくださっている内容でいけそうな気もしますが、この手のエラーが出るというのはどういうことだか……ちょっとわかりませんね。
    私が自分の環境で試してみた限りでは、なかなかエラーを再現できませんでした。いろいろやってはみたのですが、正直お手上げ状態です。すいません。
    解決できなくて私もちょっと残念。なんとか問題解決できるといいですね。応援してます。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません