【VBScript(WSH)】エラーの回避方法『オブジェクトがありません』
【VBScript(WSH)】エラーの回避方法『オブジェクトがありません』
VBSでスクレイピング組んでれば必ず遭遇するであろうエラー『オブジェクトがありません』
コード:800A01A8
ソース:Microsoft VBScript 実行時エラー
いやいや、存在するかしないかで場合分けしたいんだって!
存在してればレコードはあるから取得して、存在してなかったらスキップしたいのよ。
と思っていても意図した動きになったりならなかったり。
と言う事で、ここら辺まとめてみます。
意図した動きをさせるためのチェックポイント
動的サイト内に下のようなHTMLがあったとします。
#レコードがある時
<div class="listbase">
<div class="hogelist">
<ol>
<li>○○○</li>
<li>▲▲▲</li>
</ol>
</div>
</div>
さて、検索したらレコード件数がゼロ。その時、動的サイトは大別すると下の3パターンになっていると思います。
■タイプ1:一部のタグ(olとかtableなど)を残して値が消えている
<div class="listbase">
<div class="hogelist">
<ol></ol>
</div>
</div>
■タイプ2:レコード情報が(olとかtableなどの)タグごと消えている
<div class="listbase"> <div class="hogelist"> </div> </div>
■タイプ3:無いよと言う値が挿入されている
<div class="listbase"> <div class="searchNonItems">データは存在しません</div> </div>
スクレイピングの際はこの中のどのパターンかを把握しておきます。
タイプに合わない形で分岐を書いていると「オブジェクトが無い」と怒られます。
どうすればいいか答え的なもの
考え方は2つです。
- 検索レコードのオブジェクトを存在確認して分岐する
- エラーオブジェクトの存在確認をして分岐する
そしてやってはいけない事(エラーの元凶)は次の2つです。
- 検索レコードにテキストがあるかを存在確認して分岐する
- エラーオブジェクトのテキストがあるか確認して分岐する
オブジェクトそのものの存在確認をする場合は【有無】で分岐できますが、オブジェクト内の値で分岐しようとした場合は『オブジェクトの存在が大前提』となります。
なので[ objIE.Document.getElementsByTagName("li").innerText ]などと書いた場合、タイプ1-3全てで liタグは存在しないのにテキストを取ろうとしている=「オブジェクトがありません」とエラーが出てきてしまいます。
オブジェクトが無いってどういう事?
例として【タイプ1:一部のタグ(olとかtableなど)を残して値が消えている】で見ていきます。
正しく動くIF分岐script
Dim inText
If IsObject(objIE.Document.getElementsByClassName("hogelist")(0).getElementsByTagName("li")) Then
'オブジェクトが存在しない時の動作
MsgBox("データは見つかりません")
Else
'オブジェクトが存在する時の動作
inText = objIE.Document.getElementByClassName("hogelist")(0).getElementsByTagName("li")(0).innerText
MsgBox("inText")
End If
こんなのはNGです。
Dim inText
If IsEmpty(objIE.Document.getElementsByClassName("hogelist")(0).getElementsByTagName("li")) Then
'オブジェクトが存在しない時の動作
MsgBox("データは見つかりません")
Else
'オブジェクトが存在する時の動作
inText = objIE.Document.getElementByClassName("hogelist")(0).getElementsByTagName("li")(0).innerText
MsgBox("inText")
End If
Dim inText
If IsNull(objIE.Document.getElementsByClassName("hogelist")(0).getElementsByTagName("li").innerText) Then
'オブジェクトが存在しない時の動作
MsgBox("データは見つかりません")
Else
'オブジェクトが存在する時の動作
inText = objIE.Document.getElementByClassName("hogelist")(0).getElementsByTagName("li")(0).innerText
MsgBox("inText")
End If
タイプ1の場合、<li>も<li>に囲まれたテキストも存在しません。
その為、EmptyやNULLで存在確認をしようとすると、そもそものliタグが存在していない為「オブジェクトが無い」と怒られる事になります。
存在確認の鍵は【 IsObject / IsEmpty / IsNull 】を使いこなすこと
私もしばらく戸惑っていましたが、VBScriptでスクレイピングを書こうとした場合、この3つの違いを理解している事は大切です。
- IsObject(変数):変数がobjectか否かを確認。変数が存在しない場合はオブジェクトではないと回答
- IsEmpty(変数):変数に値が入っているかを確認(入っていない場合がTRUE)。NULLの場合、NULLという値が入っているのでFALSEが返る。TRUEとなるのはEmptyで初期化されている場合のみ。変数が存在しない場合はobjectNothingのエラーが出る。
- IsNull(変数):変数にNULLが入っているかを確認(NULLの場合がTRUE)。初期化した値(変数=Empty)の場合FALSEが返る。変数が存在しない場合はobjectNothingのエラーが出る。
具体的に見てみましょう。
IsObjectの動作
こんなスクリプトを実行してみます。
Option Explicit
Dim objTEST
'変数にNULLを代入
objTEST = NULL
IF IsObject(objTEST) Then
MsgBox("TRUE")
Else
MsgBox("FALSE")
End If
'変数をSETしNothingで初期化
Set objTEST = Nothing
IF IsObject(objTEST) Then
MsgBox("真")
Else
MsgBox("偽")
End If
'変数をEmptyで初期化
objTEST = Empty
IF IsObject(objTEST) Then
MsgBox("正")
Else
MsgBox("否")
End If
メッセージボックスで出てくる値は【FALSE / 真 / 否】です。NothingでもオブジェクトとしてセットされていればTRUEを返します。
IsEmptyの動作
IsObjectと同じくこんなスクリプトを実行してみます。
Option Explicit
Dim objTEST
'変数にNULLを代入
objTEST = NULL
IF IsEmpty(objTEST) Then
MsgBox("TRUE")
Else
MsgBox("FALSE")
End If
'変数をSETしNothingで初期化
Set objTEST = Nothing
IF IsEmpty(objTEST) Then
MsgBox("真")
Else
MsgBox("偽")
End If
'変数をEmptyで初期化
objTEST = Empty
IF IsEmpty(objTEST) Then
MsgBox("正")
Else
MsgBox("否")
End If
この答は【FALSE / 偽 / 正】です。ちなみに、オブジェクトをEmptyで初期化する事は出来ません。[ Set objTEST = Empty ]と書くと「オブジェクトがありません」と怒られます。
IsNullの場合
同じ方法でこんなスクリプトを実行します。
Option Explicit
Dim objTEST
'変数にNULLを代入
objTEST = NULL
IF IsNull(objTEST) Then
MsgBox("TRUE")
Else
MsgBox("FALSE")
End If
'変数をSETしNothingで初期化
Set objTEST = Nothing
IF IsNull(objTEST) Then
MsgBox("真")
Else
MsgBox("偽")
End If
'変数をEmptyで初期化
objTEST = Empty
IF IsNull(objTEST) Then
MsgBox("正")
Else
MsgBox("否")
End If
この答は【TRUE/ 偽 / 否】です。[ Set objTEST = NULL]と書いた場合もEmpty と同じく「オブジェクトがありません」と怒られます。
まとめ
ここまでを表にするとこんな感じ。
| 変数 = NULL | 変数 = Empty | 変数 = "" | Set 変数 = Nothing | 備考 | |
|---|---|---|---|---|---|
| IsNull() | TRUE | FALSE | FALSE | FALSE | 変数がobjectの時は無条件でFALSE。 空文字 ”” もNULLでは無いためFALSE。 スクレイピングではまず使い道はない。 |
| IsEmpty() | FALSE | TRUE | FALSE | FALSE | 初期化されているかを判別する。 つまりは、Flag的使い方が可能。 何かの処理で値が入ればそれを軸に分岐を組める。 |
| IsObject() | FALSE | FALSE | FALSE | TRUE | オブジェクトか否かを判断する。 スクレイピングでは存在確認で使いどころが多い。 変数に値が入っていてもオブジェクトでなければFALSE。 |
ClassNameで抽出した値が存在しているかを確認するのはIsObjyect一択。


