tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトルDo Until objIE.Busy = Falseが効いていない?
記事No15033
投稿日: 2010/11/09(Tue) 10:19
投稿者ガッツ
VB6+XP+IE7です。

IEを起動してテキストボックスに値を入れて検索ボタンをクリックし、
ソースを取得するというプログラムを作成していますが、
ソースを取得する部分でたまに以下のエラーが出ます。
出ないときもあります。

「実行時エラー '91'
オブジェクト変数またはWithブロック変数が設定されていません。」

Do Until objIE.Busy = Falseの判定が効いてないのでしょうか。
Do 〜 Loop の中にDebug.Printを入れて確認したのですが、
1〜3回程度入っているようです。

本来は以下のページのように
http://www.happy2-island.com/vbs/cafe02/capter00710.shtml
フォームの操作を行いたいのですが、
今回やりたいページ(http://phonebook.excite.co.jp)ではフォームがないので、
以下のソースのようにキーボードを操作する関数を使用しています。

ソース
    'objIEオブジェクトを作成します
    Set objIE = CreateObject("InternetExplorer.Application")
    
    'ウィンドウの大きさを変更します
    objIE.Width = 800
    objIE.Height = 600
    
    '表示位置を変更します
    objIE.Left = 0
    objIE.Top = 0
    
    'インターネットエクスプローラ画面を表示します
    objIE.Visible = True
    
    '指定したURLを表示します
    objIE.Navigate "http://phonebook.excite.co.jp"

    'ページの読み込みが終わるまでココでグルグル回る ←ここはOK
    Do Until objIE.Busy = False
       '空ループだと無駄にCPUを使うので1000ミリ秒のインターバルを置く
       Sleep 500
    Loop '

    'テキストファイルから検索文字を取得し、検索
    Do While Not EOF(FN1)
      '検索文字の取得処理

      '前回入力文字の削除
       Call sSetSendKeys(vbKeyControl, vbKeyA)
       Sleep 250
       Call sSetSendKeys(vbKeyDelete)
       Sleep 250
                    
       'IEの検索BOXに電話番号をセット
       Call sSetSendTxts(strTelNo)
                    
       '検索ボタンクリック
       Call sSetSendKeys(vbKeyReturn)

       'ページの読み込みが終わるまでココでグルグル回る
       '中にDebug.Printを入れて確認したが、何回かこの中に入っているのを確認
       Do Until objIE.Busy = False
           Sleep 500
       Loop

      'HTMLソースを取出す
       strHTML = objIE.Document.body.innerHTML  'ここでたまに上記エラー

      '取得したソースから欲しい情報を取得してファイルに出力処理
    Loop
    Close #FN1


'キーボード操作
'==================================================================
'キーストロークをシミュレートする(P1065)
Public Declare Sub keybd_event Lib "user32.dll" _
   (ByVal bVk As Byte, ByVal bScan As Byte, _
    ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
Public Const KEYEVENTF_KEYUP = &H2         'キーアップ
Public Const KEYEVENTF_EXTENDEDKEY = &H1   'スキャンコードは拡張コード
'仮想キーコード・ASCII値・スキャンコード間でコードを変換する(P1067)
Public Declare Function MapVirtualKey Lib "user32" _
    Alias "MapVirtualKeyA" (ByVal wCode As Long, _
    ByVal wMapType As Long) As Long
'==================================================================
'システムを立ち上げてからの経過時間を高精度に取得する(P1002)
Public Declare Function timeGetTime Lib "winmm.dll" () As Long


Public Sub sSetSendKeys(bVk1 As Long, _
                Optional bVk2 As Long = 0, Optional bVk3 As Long = 0)
'SendKeys と同様にアクティブウィンドウにキーストロークを送る
'以下のパターンは必要により追加して下さい。
    If bVk2 = 0& And bVk3 = 0& Then
    'キーを1個だけ送る
        Call keybd_event(CByte(bVk1), MapVirtualKey(CByte(bVk1), 0), _
                        KEYEVENTF_EXTENDEDKEY Or 0, 0)
            Call keybd_event(CByte(bVk1), MapVirtualKey(CByte(bVk1), 0), _
                        KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0)
    ElseIf bVk3 = 0& Then
    'キーの複合操作 [Alt] + [E] 等
        Call keybd_event(CByte(bVk1), MapVirtualKey(CByte(bVk1), 0), _
                        KEYEVENTF_EXTENDEDKEY Or 0, 0)
            Call keybd_event(CByte(bVk2), MapVirtualKey(CByte(bVk2), 0), _
                        KEYEVENTF_EXTENDEDKEY Or 0, 0)
            Call keybd_event(CByte(bVk2), MapVirtualKey(CByte(bVk2), 0), _
                        KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0)
        Call keybd_event(CByte(bVk1), MapVirtualKey(CByte(bVk1), 0), _
                        KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0)
    ElseIf (bVk1 <> 0&) And (bVk2 <> 0&) And (bVk3 <> 0&) Then
    'SendKeys "%(EA)" と同様の操作
        Call keybd_event(CByte(bVk1), MapVirtualKey(CByte(bVk1), 0), _
                        KEYEVENTF_EXTENDEDKEY Or 0, 0)
        Call keybd_event(CByte(bVk2), MapVirtualKey(CByte(bVk2), 0), _
                        KEYEVENTF_EXTENDEDKEY Or 0, 0)
        Call keybd_event(CByte(bVk2), MapVirtualKey(CByte(bVk2), 0), _
                        KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0)
        Call keybd_event(CByte(bVk3), MapVirtualKey(CByte(bVk3), 0), _
                        KEYEVENTF_EXTENDEDKEY Or 0, 0)
        Call keybd_event(CByte(bVk3), MapVirtualKey(CByte(bVk3), 0), _
                        KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0)
        Call keybd_event(CByte(bVk1), MapVirtualKey(CByte(bVk1), 0), _
                        KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0)
    End If
    StopTime (50)     '連続処理した場合を考慮
End Sub


Public Sub sSetSendTxts(MyString As String)
'SendKeys と同様にデータ(文字列)をアクティブウィンドウに送ります。
    'クリップボードを初期化
    Clipboard.Clear
    StopTime (10)
    '選択した範囲のテキストをコピー
    Clipboard.SetText MyString
    StopTime (10)
    Call sSetSendKeys(vbKeyControl, vbKeyV) '貼り付け
    StopTime (10)
End Sub

[ツリー表示へ]
タイトルRe: Do Until objIE.Busy = Falseが効いていない?
記事No15034
投稿日: 2010/11/09(Tue) 10:39
投稿者花ちゃん
>     'ページの読み込みが終わるまでココでグルグル回る ←ここはOK
>     Do Until objIE.Busy = False
>        '空ループだと無駄にCPUを使うので1000ミリ秒のインターバルを置く
>        Sleep 500
>     Loop '

このコードで確認はしていませんが、上記では完全に表示されてから次のステップに
進んでいるとは言えません、特に2回目以降のアクセス等は。

VBはイベント駆動型の言語なので、ループで待機させるのではなく、Documentプロパティ
への読み込み完了なら、DocumentComplete イベントを利用するようにとあちこちの
掲示板で魔界の仮面弁士さんが解説されています。
http://homepage1.nifty.com/MADIA/vb/vb_bbs2/200510/200510_05100089.html

当サイトでの使用例(サンプル投稿用掲示板でカテゴリ別で参照願います。)
 http://hanatyan.sakura.ne.jp/patio/read.cgi?no=176

又、Sleep や DoEvents() 等も無闇に使用すると予期せぬトラベルの元になるので
使用を控えるような書き込みが最近では多く目に付きます。
特に今回のように Sleep を単独で使用されるとその間メッセージ等の処理を含む一切の
処理がなされないので、十分注意して下さい。

--------------------------------------------------------------------------------
ちょっと便利な検索ソフト(http://hanatyan.sakura.ne.jp/yybbs/read.cgi?no=117)
を使って、キーワード【DocumentComplete 魔界の仮面弁士】での検索結果(当サイト内・外の検索でも同じ)

  ヒット件数    検索対象サイト名    検索結果のURL(短く変換しています)
            234 件  ■ウェブ全体から検索       http://tinyurl.com/2dposug
             39 件  わんくま同盟               http://tinyurl.com/293xmw6
             35 件  Programing Library         http://tinyurl.com/2bpt3co
             27 件  ★VBレスキュー(花ちゃん)   http://tinyurl.com/2g7lmdp
             23 件  DOBON.NET                  http://tinyurl.com/2dvv42n
              0 件  Visual Basic 中学校        http://www.google.co.jp/webhp?hl=ja
              0 件  WinAPI Database for VB...  http://www.google.co.jp/webhp?hl=ja
              0 件  moug モーグ                http://www.google.co.jp/webhp?hl=ja
              0 件  ●msdn.microsoft.com/      http://www.google.co.jp/webhp?hl=ja
              0 件  pin's Laboratory           http://www.google.co.jp/webhp?hl=ja
              0 件  Visual Basic Station       http://www.google.co.jp/webhp?hl=ja
              0 件  アットマーク・アイティ     http://www.google.co.jp/webhp?hl=ja
              0 件  C# と VB.NET の入門サイト  http://www.google.co.jp/webhp?hl=ja
              0 件  HIRO's.NET                 http://www.google.co.jp/webhp?hl=ja
--------------------------------------------------------------------------------

[ツリー表示へ]
タイトルRe^2: Do Until objIE.Busy = Falseが効いていない?
記事No15035
投稿日: 2010/11/09(Tue) 11:41
投稿者ガッツ
花ちゃんさん

いつも活用させていただいています。返信ありがとうございます。
DocumentComplete イベントを利用することはわかりました。
今はこれらを使用して連続で検索する処理にしようとしています。

Yahooログインのサンプルソースで質問なのですが、
以下のIf CStr(URL) <> myURL Then
の部分はログイン後の画面が表示されたときにDocumentCompleteの
イベントが発生して入る部分だと思いますが、これが2回発生しているようです。
これは何故かお分かりでしょうか。
下記で言うと、

ログイン前
ログイン後
ログイン後

とイミディエイトウインドウに表示されます。

以上よろしくお願いします。


Private Sub IE_DocumentComplete(ByVal pDisp As Object, URL As Variant)
   If CStr(URL) <> myURL Then
      Debug.Print "ログイン後"
      Exit Sub
   End If
   With IE
      Debug.Print "ログイン前"
      .Document.Forms(0).Elements("login").Value = "ログイン用IDを記入"
      .Document.Forms(0).Elements("passwd").Value = "パスワードを記入"
      'IDとパスワードを記憶用のチェックボックスにチェックを入れる
              If .Document.Forms(0).Elements(".persistent").Checked = False Then
                  .Document.Forms(0).Elements(".persistent").Click
              End If
      'ログインボタンをクリック
      .Document.Forms(0).submit
   End With
End Sub

[ツリー表示へ]
タイトルRe^3: Do Until objIE.Busy = Falseが効いていない?
記事No15036
投稿日: 2010/11/09(Tue) 12:47
投稿者花ちゃん
> イベントが発生して入る部分だと思いますが、これが2回発生しているようです。
> これは何故かお分かりでしょうか。

>    If CStr(URL) <> myURL Then
>       Debug.Print "ログイン後"
>       Exit Sub
>    End If

Debug.Print で調べるなら、なぜ、どのような URL が表示されているのか調べないのですか?

Debug.Print "ログイン後", TypeName(pDisp), URL

指定した URL が、 http://hanatyan.sakura.ne.jp/index.html のような場合、表示される
URL は フレームのページを使っているので、4個になります。

[ツリー表示へ]
タイトルRe^4: Do Until objIE.Busy = Falseが効いていない?
記事No15037
投稿日: 2010/11/09(Tue) 13:08
投稿者ガッツ
> Debug.Print "ログイン後", TypeName(pDisp), URL
>
> 指定した URL が、 http://hanatyan.sakura.ne.jp/index.html のような場合、表示される
> URL は フレームのページを使っているので、4個になります。

ありがとうございました。
今後はDocumentCompleteを使用するようにします。

[ツリー表示へ]