Excel (VBA)

Excel VBAに関するフォーラムです。
  • 掲示板への投稿には会員登録(無料)が必要です。会員登録がまだの方はこちら
  • 掲示板ご利用上のお願い」に反するご記入はご遠慮ください。
  • Q&A掲示板の使い方はこちらをご覧ください
トピックに返信
質問

 
(Windows 10 Pro : Excel 2016)
IEの要素の取得
投稿日時: 19/09/07 07:41:02
投稿者: kumatti
投稿者のウェブサイトに移動

こんにちは。
 昨今のスクリプト多めのページとして、例に"みずほ銀行の宝くじのサイト"を挙げましたが、
DocumentCompleteイベント相当の待ちを行っているにも関わらず、要素を取得できません。
  
> Sleep 5000&
十分な時間を待てば、その限りではありませんが、なんとなく気に入りません。
  
また、本来は"Webブラウザ"を必要とするものでもなく、「curl」で可能な類です。
https://www.runserver.jp/blog/%E5%AE%9D%E3%81%8F%E3%81%98%E3%80%81%E3%83%AD%E3%83%886%E3%81%AA%E3%81%A9%E3%81%AE%E7%B5%90%E6%9E%9C%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/
   
取り立てて困ってるわけでもなく、「こうしたらどう?」みたいなアイデアがありましたら、お聞かせ頂きますと幸甚です。

Option Explicit
'標準モジュール

Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Public ie As Object
Public flg As Boolean
Public cls1 As Class1

Private Sub Main()

    Set ie = CreateObject("InternetExplorer.application")
    ie.Visible = True

    Set cls1 = New Class1

    ie.navigate "https://www.mizuhobank.co.jp/retail/takarakuji/loto/loto6/index.html"

    While ie.Busy
        Sleep 1&
    Wend
    
    
    ie.document.addEventListener "load", cls1, True
    
    While Not flg
        DoEvents
    Wend
    'Sleep 5000&
    Debug.Print ie.document.getElementsByClassName("alnCenter extension")(0).innertext


End Sub

 
Option Explicit
'クラスモジュール

Sub hoge()
Attribute hoge.VB_UserMemId = &H0

    If ie.document.readyState = "complete" Then
        ie.document.removeEventListener cls1, "load", True
        flg = true
        Exit Sub
    End If

End Sub

回答
投稿日時: 19/09/07 14:04:28
投稿者: 半平太

提示されたコードでテストしようとしたのですが、
こんなエラーメッセージが出て、先に進めませんでした。
  ↓
>プロパティまたはメソッドの呼び出しの場合には、
>引数または戻り値としてプライベート オブジェクトへの
>参照を含めることができません。
 
問題は、読み込み完了したか、どう判定するかですよね?
 
一般にはこんなので誤魔化していますが、
      ↓
> Do While ie.Busy = True Or ie.readyState <> 4
> DoEvents
> Loop
 
現実には、この関門をすり抜けてくるケースがあるので、あるサイトでは
Completeイベントで処理すると言うアイデアを(自信たっぷりに)提示しています。
 
しかしながら、それでも解決にならないケースもあるようです。
多分、Completeイベントは1ページの読み込みで数回発生することもある為でしょう。
 
必要条件であっても十分条件ではない。
 
そうなると、ある回答者が言っていたのですが、
「ありとあらゆる手掛かりを利用して判断する」しかないのかな・・と私は諦めています。
 
つまり、特定のページ毎に、読み込み完了が判断できる情報はないか、解析する。
特定のページ毎なので、汎用的な解法にはなり得ませんし、泥臭い方法です。
 
今回の事例だと、まず私は
 Set Temp = ie.document.getElementsByClassName("alnCenter extension")
 If Not(Temp is Nothing) then
でいいのではないかと思ったのですが、それではダメだったので更に
 
 If Temp(0) <> "" then
としてみましたら、とりあえず結果は得られました。
 
※本当に取得すべきデータが「""」でいい場合は無限ループに陥ります。
 
<ご参考まで>

Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Public ie As Object

Private Sub Main2()
    Dim Temp, mayEscape As Boolean
    
    Set ie = CreateObject("InternetExplorer.application")
    ie.Visible = True
    
    ie.navigate "https://www.mizuhobank.co.jp/retail/takarakuji/loto/loto6/index.html"
    
    Do While ie.Busy = True Or ie.readyState <> 4
        DoEvents
    Loop

    'Sleep 5000&
    Do Until mayEscape
        Sleep 10&
        Set Temp = ie.document.getElementsByClassName("alnCenter extension")
        If Not (Temp Is Nothing) Then
            If Not Temp(0).innerText = "" Then
                Debug.Print Temp(0).innerText
                mayEscape = True
            End If
        End If
    Loop
End Sub

投稿日時: 19/09/07 18:59:28
投稿者: kumatti
投稿者のウェブサイトに移動

半平太さん、回答ありがとうざいます。

提示されたコードでテストしようとしたのですが、
こんなエラーメッセージが出て、先に進めませんでした。
  ↓
>プロパティまたはメソッドの呼び出しの場合には、
>引数または戻り値としてプライベート オブジェクトへの
>参照を含めることができません。

プロパティウィンドウで、「Public」に変更されてください。
 
載せられたコードで動作確認できました。
要素が取得できるまで都度、ループするのがベストかな、と。

投稿日時: 19/09/07 19:23:42
投稿者: kumatti
投稿者のウェブサイトに移動

>ie.document.removeEventListener cls1, "load", True
ie.document.removeEventListener Nothing, "load", True
に変更してください。

回答
投稿日時: 19/09/07 20:25:59
投稿者: 半平太

>プロパティウィンドウで、「Public」に変更されてください。
 
変更してみた所、上述エラーは出なくなりました。ありがとうございます。
 
私はEvent発生ベースでも旨く行かないという立場なので
あれこれ弄る意欲に乏しく、取り敢えず、ROMにさせてください。m(__)m

トピックに返信