web-dev-qa-db-ja.com

VBA Internet Explorerは、Webページが読み込まれるのを待ちます

私はこのような質問が以前に尋ねられたことを知っていますが、私のものは少し異なり、かなり厄介です。私が扱っているのは、入力ボックスの特定の項目が入力されたときにページのより多くをロードするいくつかのイベントを含むフォームを備えたWebページです。これらのイベントが発生すると、ページが再度読み込まれますが、同じURLで同じnamepropのままになります。私は次のタイプのメソッドを別々に使用し、ページが読み込まれるのを待つために一緒につなぎ合わせましたが、VBAが実行を継続し、HTMLDocument変数をページに設定しても、適切な情報がなくてもマクロが発生することがありますデバッグします。これが私がこれまで試してきた種類のことです:

While IE.Busy
    DoEvents
Wend

Do Until IE.statusText = "Done"
    DoEvents
Loop

Do Until IE.readyState = 4
    DoEvents
Loop

これらのイベントを次のようなループに配置しようとしましたが、lastModifiedプロパティが値を秒まで返すだけで、マクロが新しいフィールドを返すのに十分な速度でフィールドをスピンするため、うまくいきませんでした。同じ秒のページ:

Do Until IE.statusText = "Done" And IE.Busy = False And IE.ReadyState = 4 _
And IE.document.lastModified > LastModified ----or---- IE.document.nameprop = _
"some known and expected name prop here"
    While IE.Busy
        DoEvents
    Wend
    Do Until IE.statusText = "Done"
        DoEvents
    Loop
    Do Until IE.readyState = 4
        DoEvents
    Loop
Loop

それでも、デバッグにつながるHTMLDocumentオブジェクトを設定するのに十分な時間待機することはできません。次の入力要素を設定し、コードを進めるために何もチェックしないことを検討しましたが、通常、入力要素はHTMLに存在しますが、適切なイベントが発生するまで非表示になるため、100%成功することはありません。 、これは問題にはなりませんが、イベントが発生するまで、可能な選択をロードしません。奇妙なページかもしれません。

とにかく...他に何を追加するかわからない。見るのに役立つかもしれない何か他のものがあれば、ただ尋ねてください。私が探しているのは、VBAをIEが別のページが途中にないことを認識するまで待機させる方法だと思います。完全に完了する前に、数回読み込まれるようです。

だから...誰かアイデアはありますか?

編集:試すべきいくつかの新しいことを見つけました。それでも、サイコロはありません。これらの試みを追加することが提案されました。これがコードです。select要素のオプションを設定する必要があるイベントを発生させた後、このアプローチを使用すると、何らかの理由でVBEとExcelインスタンスが応答しなくなります... xmlの試行を考えています...コードは次のとおりです。

intCounter = 0
Do until intCounter > 2
    Do Until IE.Busy = False: DoEvents: Loop
    Do Until IE.ReadyState = 4: DoEvents: Loop
    Set HTMLDoc = IE.Document
    Do Until HTMLDoc.ReadyState = "complete"
    Set HTMLSelect = HTMLDoc.getElementById("ctl00$ctl00$MainContent$ChildMainContent$ddlEmployeeBranchCodes")
    intCounter = 0
    For each Opt in HTMLSelect
        intCounter = intCounter + 1
    Next Opt
Loop

Webページで何が起こっているかを見ると、VBEとExcelが応答しなくなるのはこのループのどこかにあることがわかります。

それが役に立てば幸い...私はそれが私を助けなかったことを知っています...ドラッツ。

編集:私がこれを追加すると思っただけです。 Webページの自動化に関しては、ほとんどの場合、IEを使用していません。私はそれがはるかに優れていることを発見し、単に投稿を実行して自分自身を取得するために、非同期のもののこの問題を完全に回避します。何をしようとしているのかによっては最善の解決策ではないかもしれませんが、トラフィックを注意深く観察し、物事を適切にパラメータ化すれば、かなり確実に機能します。

7
MattB

徹底的な検索の結果、AJAXリクエスト、バックグラウンドで非同期に実行されるjavascriptコードは、何らかの方法でシグナルを取得できるものではないと判断しました。トリガーされているようです。ページの読み込みが終了したときのイベント。これは、将来検討したいオプションです。ただし、私の目的では、ページのフォームに入力するためにすでに使用していたのと同じコードを使用しただけです。送信ボタンをクリックする前に、各フィールドを再度ループして値がまだ正しいかどうかを確認します。これは理想的な解決策ではありませんが、この場合は問題を解決したように見える回避策です。

私の解決策がこの問題を扱っている他の誰かに適用できるかどうかはわかりませんが、それが役立つかどうかはわかります。この問題の回避策は、問題のアプリケーションとWebページに基づいている必要があると思います。

7
MattB

私が知っている古い質問ですが、これは私があまり見たことがない良い答えだと思います...


私は 同様の問題 ;グーグル画像検索のすべての画像が読み込まれるのを待っています(画像の読み込みはAJAXとユーザーがページをスクロールすることによって促されるため、注意が必要です)。コメントで示唆されているように。 私の解決策 特定の要素がビューポートに表示されるのを待つことでした(これはモニター画面より少し大きい領域であり、として扱われます実際に「見る」ことができるもの)。

これは、getBoundingClientRectメソッドで実現されます

Dim myDiv As HTMLDivElement: Set myDiv = currPage.getElementById("fbar") 
'myDiv should some element in the page which will only be visible once everything else is loaded
Dim elemRect As IHTMLRect: Set elemRect = myDiv.getBoundingClientRect
Do Until elemRect.bottom > 0 'If the element is not in the viewport, then this returns 0
    DoEvents
    'Now run the code that triggers the Ajax requests
    'For me that was simply scrolling down by a big number
    Set elemRect = myDiv.getBoundingClientRect
Loop
myDiv.ScrollIntoView

リンクされた回答でこれがどのように機能するかを詳細に説明しますが、要素がビューポートに入るまで、基本的にBoundingClientRect.bottomは0に等しくなります。

要素はすぐに読み込まれるものです(ページのフレーム/テンプレートなど)。ただし、すべてのコンテンツが読み込まれるまで実際には表示されません。これは、下部にあるためです。

その要素が実際にロードされる最後のものである場合(私のグーグル検索ではそれは Show More Results ボタン)、次にロードされたときにビューポートに入る限り、ページにいつ表示されるかを検出できるはずです。次に、.bottomはゼロ以外の値を返します(ページ上の要素の実際の位置と関係があります-私は自分の目的のために本当に気にしませんでした)。最後に.ScrollIntoViewで終わりますが、それは必須ではありません。

1
Greedo

私のウェブページでも同じ問題が発生しました。

最初のオプションは

While Ie.**document**.readystate="complete"
DoEvents
Wend

ボタンをクリックした後、または別のボックスで起動した後にオプションがロードされたボックスはほとんどありませんでした...私はこのようなコードを配置しました。

Do Until IE.document.getelementbyid("Next box").Lenght>0
DoEvents
Loop
Application.wait Now+Timevalue("00:00:02)
1
Deepak