DOMを変数で渡してinnerTextを得る方法
未読分:16件
昨日以降(0) 2日前以降(0) 3日前以降(0) 4日前以降(0) 5日前以降(0)
近田 伸矢, 植木 悠二, 上田 寛
IEのデータ収集&自動操作のプログラミング本はこの1冊だけ!IEの起動やポップアップウィンドウ、表示を制御する基本的なコードはもちろん、テキストボックスやラジオボタン、表、ハイパーリンクなどのHTML部品を制御する方法など、自動操作に欠かせないノウハウを丁寧に解説。
Message#16 2015年7月18日(土)01時55分 From: 管理人 | 返事 削除 変更 |
> のIf InStr(objDoc.outerHTML, keywords) > 0 Thenの中のobjDoc.outerHTMLは、オブジェクト名が変わっているので、正しくは > If InStr(myDoc.outerHTML, keywords) > 0 > になります。 > こちらでしたら、正常に取得できますね。 > 管理人様へメール報告しておきました。 VBAマスター様 ご連絡ありがとうございました。 ご指摘どおり記述が間違っておりました。 修正しましたので、ご報告させていただきます。 |
Message#15 2015年7月17日(金)18時40分 From: pyonko | 返事 削除 変更 |
ジャッカルのメッセージ(#14)への返事 ありがとうございました。 > 確かに、myDocに変更するとうまくいくね。 > IEバージョンの問題ではないか? > 違うバージョンを試してみるとか。 IE.8(基幹業務のため)では、先程報告したエラーが出ましたが、 別のPC(IE.11)で実行したところ、myDocに変更することで、 3か所のMsgBoxが全て正常に表示されました。 環境さえ合致すれば利用が可能であることが判りましたので、 大変スッキリしました。 いろいろご指導いただきまして、ありがとうございました。 |
Message#14 2015年7月17日(金)15時33分 From: ジャッカル | 返事 削除 変更 |
> のIf InStr(objDoc.outerHTML, keywords) > 0 Thenの中のobjDoc.outerHTMLは、オブジェクト名が変わっているので、正しくは > If InStr(myDoc.outerHTML, keywords) > 0 > になります。 確かに、myDocに変更するとうまくいくね。 IEバージョンの問題ではないか? 違うバージョンを試してみるとか。 もしくは64bitを利用しているとか。 64bit版はエラーがおきやすいらしい。 |
Message#13 2015年7月17日(金)10時12分 From: pyonko | 返事 削除 変更 |
VBAマスターのメッセージ(#12)への返事 > のIf InStr(objDoc.outerHTML, keywords) > 0 Thenの中のobjDoc.outerHTMLは、オブジェクト名が変わっているので、正しくは > > > If InStr(myDoc.outerHTML, keywords) > 0 > > になります。 ご指摘ありがとうございました。 このとおりにした上で、再度実行しました。 結果は、2015年7月16日(木)15時53分に投稿した時と同じことになりました。 ・一つ目のMsgBoxは表示されましたが、空白 ・二つ目表示の直前で実行時エラー438。 Case "class" Set objDoc = objIE.Document.getElementsByClassName(elementName) のSet objDoc.......で停止します。elementNameには「classtest3」は入っていますが、 onjDocは「Nothing」です。 参照設定は、Microsoft Internet Controlesの他に必要なものがあったりしますでしょうか? ご面倒おかけしますが、よろしくお願いします。 【追記】 Microsoft HTML Object Libraly を追加設定して実行しましたが、状況に変化はありませんでした。 |
Message#12 2015年7月17日(金)08時45分 From: VBAマスター | 返事 削除 変更 |
サブルーチンが間違っていますね。 For Each myDoc In objDoc With myDoc If InStr(objDoc.outerHTML, keywords) > 0 Then Select Case valueType Case "innerHTML" tagValue = .innerHTML Case "innerText" tagValue = .innerText Case "outerHTML" tagValue = .outerHTML Case "outerText" tagValue = .outerText End Select Exit For のIf InStr(objDoc.outerHTML, keywords) > 0 Thenの中のobjDoc.outerHTMLは、オブジェクト名が変わっているので、正しくは If InStr(myDoc.outerHTML, keywords) > 0 になります。 こちらでしたら、正常に取得できますね。 管理人様へメール報告しておきました。 |
Message#11 2015年7月17日(金)00時12分 From: pyonko | 返事 削除 変更 |
ジャッカルのメッセージ(#10)への返事 > 設定したコードを張らないことには答えようがないはず。 > 多分、エラーからみてドキュメントが取得できずエラーが起きているんだろう。 > オブジェクトの取得もね。 失礼しました。前回投稿したのと違うPCからですが、コードを付けます。http://www.vba-ie.net/element/tagvalue.html のサンプルをそのまま使ったもので、一切変更しておりません。 Sub sample() Dim objIE As InternetExplorer 'IE(InternetExplorer)でテストページを起動する Call ieView(objIE, "http://www.vba-ie.net/code/all.html") 'getElementsByNameメソッドで文書ドキュメントを抽出する MsgBox tagValue(objIE, "name", "nametest3", "円(税込)", "innerText") 'getElementsByClassNameメソッドで文書ドキュメントを抽出する MsgBox tagValue(objIE, "class", "classtest3", "円(税込)", "innerText") 'getElementsByTagNameメソッドで文書ドキュメントを抽出する MsgBox tagValue(objIE, "tag", "td", "円(税込)", "innerText") End Sub Function tagValue(objIE As InternetExplorer, _ methodType As String, _ elementName As String, _ keywords As String, _ valueType As String) As String Dim objDoc As Object, myDoc As Object Select Case methodType Case "id" Set objDoc = objIE.Document.getElementById(elementName) Case "name" Set objDoc = objIE.Document.getElementsByName(elementName) Case "class" Set objDoc = objIE.Document.getElementsByClassName(elementName) Case "tag" Set objDoc = objIE.Document.getElementsByTagName(elementName) End Select For Each myDoc In objDoc With myDoc If InStr(objDoc.outerHTML, keywords) > 0 Then Select Case valueType Case "innerHTML" tagValue = .innerHTML Case "innerText" tagValue = .innerText Case "outerHTML" tagValue = .outerHTML Case "outerText" tagValue = .outerText End Select Exit For End If End With Next End Function 今sample()を実行させますと、一つ目のMsgBoxが表示される前にストップします。エラー内容は変わりませんでした。 今回は、elementNameには"nametest3"が入っています。 (前回投稿時は、一つ目のMsgBoxは表示され(ただし内容は"")、二つ目の手前で止まったので、elementNameが"classtest3"になったんだと思います。) |
Message#10 2015年7月16日(木)23時07分 From: ジャッカル | 返事 削除 変更 |
> 1回目が""ということは、 > MsgBox tagValue(objIE, "name", "nametest3", "円(税込)", "innerText") > の結果が""、 > 2回目では、黄色くなったコードの「elementName」の上にマウスをかざすと、 > ツールチップで「classtest3」が入っていますが、「objDoc」の上では、 > 「Nothing」になります。 classtest3? nametest3の間違いということか? これだけじゃ何が悪いのかなんて分からないぞ。 設定したコードを張らないことには答えようがないはず。 多分、エラーからみてドキュメントが取得できずエラーが起きているんだろう。 オブジェクトの取得もね。 |
Message#9 2015年7月16日(木)15時53分 From: pyonko | 返事 削除 変更 |
VBAマスターのメッセージ(#8)への返事 いろいろやっています。 今回は、tagValue用に掲示されているサンプルコードを変更なしで実行してみました。 その結果、最初のMsgBoxでは中身は"", そして2回目のMsgBoxは表示されず、次のコードの背景が黄色くなり、 Set objDoc = objIE.Document.getElementsByClassName(elementName) でストップし、 「実行時エラー438 オブジェクトは、このプロパティまたはメソッドをサポートしていません。」 となります。 1回目が""ということは、 MsgBox tagValue(objIE, "name", "nametest3", "円(税込)", "innerText") の結果が""、 2回目では、黄色くなったコードの「elementName」の上にマウスをかざすと、 ツールチップで「classtest3」が入っていますが、「objDoc」の上では、 「Nothing」になります。 どこに原因があるのかわからずにいます。よろしくお願いします。 |
Message#8 2015年7月15日(水)22時56分 From: VBAマスター | 返事 削除 変更 |
> 「tagValue」を利用して特定の文書ドキュメントを抽出するサンプルコードを使い、 > 'getElementsByNameメソッドで文書ドキュメントを抽出する > Debug.Print tagValue(objIE, "id", "temp_contents", "", "innerText") > を実行させると、サブルーチンの > Set objDoc = objIE.Document.getElementById(elementName) > で止まり、objDocは「Nothing」となりました。(実行時エラー424,オブジェクトが必要です) > tagValue(objIE, "id", "temp_contents", "", "innerText") は第四引数のキーワードが設定されていないので、Nothingがでてるんでしょう。 キーワードはouterHTMLでチェックしてるので、そのままid名でもキーワードとして利用すればいけると思いますよ。 |
Message#7 2015年7月15日(水)21時39分 From: pyonko | 返事 削除 変更 |
VBAマスターのメッセージ(#6)への返事 VBAマスター様 早速ですが、methodTypeを「id」でやる場合です。 <div id=temp_contents"> <h1>見出し</h1> <ul> <li>テキスト</li> <li>テキスト</li> <li>テキスト</li> <li>テキスト</li> </ul> </div> この場合、 「tagValue」を利用して特定の文書ドキュメントを抽出するサンプルコードを使い、 'getElementsByNameメソッドで文書ドキュメントを抽出する Debug.Print tagValue(objIE, "id", "temp_contents", "", "innerText") を実行させると、サブルーチンの Set objDoc = objIE.Document.getElementById(elementName) で止まり、objDocは「Nothing」となりました。(実行時エラー424,オブジェクトが必要です) ul内のテキストがほしいのですが、この中にキーワードとなりうる単語がないのです。 かと言ってh1のテキストを使用するわけにもいかず。。。 どこを勘違いしているのでしょうか? |
Message#6 2015年7月15日(水)12時27分 From: VBAマスター | 返事 削除 変更 |
> あ!こんな便利な関数を作ってくださっていたのですね! いえ、作ってくれたのはこのサイトの管理人様ですw > idでやれそうなサイトにはidで、idがなくてもclassがあれば、さらにclassが同じのがいくつかあれば何か違っている所をみつけてキーワード、 > という感じでやっていけばいいのですね? そんな感じであっています。 > 今夜、早速取り組んでみます。また、お聞きしなくてはならないことがあるかもしれません。出来たら報告させていただきます。 > まずは、どうもありがとうございました。引き続きがんばってみます。 がんばってみてください。 |
Message#5 2015年7月15日(水)06時31分 From: pyonko | 返事 削除 変更 |
VBAマスターのメッセージ(#4)への返事 VBAマスター様 ありがとうございます。 > 極論で言えば100行あったら100ケース記述する必要があると思いますが、ちょっとこれはどうかなと思います・・・ > おしゃるとおりです!(汗) > 理想としては、tagValueサブルーチンを利用するのがスマートに記述できる方法だと思います。 あ!こんな便利な関数を作ってくださっていたのですね! idでやれそうなサイトにはidで、idがなくてもclassがあれば、さらにclassが同じのがいくつかあれば何か違っている所をみつけてキーワード、 という感じでやっていけばいいのですね? > おそらくここの「一意のキーワード」を見つけれないがために断念したと思いますが、どこかしら違うところがあるはずなので、それを見つけたほうが早いかと思います。 > > どうしても分からない場合は、以下のように個別の条件を追記すれば対応できるかと思います。 > > For i = 2 To sh2.Cells(Rows.Count, 1).End(xlUp).Row > > With sh2 > > sh1.Cells(i, 2) = tagValue(objIE, .Cells(i, "B"), .Cells(i, "C"), .Cells(i, "D"), "innerText") > > If sh1.cells(i,2) = "" then > ※個別条件のマクロを記述 > End if > > End With > > Next 今夜、早速取り組んでみます。また、お聞きしなくてはならないことがあるかもしれません。出来たら報告させていただきます。 まずは、どうもありがとうございました。引き続きがんばってみます。 |
Message#4 2015年7月15日(水)00時36分 From: VBAマスター | 返事 削除 変更 |
> スマートではないですが、とりあえずは現在動いている > Select Case構文で進めることとにします。 For i = 2 To sh2.Cells(Rows.Count, 1).End(xlUp).Row Step 1 '第一列目(A列)にURLリストがあるとします Select Case i Case 1 sh1.Cells(i, 2) = objIE.Document.body.all.tags("ul")(3).innerText Case 2 sh1.Cells(i, 2) = objIE.Document.body.all.tags("table")(3).all(61).innerText Case 3 sh1.Cells(i, 2) = objIE.Document.body.all.tags("div")(10).innerText End Select Next For Next構文ですが、上記の変数iは行番号ですよね? この変数iをSelect Case構文の条件としているということは、 1行目の場合は、objIE.Document.body.all.tags("ul")(3).innerText 2行目の場合は、objIE.Document.body.all.tags("table")(3).all(61).innerText 3行目の場合は、objIE.Document.body.all.tags("div")(10).innerText のデータを抽出しているということであってますか? 極論で言えば100行あったら100ケース記述する必要があると思いますが、ちょっとこれはどうかなと思います・・・ あと、 tags("ul")(3) tags("table")(3).all(61) tags("div")(10) も指定した要素に対して何番目の要素を抽出するかということですが、html文が変わると取得範囲も変わるのでオススメではないですね。 特に2番目の(61)はよく数えていったなと思います。 > getElementById(sh2.Cells(i, 3))はオールマイティではないことが判りました。 > classも同じclass名を持つ要素がサイトによって違っていたり、ということで > 結局諦めてしまったわけなのです。 ということですが、サイトによって違う部分を変数扱いすることで大抵は解決します。 理想としては、tagValueサブルーチンを利用するのがスマートに記述できる方法だと思います。 sh2シート A列 |B列 |C列 |D列 | URL |メソッドタイプ |タグ |一意のキーワード | For i = 2 To sh2.Cells(Rows.Count, 1).End(xlUp).Row With sh2 sh1.Cells(i, 2) = tagValue(objIE, .Cells(i, "B"), .Cells(i, "C"), .Cells(i, "D"), "innerText") End With Next おそらくここの「一意のキーワード」を見つけれないがために断念したと思いますが、どこかしら違うところがあるはずなので、それを見つけたほうが早いかと思います。 どうしても分からない場合は、以下のように個別の条件を追記すれば対応できるかと思います。 For i = 2 To sh2.Cells(Rows.Count, 1).End(xlUp).Row With sh2 sh1.Cells(i, 2) = tagValue(objIE, .Cells(i, "B"), .Cells(i, "C"), .Cells(i, "D"), "innerText") If sh1.cells(i,2) = "" then ※個別条件のマクロを記述 End if End With Next |
Message#3 2015年7月14日(火)21時13分 From: pyonko | 返事 削除 変更 |
VBAマスターのメッセージ(#2)への返事 > よく分からない部分もあったのですが > > objIE.sh2.Cells(i, 2) > > の部分がエラーがでて動作しないということでしょうか? > > sh2.Cells(i, 2)に記述されたobjIE.Document.body.all.tags("ul")(3).innerTextを利用しているということですが、こちらを当てはめたら、objIE.objIE.Document.body.all.tags("ul")(3).innerTextでobjIEオブジェクトが2つ続きます。 まずは訂正させてください。objIE.objIEとならないように、 sh1.Cells(i, 2) = sh2.Cells(i, 3) としています。この結果はエラーにはなりませんが、(当然ですが)文字列で、 objIE.Document.body.all.tags("ul")(3).innerText と出力されます。 > > 試していませんが、セルをオブジェクトに代入してもエラーが起きるだけではないでしょうか? > > サイトによって値が異なるのであれば、処理をサイト毎にわけるか、統一したデータを取得する方法を利用するほうが一般的だと思いますよ。 > > 値の取得については、以下ページが参考になりますので、こちらを見てみてはいかがですか? > > > http://www.vba-ie.net/element/tagvalue.html はい、 http://www.vba-ie.net/element/idvalue.html を参考にしていますいが、id属性は引数になるので目的に叶うのですが、 大半のWEBページにおいて、絞り込んだエリアに適当なid属性がなく、 getElementById(sh2.Cells(i, 3))はオールマイティではないことが判りました。 classも同じclass名を持つ要素がサイトによって違っていたり、ということで 結局諦めてしまったわけなのです。 > あと、セル値をオブジェクトとしてセットしてみるとうまくいくかもしれません。イメージとしては以下のような感じです。 > 試したわけではないので、参考まで。 > > > Dim objDoc As Object > > Set objDoc = osh2.Cells(i, 2) > > sh1.Cells(i, 2) = objDoc ありがとうございます。これを早速試しましたが、 sh1.Cells(i, 2) = sh2.Cells(i, 3) と同じ結果になりました。オブジェクトにならない みたいです。 javascriptでいう、eval()関数のようなものでどうかと思い、 sh1.Cells(i, 2) = Application.Evaluate(sh2.Cells(i, 3)) とやってみましたが、この行で「オブジェクトが必要です」 エラーとなりました。 Dim objDoc As IHTMLDOMNode Set objDoc = sh2.Cells(i, 3) sh1.Cells(i, 2) = objDoc を試してみようとしましたが、 「こんぱいるえらー:ユーザー定義型は定義されていません」 となりました。参照設定が足りないと思われますが、 何を参照したらよいか解らなくて。。。。 スマートではないですが、とりあえずは現在動いている Select Case構文で進めることとにします。 |
Message#2 2015年7月14日(火)16時30分 From: VBAマスター | 返事 削除 変更 |
よく分からない部分もあったのですが objIE.sh2.Cells(i, 2) の部分がエラーがでて動作しないということでしょうか? sh2.Cells(i, 2)に記述されたobjIE.Document.body.all.tags("ul")(3).innerTextを利用しているということですが、こちらを当てはめたら、objIE.objIE.Document.body.all.tags("ul")(3).innerTextでobjIEオブジェクトが2つ続きます。 試していませんが、セルをオブジェクトに代入してもエラーが起きるだけではないでしょうか? サイトによって値が異なるのであれば、処理をサイト毎にわけるか、統一したデータを取得する方法を利用するほうが一般的だと思いますよ。 値の取得については、以下ページが参考になりますので、こちらを見てみてはいかがですか? http://www.vba-ie.net/element/tagvalue.html あと、セル値をオブジェクトとしてセットしてみるとうまくいくかもしれません。イメージとしては以下のような感じです。 試したわけではないので、参考まで。 Dim objDoc As Object Set objDoc = osh2.Cells(i, 2) sh1.Cells(i, 2) = objDoc |
Message#1 2015年7月13日(月)19時37分 From: pyonko | 返事 削除 変更 |
Excelに記述したURLリストに従って、WEBページの更新有無 を定期的にチェックするVBAを作成中です。 ページごとに、着目している情報が掲載されているDOM要素 を次のような感じで予め特定しました。 Aサイト:objIE.Document.body.all.tags("ul")(3).innerText Bサイト:objIE.Document.body.all.tags("table")(3).all(61).innerText Cサイト:objIE.Document.body.all.tags("div")(10).innerText これらも、URLリストの隣の列に記述しております。 (sh2:URL,DOMを記述したSheet2とします) サイトが沢山ある場合、ループで回し、例えば For i = 2 To sh2.Cells(Rows.Count, 1).End(xlUp).Row Step 1 '第一列目(A列)にURLリストがあるとします Select Case i Case 1 sh1.Cells(i, 2) = objIE.Document.body.all.tags("ul")(3).innerText Case 2 sh1.Cells(i, 2) = objIE.Document.body.all.tags("table")(3).all(61).innerText Case 3 sh1.Cells(i, 2) = objIE.Document.body.all.tags("div")(10).innerText End Select Next などとしていますが、このように右辺に直接個々の i 毎にDOMの連なりを記述する のではループの意味がなくなってしまうので、シートのsh2.Cells(i, 2)に記述されたobjIE.Document.body.all.tags("ul")(3).innerTextを使って sh1.Cells(i, 2) = objIE.sh2.Cells(i, 2) のように記述できないでしょうか? DOM要素でなく、id属性をリストに入れているのであれば、 sh1.Cells(i, 2) = objIE.Document.body.getElementById("id名") が使えるので、 sh1.Cells(i, 2) = objIE.Document.body.getElementById(sh2.Cells(i, 2)) と、( )内に変数を渡すことが可能と思われます。「.」でつなげていく方法では、 変数にできなくて困っています。 アイデアがあれば、ぜひ教えて下さい。 |
昨日以降 2日前以降 3日前以降 4日前以降 5日前以降