質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.21%

ExcelVBAでIE操作中にIEオブジェクトがクライアントから切断される?

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 9,140

dam9806

score 17

以下のコードは、あるWebサイトについて3パターンでページをロードするExcelVBAの処理です。

#If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr)
#Else
Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
#End If

Private Sub driver_getKatsuki()
    Dim ret
    Dim objIE As InternetExplorer

    ' IEの起動
    Set objIE = CreateObject("InternetExplorer.Application")
    objIE.Visible = True

    'パターン1
    ret = getKatsuki("9784344033856", objIE)
    Debug.Print "戻り値=[" & ret & "]"

    'パターン2
    ret = getKatsuki("9784897481159", objIE)
    Debug.Print "戻り値=[" & ret & "]"

    'パターン3
    ret = getKatsuki("4866510553", objIE)
    Debug.Print "戻り値=[" & ret & "]"

    objIE.quit
    Set objIE = Nothing
End Sub

Function getKatsuki(searchKey As String, objIE As InternetExplorer)
    Dim url
    On Error GoTo Err

    url = "http://www.katsuki-books.jp/kensaku/detail.asp?Cd=" & searchKey
    objIE.Navigate2 url
    ' ★ロード待ち
    Do While objIE.Busy = True Or objIE.readyState <> 4
        DoEvents
        Sleep (1000) '1秒待機
    Loop
    Debug.Print objIE.LocationURL

    getKatsuki = 1
    Exit Function
Err:
    Debug.Print "Err.Number=[" & Err.Number & "], Err.Description=[" & Err.Description & "]"
    getKatsuki = -1
End Function


これを実行するとパターン1までは正常に動作しますが、パターン2のページロードでビジー状態が継続し、「★ロード待ち」とコメントしているループ処理を脱出しません。(IEを見るとロードは完了しているように見えるのですが・・・)

また、何度か実行していると、「'Navigate2' メソッドは失敗しました: 'IWebBrowser2' オブジェクト」のエラーメッセージを吐くこともあります。

上記コードは最小限の処理のみ記述したものです。実際にはデータ取得する処理等あるのですが、その実行時に「起動されたオブジェクトはクライアントから切断されました。」のエラーが出たこともあります。私は、上のエラーもクライアントから切断されたものと予想しています。

一方で、デバッグでステップ実行すると、最後まで問題なく処理できます。

サイト側で何か制限をかけているのかな・・・と勘ぐったりもしますが分かりません。
原因・対策など教えていただけないでしょうか。

実行環境:Windows7、Excel2016

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

check解決した方法

0

objIE.Visible をTrueからFalseに変えたところ、正常に処理できるようになりました。
複数回実行してもエラーにならないので、恐らくこれで大丈夫かと思います。
回答してくださった方、ありがとうございました!

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/01/26 13:15

    私もまったく同じ問題にぶちあたり、ここにたどり着きました。
    しかし、原因については、いまだにわからずにいます。
    デバッグする際は、IEの画面を見ながらテストしたいので、
    Trueのままでも、切断されずに正常に動作させるには、どうしたらいいんでしょうね?

    キャンセル

  • 2019/01/27 09:45

    質問主です。
    私の質問に対する回答者との過去のやりとりをお読みになり、回答者の提示した処方をお試し下さい。
    回答者から色々アドバイスを頂きました。例えば、DoEventsを所々に挿入するなどです。

    キャンセル

0

Sleep の直後に DoEvents 使ってもダメ?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/12/06 12:43

    これも経験則ですが、getElementsByXXX 等、IEにアクセスする回数が多いと、
    たまに失敗することがあったと思います。

    なので、自分は、getElementsByXXX 等用に関数を作り、
    10回トライし、トライ毎に待ち時間を長くして対応したように思います。

    メソッドチェーンは書くのは楽ですが、
    処理が込み入ってくると安全ではないので、
    1回づつに分けた方が無難だと思います。

    キャンセル

  • 2018/12/06 14:21

    ありがとうございます。
    対応に時間かかりそうですが、メソッドを分割して試してみたいと思います。

    キャンセル

  • 2018/12/06 20:22

    objIE.Visible をTrueからFalseに変えたところ、正常に処理できるようになりました。
    複数回実行してもエラーにならないので、恐らくこれで大丈夫かと思います。
    メモリ等のリソース関係で何か問題が出ていたのかもしれません。

    DoEventsを所々に挟むというのは、OSに制御渡すことで擬似的にステップ実行している状況に近づけていたのだと思います。とても勉強になりました。
    お付き合いくださり、ありがとうございました!

    キャンセル

0

IE表示待ちでしつこくステータスを確認してはどうでしょうか。

Function ie_wait(objIE As Object) As Boolean
    Dim timeout As Date
    Dim cnt As Integer

    '読み込み中なら以下を繰り返す
    cnt = 0
    timeout = DateAdd("s", 50, Now())
    Do
        '下記ステータス30回一致
        If objIE.Busy = False And objIE.readyState = 4 Then
            DoEvents
            Sleep 100
            DoEvents
            cnt = cnt + 1
            If cnt > 30 Then
                Exit Do
            End If
        Else
            cnt = 0
        End If

        'タイムアウトチェック
        If timeout < Now() Then
            ie_wait = False
              Exit Function
        End If
        DoEvents
    Loop

    ie_wait = True
End Function

また、Sleep関数は 64bitでもLongで渡します。
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As Long)

<追記>
私が普段使っているIE表示待ちも試してみてください。
これでダメならお役に立てそうにありません。

Public Sub Myloop(ByRef ie As Object)

    Dim nowURL As String
    nowURL = ie.LocationURL

    Dim IEretry   As Boolean: IEretry = False
    Dim RepeatSec As Single:  RepeatSec = Timer

On Error GoTo INVALID

    Do While ie.Busy = True Or ie.readyState < 4 'READYSTATE_COMPLETE
        DoEvents: Sleep 200 '200ms停止

        If (Timer - RepeatSec) > 80 Then
            Debug.Print ie.readyState
            MsgBox "サーバーが応答していません。インターネット接続をご確認後、再度実行してください。"
            ie.Quit
            End
        ElseIf (Timer - RepeatSec) > 40 And IEretry = False Then
            'IEの再読み込みは1回限りとする
            IEretry = True
            On Error Resume Next
            ie.Refresh
            Debug.Print "ie.Refresh/エラー番号:" & Err.Number & vbNewLine & "エラーの種類:" & Err.Description
            On Error GoTo INVALID
        End If
    Loop

    DoEvents

    Do While ie.document.readyState <> "complete"
        DoEvents: Sleep 200 '200ms停止

        If (Timer - RepeatSec) > 100 Then
            Debug.Print ie.document.readyState
            ie.Quit
            MsgBox "ドキュメントを取得できません。インターネット接続をご確認後、再度実行してください。"
            End
        End If
    Loop

    '念のため確認
    DoEvents: Sleep 1: DoEvents
    If ie.Busy = True Or ie.readyState < 4 Then
        Call Myloop(ie)  '再帰呼出
    End If

    Exit Sub

INVALID:

    Debug.Print "エラー番号:" & Err.Number & vbNewLine & "エラーの種類:" & Err.Description

    If Err.Number = 70 Then
        '実行時エラー「書き込みできません。」(70)は想定内なので無視。
        On Error GoTo 0
        MsgBox "IE読み込み時にエラー発生。処理を継続します。"

    ElseIf Err.Number = -2147417848 Then
        On Error GoTo 0
        '新規IEオブジェクト作成
        Dim getIE As Object
        Set getIE = CreateObject("InternetExplorer.Application")
        getIE.Visible = True
        getIE.navigate nowURL 'URL指定

        MsgBox "対象IEが存在しないため、IEを起動します。"
        Set ie = getIE
        getIE = Nothing

    Else
        '上記以外はエラーを発生させる。
        Err.Raise Err.Number
    End If
End Sub

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/12/06 14:19

    お気遣い、ありがとうございます。
    連続実行は控えます。

    キャンセル

  • 2018/12/06 20:21

    objIE.Visible をTrueからFalseに変えたところ、正常に処理できるようになりました。
    複数回実行してもエラーにならないので、恐らくこれで大丈夫かと思います。
    メモリ等のリソース関係で何か問題が出ていたのかもしれません。

    キャッシュを使わないURLの作成方法や、具体的なコードまで提示していただき、とても勉強になりました。
    お付き合いくださり、ありがとうございました!

    キャンセル

  • 2018/12/06 21:42

    直接お役に立てませんでしたが、解決してよかったですね。
    別の下記質問で私が回答した objIE.Visible = False が有効なケースがあることがわかり、うれしいです。
    https://teratail.com/questions/102572

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.21%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる