エクセルVBAを使ったWEBスクレイピングツールの作成①
目次
1. Webスクレイピング(Web scraping)とは
ウェブサイトのHTML情報から欲しい情報を抽出することがあります。
クラウドワークスやランサーズでよく依頼されているものは、ネットショップの経営者等が、自社のサイトに関連するものを定期的にスクレイピングし、
・検索順位をチェック
・検索の上位に上がるための対策を行う
・その対策の効果を確認する
と言ったことに使われるものです。また、そのための専用S/Wも市販されています。
2. 今回の目標
表題どおりエクセルのVBAを使って、InternetExplorer(以降IEと呼びます)を起動することによって、IE経由でHTMLの情報を簡単に取得できるプログラム作りを目指します。
具体的な目標は「アマゾンの検索ボックスにキーワードを入力し、検索する」です。
3. 始める前に
エクセルVBAエディターの「ツール」→「参照選択」を開き、
・Microsoft HTML Object Library
・Microsoft Internet Controls
にチェックを入れて「OK」を押しウィンドゥを閉じます。
これで、IEのHTMLの内容をVBA側からのぞけるようになります。
さて、いよいよIEの起動。
- Sub main()
- Dim objIE As InternetExplorer
- 'IEのオブジェクトを作成
- Set objIE = CreateObject("InternetExplorer.Application")
- 'IEを起動
- objIE.Visible = True
- End Sub
これでひとまず、IEの起動は終わりです。
次に、URLを指定して、希望のサイトを表示させます。
アマゾンのサイトは https://www.amazon.co.jp/
前のプログラムに対して追加した部分を赤字で示します。
本プログラムでIEを起動し、アマゾンのホームぺージを立ち上げた場合に、内容が全て読み込まれないまま、次のブログラムに渡してしまうと次のスクレイピング作業時にエラーが発生するので、完全に読み込まれてから渡すようにします。そのために「Do while – Loop文」を追記しました。
●「readyState」は戻り値でIEの状態を示します。4(READYSTATE_COMPLETE)は IEオブジェクトの全データが読み込まれた状態を示す完了状態。
●BusyがTrue、またはobjIE.readyStateがREADYSTATE_COMPLETE(4)以外の時にはループを繰り返し、IEが立ち上がるのを待ちます。何らかの理由でIEが立ち上がらない時に『ESC』キーで、このループから脱出することが可能となります。
赤字が追加部分。
- Option Explicit
- Const READYSTATE_COMPLETE = 4
- Sub main()
- Dim objIE As InternetExplorer
- Set objIE = CreateObject(“InternetExplorer.Application”)
- objIE.Visible = True
- objIE.Navigate2 “https://www.amazon.co.jp/"
- Do While objIE.Busy Or objIE.readyState <> READYSTATE_COMPLETE
- DoEvents ‘上記の条件が長時間不成立の時、ESCキーで停止できるように追記。
- Loop
- End Sub
4. 検索用のテキストボックスに検索文字を入力する。
さて、アマゾンの初期画面は表示できました。
ここからは、HTMLを解析して該当の入力部のHTML構文を眺めてみたいと思います。
HTMLを見るのは、IEに標準でついている[DOM Explorer]が便利です。
「F12」キーを押すと画面のように、下半分に[DOM Explorer]が現れます。
左上の角にある[要素の選択]ボタンを押すと、IEのブラウザー上で要素を選択するモードになのます。
そのときに上部にあるWEB画面上で、マウスカーソルを当てた箇所がハイライトされるので、HTMLを見たいブロックでマウスをクリックし選択します。
選択した部分に該当するHTMLが下部にある[DOM Explorer]上で、水色の背景となって表示されます。
今回は検索用のテキストボックスをクリックし、そのHTMLを早速見てみると、下記のようになっています。
<input name="field-keywords" tabindex="9" class="nav-input" id="twotabsearchtextbox" dir="auto" type="text" placeholder="" value="" autocomplete="off">
textタイプのinput要素になりますが、id属性 "twotabsearchtextbox" があります。同じid属性を持つ要素はこの画面にはないというお決まりですので、getElementByIdメソッドを使って要素を探し出し、IHTMLElement変数のobjElementに代入します。
Set objElement = objIE.document.getElementById("twotabsearchtextbox")
次に、同定したテキストボックスに値を入力します。
objElement.Value = “キーワード”
5. 検索文字をサーバーに送信する
検索テキストボックスのHTMLの場所を見つけたのと同様に[DOM Explorer]で 検索テキストボックスの右にある「虫めがね」のアイコンをクリックして、該当のHTMLを見ます。
今度はid属性がありません。これは困りました。
<input tabindex="10" class="nav-input" type="submit" value="検索">
tabindexは「TAB」キーを押したときの順番を示すものなので、これ自体は1つしかない数字ですが、これはデザイン変更時に簡単に変えられる可能性がおおきいです。
ここではinputタグとそのタグの属性であるclass属性の"nav-input"をキーワードにして該当のHTMLを探します。
今度は getElementsByTagNameメソッドを使います。
getElementsのs(複数形)が示すように、そのHTMLの中にあるinput属性のtagを全て取り込みます。
取り込んだ配列はIHTMLElementCollectionの変数であるobjInputTagsに保存します。
次にobjInputTagsの各要素を「For Each」処理でひとつずつ取り出してIHTMLElement の変数であるobjInputに代入し、そのclass属性が "nav-input"であるかどうかを判定します。
見つけたらobjInput.Clickで検索キーワードをサーバーに送信します。
- Set objInputTags = objIE.document.getElementsByTagName("input")
- For Each objInput In objInputTags
- On Error Resume Next 'エラーが発生するとエラーの発生した次の要素から処理
- class_name = objInput.className
- On Error GoTo 0 ' 1つ前で宣言したエラー無視を無効にする。
- If class_name = "nav-input" Then
- objInput.Click '見つけた! すかさずクリック
- 'IEが完全表示されるまで待機
- Do While objIE.Busy Or objIE.readyState <> READYSTATE_COMPLETE
- DoEvents '上記の条件が長時間不成立の時、ESCキーで停止できるように追記。
- Loop
- Exit For
- End If
- Next
以上で、自動でキーワードを入力し、検索するプロクラムは終わりです。
今回作成したブログラムを清書すると以下となります。
- Option Explicit
- Const READYSTATE_COMPLETE = 4
- Dim objIE As InternetExplorer
- Dim objElement As IHTMLElement
- Dim objInputTags As IHTMLElementCollection 'Inputオブジェクト配列、集合体
- Dim objInput As IHTMLElement 'Inputオブジェクト
- Dim class_name As String
- Sub main()
- Set objIE = CreateObject("InternetExplorer.Application")
- objIE.Visible = True
- objIE.Navigate2 "https://www.amazon.co.jp/"
- Do While objIE.Busy Or objIE.readyState <> READYSTATE_COMPLETE
- DoEvents '上記の条件が長時間不成立の時、ESCキーで停止できるように追記。
- Loop
- Set objElement = objIE.document.getElementById("twotabsearchtextbox")
- objElement.Value = "キーワード"
- Set objInputTags = objIE.document.getElementsByTagName("input")
- For Each objInput In objInputTags
- On Error Resume Next 'エラーが発生するとエラーの発生した次の要素から処理
- class_name = objInput.className
- On Error GoTo 0 ' 1つ前で宣言したエラー無視を無効にする。
- If class_name = "nav-input" Then
- objInput.Click '見つけた! すかさずクリック
- 'IEが完全表示されるまで待機
- Do While objIE.Busy Or objIE.readyState <> READYSTATE_COMPLETE
- DoEvents '上記の条件が長時間不成立の時、ESCキーで停止できるように追記。
- Loop
- Exit For
- End If
- Next
- ‘(ASINを取り出すプログラム)
- End Sub