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

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

ただいまの
回答率

88.32%

VB.netでIE操作中に「HRESULT からの例外」エラーで止まる

解決済

回答 3

投稿 編集

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

ot2os

score 23

いわゆるWebスクレイピングのようなことをやろうとしています。
IEウィンドウを操作して特定のWebサイト上で決まったメニュー操作を行い、表示された情報を取得する作業です。

実際に作成したコードを走らせると途中で「HRESULT からの例外」エラーが発生して処理が止まってしまいます。
このエラーへの対処法についての質問です。
エラー発生状況を以下に箇条書きします。

  • 全く同じ条件で同じコードを走らせても、エラーが出るときと出ない時がある。
  • エラーが出る箇所も毎回異なる。
  • 出るエラーも毎回異なる。
  • ただし、すべて「HRESULT からの例外:0x????????」形式のエラーで出ている(?は数字)
  • エラーが出てから再度[続行]で進めても同じエラーで先へ進めない(つまり実施タイミングの問題ではない?)

コードの一例を以下に記載します。(下記以外のコードでもエラーは出ます)

Option Explicit On

Module Module1
    Public Sub Main(ByVal targetURL As String)    '引数に対象URLを入れて実施する
        Dim objIE As Object
        objIE = CreateObject("InternetExplorer.Application")
        objIE.Visible = False     '←★ここでエラーが出る場合もある。
        objIE.navigate(targetURL)

        Do  '「次のページ」ボタンのループ
            Call IEWait(objIE)

            'ページ内の全要素検索
            For Each one_tag In objIE.document.all
                If UCase(one_tag.TagName) = UCase("a") Then
                    Debug.Print(one_tag.href)    '該当リンクアドレスを取得
                End If
            Next
        Loop While Ichiran_Tugihe(objIE)  '「次のページ」ボタンを押す

        'IE終了
        objIE.Quit
        objIE = Nothing
    End Sub


    'IEを待機する関数
    Private Sub IEWait(ByRef objIE As Object)
        Do While objIE.busy = True Or objIE.readystate <> 4
            System.Windows.Forms.Application.DoEvents()
        Loop
    End Sub

    '「次のページ」ボタンを押すスクリプト
    Private Function Ichiran_Tugihe(ByRef objIE As Object) As Boolean
        Dim i As Long
        Ichiran_Tugihe = False

            For i = 0 To objIE.document.links.length - 1    '←★追加情報:HRESULT からの例外:0x800A01B6エラーが出たりでなかったり
                If objIE.document.links(i).title = "次のページ" Then
                    Ichiran_Tugihe = True
                    objIE.document.links(i).Click   'クリック
                    Call IEWait(objIE)
                    Exit For
                End If
            Next
    End Function

End Module

●発生するエラー:
上記コードで最もよく発生するエラーは下記です。

型 'System.NotSupportedException' のハンドルされていない例外が Microsoft.VisualBasic.dll で発生しました
  追加情報:HRESULT からの例外:0x800A01B6

このエラーを控えた際はFor i = 0 To objIE.document.links.length - 1部分で発生していましたが、他の部分でも出たりでなかったりします。

上記より発生頻度は低い気がしますが、下記も出ます。

型 'System.Runtime.InteropServices.COMException' の例外が Microsoft.VisualBasic.dll で発生しましたが、ユーザー コード内ではハンドルされませんでした
  追加情報:リモート プロシージャ コールに失敗しました。 (HRESULT からの例外:0x800706BE)
これはobjIE.Visible = Falseで出ました。

●試したこと:

  • Dim objIEdoc As mshtml.HTMLDocument = DirectCast(objIE.document, mshtml.HTMLDocument)を使って、objIEに対して実施していたコマンドをobjIEdocに置き換える
    → 心なしかエラー発生率は下がった気がしますが、やはり同様のエラーが出ることがあります。

  • Form上にWebBrowserオブジェクトを配置し、objIE = Form1.WebBrowser1コードを配置する
    → WebBrowserとIEの動作仕様が違うのか、JavaScript絡みのエラーダイアログが頻発してどのサイトも正常動作せず。

  • 各プロシージャ内にTry~Catchを使って無理やりエラー回避することは一応は可能です。

Dim Retry As Boolean = True
Dim objIE As Object
objIE = CreateObject("InternetExplorer.Application")

Do While Retry = True
    Try
        '
        'ここに実施するコードを入れる。
        '
        Retry = False
    Catch ex As System.Exception
        objIE.Quit
        objIE = Nothing
        objIE = CreateObject("InternetExplorer.Application")
    End Try
Loop

開発、テスト環境:
Win10x64 1709
Internet Explorer 11
Visual Studio Community 2015


補足です。

今回、エラーコードを基に調べてみたところ「原因はわからないけどこうすれば直った」と言う旨の話が何件かあり、それを基に「●試したこと:」を実施していますが、解決していません。

前述の通り、エラー発生時にエラーをcatchしてから再度同じ処理を実施すれば今度はエラーが出ずに継続できますが、何回かに一回、全く同じ場所で同じエラーが出続けて無限ループすることがあることがわかりました。

Form側のコードを下記のようにし、メインの処理をスレッドに分けて、一定期間処理が終わらなければ無理やりスレッドごと処理を中断し、その後再開すると言う方法を試してみました。しかし、この方法で処理を再実行しても全く同じ場所で同じエラーが出て進めません。

試しに[ielowutil]プロセスも終了するようにしてみましたが、同様でした。

しかし、手動で[デバッグの停止]を実施して、再度プログラムを開始して同じURLを処理すると正常に機能します。

Option Explicit On

Public Class Form1

    Private t As New System.Threading.Thread(
            New System.Threading.ParameterizedThreadStart(AddressOf Main))

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

        LastAct = Now
        Me.Timer1.Enabled = True
        t.Start(Me.TextBox1.Text)    '入力されたURL内のリンクを調べる

    End Sub

    '一定期間応答がなければ強制的にスレッドを立ち上げなおす
    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        '10分以上応答なければ強制再実行
        If DateDiff("n", LastAct, Now) > 10 Then
            Me.Timer1.Enabled = False
            Debug.Print("10分応答なし")
            t.Abort()
            t.Join()
            KillProcess("iexplore")    'iexploreのプロセスを強制終了するコマンド
            LastAct = Now
            t = Nothing
            t = New System.Threading.Thread(
            New System.Threading.ParameterizedThreadStart(AddressOf Main))
            t.Start(Me.TextBox1.Text)
            Me.Timer1.Enabled = True
        End If
    End Sub
End Class
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • defghi1977

    2018/03/30 14:05

    こういう場合は「0x800A01B6」とか「0x800706BE」とかでググるのですよ

    キャンセル

回答 3

checkベストアンサー

+1

「Webスクレイピングのようなこと」を行いたいのであれば、
WebBrowserの方が.Netで扱いやすいし、応用が利くし、
少なくとも今回のようなエラーは見たことがありません。
注意点として、WebBrowserは何もしなければIE7で動きますが、
WebBrowserで使用するIEのバージョンを上げることができるため、
古いIEに対応しないサイトでも応用できます。

例えば、以下サイトを参考にしてみてください。
https://www.ipentec.com/document/csharp-change-webbrower-control-internet-explorer-version

その他、「WebBrowser IE バージョン 変更」などでググると、色々とヒットします。


追記:
サンプルを作成してみました。
今回作成するサンプルアプリをWBTest.exeとします。
まず、レジストリエディタでHKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATIONにWBTest.exeの情報を追加します。
(デバッグを行う際はWBTest.vshost.exeも登録します。)
レジストリエディタ

このアプリでは、Form1にWebBrowser1, Button1, Button2を配置します。
あとは、以下のようなコードを書いてみました。

Public Class Form1
    Private Sub WebBrowser1_DocumentCompleted(sender As Object, e As WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
        If e.Url = WebBrowser1.Url Then
            MsgBox("読込完了")
        End If
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        WebBrowser1.Navigate("https://dictionary.goo.ne.jp/")
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        WebBrowser1.Navigate("https://www.excite.co.jp")
    End Sub
End Class


このサンプルでは、WebBrowser1_DocumentCompletedイベントで、対象のURLの読込が終わったときにメッセージボックスを表示していますが、この時まではWebBrowserや表示ページのクリック等の操作はしない方が良いようです。
(読込途中のjsがスクリプトエラーになるかも知れない?)

とりあえず、このサンプルでスクリプトエラーは確認できませんでしたが、もしかしたら100%ではないかも知れません。
本来の目的とは無関係なスクリプトであれば、WebBrowser1のScriptErrorsSuppressedプロパティをTrueにすることが有効かも知れません。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/04/11 18:44

    元の回答にWebBrowserの使用例を追記しました。

    キャンセル

  • 2018/04/13 15:47 編集

    わざわざ検証までしていただいてありがとうございます。
    こちらでも同じことを試してみたのですが、やはりなぜかエラーが出てしまいます。

    ちなみに、
    https://www.excite.co.jp
    では「https://pagead2.googlesyndication.com/pagead/show_ads.js

    https://dictionary.goo.ne.jp
    では「https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js

    のURLのjsがエラーでした。

    しかし、Navigateの前に下記1行を入れるとエラーが出なくなりました。

    WebBrowser1.ScriptErrorsSuppressed = True

    objIEをそのままWebBrowserに入れ替えると、ところどころメソッドやプロパティが違ってうまく動かないので、調べながら引き続き検証してみます。

    キャンセル

  • 2018/04/13 18:48

    やはり、WebBrowser1.ScriptErrorsSuppressed = Trueを入れないとスクリプトエラーが出ましたか。スミマセン。
    ScriptErrorsSuppressedプロパティはスクリプトエラー等のダイアログを表示しない目的で使用するため、非表示のスクリプトエラーが原因で、本来の目的とする機能が動作しない恐れもあります。
    その場合は、もしかしたら今までのIEの外部処理での対応を検討した方がいいかも知れません。(お役に立てなくてゴメンナサイ。)

    キャンセル

0

IEを外部から操作する処理はSeleniumのIE用のWebDriverが参考になります。
安定して動作させるにはいくつか注意点があるので、同じことを実施してみてはどうでしょうか?
ページ遷移をする場合は、保護モードの設定を統一しないと別プロセスが生成される場合があるので重要です。

参考リンク
Required Configuration
(2)IEの設定

あと気になる点は

  • Mainに<STAThread>がない
  • System.Windows.Forms.Application.DoEvents()は普通のSleepだと問題あるのか?

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/04/10 14:28

    ありがとうございます。
    下記2点試してみましたが、やはり状況変わりませんでした。

    ・<STAThread>の追記
    ・DoEvents()をSleep(200)に変更

    追記部分では回避策としてMainの処理をスレッドにして走らせ、一定時間処理が進まなければ無理やりAbortで処理を中断するようにしています。
    (処理が成功するたびにLastAct変数に現在時刻を書き込んでいます)
    再度Mainの処理がStartされた際に同じエラーで進まないのに、手動でデバッグを終了して再度同じURLを指定して開始するとなぜか正常に進みます。

    スレッドをAbort、再Startする処理とどこが違うのかよくわからず。
    見る限り、Start後の処理もちゃんとMainの最初から走っているように見えます。

    この処理がうまく行けばひとまずの回避はできそうですが、別途Seleniumも検討してみます。

    キャンセル

  • 2018/04/12 20:20

    私が重要だと思ったのはRequired Configurationのリンク先に記載されたのIEの設定です。
    例えば、IEはマルチプロセスで動作するため、同一Window内でのページ遷移の場合でも別プロセスとなる可能性があります。そうなると正しく操作できません。
    保護モードの設定をすべて統一することでそれを抑止することが出来ます。
    そんな感じでいろいろとノウハウがあるのでリンク先の説明を見てIEの設定を変更しないとまともに動きません。

    キャンセル

  • 2018/04/18 11:55

    ありがとうございます。
    今いろいろな条件で検証中ですが、資料に従ってIEのすべてのゾーンで保護モードを統一したところ、エラーの発生率はだいぶと下がった気がします。(同様のエラー自体は発生します)
    引き続きいろいろ検証してみます。

    キャンセル

0

そもそも論になりますが、スクレイピングに依存したシステム自体、不完全と気付くべきですね。
相手のシステムに変更があれば動かなくなるんですから。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

同じタグがついた質問を見る