
最近クラウドソーシングなどで「Webスクレイピング」案件なるものがあり、興味が沸いたのでツールの作り方をまとめました。
言語はなんでもいいのですが、環境構築不要でとっつきやすいExcel VBAを使って今回は解説していきます。
目次
Webスクレイピングとは?
Webスクレイピングは、あるWebページから特定の情報を取得してデータとしてまとめる事を言います。
通販サイトやオークションサイトの商品情報、ニュースサイトやSNSの情報などが対象サイトとしてよくあげられているようです。
VBAでAmazonの商品情報をスクレイピングするツールを作成してみよう
試しにAmazonの売れ筋ランキング(ゲーム部門)の商品情報を取得するツールを作ってみます。
作りたいツールがある場合は、適宜ソースを置換してください。
【参考記事】
VBAのInternetExplorerオブジェクトのVisibleプロパティ
手順1. VBAでInternetExplorerとHTMLを操作する準備
VBAでは通常だとWebサイトの操作を行う事が出来ません。
ですが、操作を可能にするライブラリーが用意されているので、そのライブラリーを読み込む準備をします。
Excel→VBEを開き、エディタ上ツールバーの「ツール」の中にある「参照設定」をクリック。
「Microsoft Internet Controls」と「Microsoft HTML Object Library」を探してチェックを入れます。
これで、Webページのデータを取得するためのライブラリーを使う準備が整いました!
手順2.IEで特定のURLのページを起動しHTML操作を行う準備関数を作る
これらは上記「[VBA]30分あればできるVBAスクレイピング」のソースコードを参考にして作ります。
標準モジュールを新規作成し、以下のコードを記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
Sub main() '//////////////////////////////////////////// ' メイン処理 '//////////////////////////////////////////// Dim objIE As InternetExplorer ' IEを操作するInternetExplorer型の変数 Dim strUrl As String ' 開くページのURLを保持する変数 Dim htmlDoc As HTMLDocument 'HTMLを操作するHTMLDocument型の変数 ' ******************** Webスクレイピング準備 start *********************************** ' 開きたいURLをセット(今回はアマゾンの売れ筋ランキングのページ) strUrl = "https://www.amazon.co.jp/gp/bestsellers/videogames/ref=zg_bs_videogames_home_all?pf_rd_p=a947a9f9-00ea-4384-9e9e-d8f87bd87f3e&pf_rd_s=center-2&pf_rd_t=2101&pf_rd_i=home&pf_rd_m=AN1VRQENFRJN5&pf_rd_r=R2X9WNT4NPFJKX09Z8VF&pf_rd_r=R2X9WNT4NPFJKX09Z8VF&pf_rd_p=a947a9f9-00ea-4384-9e9e-d8f87bd87f3e" ' IEを立ち上げ、データを取得する準備 Call getpage(objIE, strUrl) 'objIEで読み込まれているHTMLドキュメントをセット Set htmlDoc = objIE.document ' ******************** Webスクレイピング準備 end ************************************* End Sub Sub getpage(ByRef objIE As Object, strUrl As String) '//////////////////////////////////////////// ' IEを立ち上げる処理 ' 引数:IEオブジェクト, URL文字列 '//////////////////////////////////////////// ' objIEにInternetExplorerオブジェクトを作成 Set objIE = CreateObject("Internetexplorer.Application") ' IEを表示 objIE.Visible = True ' 開くページのURLを設定 objIE.navigate (strUrl) '読み込み待ち Call WaitResponse(objIE) End Sub Sub WaitResponse(objIE As Object) '//////////////////////////////////////////// ' IEの読み込み待ちを行う処理 '//////////////////////////////////////////// '読み込み待ち Do While objIE.Busy = True Or objIE.readyState < READYSTATE_COMPLETE DoEvents Loop End Sub |
main関数が実行されると「getpage」「WaitResponse」という2つの共通関数を呼ぶようにしています。
2つの関数についてそれぞれ説明します。
・getpage関数
IEオブジェクトを作成して、設定されたURLのページをIEで表示させる処理です。
引数に「IEオブジェクトを保持する変数」と「URL文字列」を指定します。
引数のIEオブジェクトはByRef(参照渡し)でmain関数の「objIE」とgetpage関数「objIE」の値ははリンクしていますので、作成されたIEオブジェクトはそのままmain関数に引き継がれます。
・WaitRespons関数
IEが立ち上がり、指定したURLのページが表示されるまで待機する関数です。
表示まで出来たら、処理を解放し次の処理を行います。
ここまで来出来たら、main関数を実行してみましょう。
実行するとこんな感じにIEが立ち上がります。
手順3.ページのHTMLソースから特定の情報を取得する
ページの情報を取得するにはあらかじめページのHTMLソースを確認する必要があります。
(ここからはHTMLを扱う知識がある程度必要になります。)
まず、情報を取得するページをブラウザで開きます。ブラウザはIE、chrome、FireFoxなどなんでもOKですが、今回はchromeを使います。
ページを開いて「F12」キーを押すと下の画像のようにページのHTMLソースが表示されます。
ここから取得したい要素の「class名」や「id名」を特定してVBAで操作します。
ちなみに、カーソルをコードやページの要素に近づけるとどこの部分なのか簡単にわかって便利です。
要素の「class名」「id名」を取得出来たら、VBAでテキストを取得する処理を組み込んでいきます。
取得するには「main関数」で作成した「htmlDoc」変数を使います。
・id名でテキスト情報を取得したい場合
1 |
htmlDoc.getElementById("id名").innerHTML |
・class名でテキスト情報を取得したい場合
classは同名で複数使われることがあるため、何個目の物を取るか指定する必要があります。
1 |
htmlDoc.getElementsByClassName("class名")(0).innerHTML |
class名全てのデータを取得する場合はFor Eachを使って繰り返し処理で取得します。
1 2 3 |
For Each str In htmlDoc.getElementsByClassName("class名") str.innerHTML Next |
試しにランキング1ページ目のゲーム名の一覧を取得してみます。
main関数を以下のように修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
Sub main() '//////////////////////////////////////////// ' メイン処理 '//////////////////////////////////////////// Dim objIE As InternetExplorer ' IEを操作するInternetExplorer型の変数 Dim strUrl As String ' 開くページのURLを保持する変数 Dim htmlDoc As HTMLDocument 'HTMLを操作するHTMLDocument型の変数 ' ******************** Webスクレイピング準備 start *********************************** ' 開きたいURLをセット(今回はアマゾンの売れ筋ランキングのページ) strUrl = "https://www.amazon.co.jp/gp/bestsellers/videogames/ref=zg_bs_videogames_home_all?pf_rd_p=a947a9f9-00ea-4384-9e9e-d8f87bd87f3e&pf_rd_s=center-2&pf_rd_t=2101&pf_rd_i=home&pf_rd_m=AN1VRQENFRJN5&pf_rd_r=R2X9WNT4NPFJKX09Z8VF&pf_rd_r=R2X9WNT4NPFJKX09Z8VF&pf_rd_p=a947a9f9-00ea-4384-9e9e-d8f87bd87f3e" ' IEを立ち上げ、データを取得する準備 Call getpage(objIE, strUrl) 'objIEで読み込まれているHTMLドキュメントをセット Set htmlDoc = objIE.document ' ******************** Webスクレイピング準備 end ************************************* ' ******************** データを抽出する処理 start *********************************** Dim str As Variant For Each str In htmlDoc.getElementsByClassName("p13n-sc-truncated") Debug.Print str.innerHTML Next ' ******************** データを抽出する処理 end ************************************* End Sub |
実行すると、イミディエイトウィンドウ(下の白い枠)にゲームのタイトルがズラリと表示されました。
ここまでがWebスクレイピングツールを作るために基礎知識でした。
あとは、実際に要件に合わせて情報を取得していきます。
手順4.要件にあった情報を取得する
今回は簡単に、ランキングページに記載されている「順位」「ゲームタイトル」「価格」を3列に表示させる処理を作っていきたいと思います。
「main関数」の中身を下のように修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
Sub main() '//////////////////////////////////////////// ' メイン処理 '//////////////////////////////////////////// Dim objIE As InternetExplorer ' IEを操作するInternetExplorer型の変数 Dim strUrl As String ' 開くページのURLを保持する変数 Dim htmlDoc As HTMLDocument 'HTMLを操作するHTMLDocument型の変数 Dim intRowCnt As Integer ' 行カウンタ Dim str As Variant ' 取得文字列 ' ******************** Webスクレイピング準備 start *********************************** ' 開きたいURLをセット(今回はアマゾンの売れ筋ランキングのページ) strUrl = "https://www.amazon.co.jp/gp/bestsellers/videogames/ref=zg_bs_videogames_home_all?pf_rd_p=a947a9f9-00ea-4384-9e9e-d8f87bd87f3e&pf_rd_s=center-2&pf_rd_t=2101&pf_rd_i=home&pf_rd_m=AN1VRQENFRJN5&pf_rd_r=R2X9WNT4NPFJKX09Z8VF&pf_rd_r=R2X9WNT4NPFJKX09Z8VF&pf_rd_p=a947a9f9-00ea-4384-9e9e-d8f87bd87f3e" ' IEを立ち上げ、データを取得する準備 Call getpage(objIE, strUrl) 'objIEで読み込まれているHTMLドキュメントをセット Set htmlDoc = objIE.document ' ******************** Webスクレイピング準備 end ************************************* ' ******************** データを抽出する処理 start *********************************** ' カウント初期化 intRowCnt = 3 ' ランキング順位 For Each str In htmlDoc.getElementsByClassName("zg-badge-text") Cells(intRowCnt, 1).Value = str.innerHTML intRowCnt = intRowCnt + 1 Next intRowCnt = 3 ' タイトル For Each str In htmlDoc.getElementsByClassName("p13n-sc-truncated") Cells(intRowCnt, 2).Value = str.innerHTML intRowCnt = intRowCnt + 1 Next intRowCnt = 3 ' 価格 For Each str In htmlDoc.getElementsByClassName("p13n-sc-price") Cells(intRowCnt, 3).Value = str.innerHTML intRowCnt = intRowCnt + 1 Next ' ******************** データを抽出する処理 end ************************************* End Sub |
単純にWebページから取得した順位、タイトル、価格をそれぞれの列に1つずつ出力させています。
実行すると、トップ50位までの情報を取得することが出来ました!
リンクをクリックしてページ移動をする方法
別ページにボタンやリンクをクリックして移動することも可能です。
クリックしたい要素を取得後、「.Click」で移動することができます。JavaScriptのDOM操作と似てますね…
1 2 |
htmlButton = objIE.document.getElementsByClassName("class名")(0) htmlButton.Click |
リンク移動を駆使して売れ筋ランキングデータ全取得する
Amazonの売れ筋ランキングは1ページ50位までで区切られているようで、その先は別ページに移動する必要があります。
このクリック移動をうまく使って全てのデータを取得できるようにツールを改造してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
Sub main() '//////////////////////////////////////////// ' メイン処理 '//////////////////////////////////////////// Dim objIE As InternetExplorer ' IEを操作するInternetExplorer型の変数 Dim strUrl As String ' 開くページのURLを保持する変数 Dim intRowCnt As Integer ' 行カウンタ Dim objLink As Variant ' 取得リンク要素 Dim bLoopEnd As Boolean ' ループ終了フラグ ' ******************** Webスクレイピング準備 start *********************************** ' 開きたいURLをセット(今回はアマゾンの売れ筋ランキングのページ) strUrl = "https://www.amazon.co.jp/gp/bestsellers/videogames/ref=zg_bs_videogames_home_all?pf_rd_p=a947a9f9-00ea-4384-9e9e-d8f87bd87f3e&pf_rd_s=center-2&pf_rd_t=2101&pf_rd_i=home&pf_rd_m=AN1VRQENFRJN5&pf_rd_r=R2X9WNT4NPFJKX09Z8VF&pf_rd_r=R2X9WNT4NPFJKX09Z8VF&pf_rd_p=a947a9f9-00ea-4384-9e9e-d8f87bd87f3e" ' IEを立ち上げ、データを取得する準備 Call getpage(objIE, strUrl) 'objIEで読み込まれているHTMLドキュメントをセット Set htmlDoc = objIE.document ' ******************** Webスクレイピング準備 end ************************************* ' ******************** データを抽出する処理 start *********************************** ' カウント初期化 intRowCnt = 3 ' フラグ初期化 bLoopEnd = True ' 「次のページ」リンクが存在する限り繰り返す Do While bLoopEnd = True bLoopEnd = False For Each objLink In htmlDoc.Links If InStr(objLink.outerHTML, "次のページ") > 0 Then ' 「次のページ」リンクがあれば遷移 objLink.Click Call WaitResponse(objIE) Call set_webdata(objIE, intRowCnt) ' 50位ぶん追加して次の行を設定 intRowCnt = intRowCnt + 50 bLoopEnd = True Exit For End If Next Loop ' ******************** データを抽出する処理 end ************************************* End Sub Sub set_webdata(objIE As Object, rowcnt As Integer) '//////////////////////////////////////////// ' Webページから取得したデータをExcelシートに出力する処理 ' 引数:IEオブジェクト, 行カウント '//////////////////////////////////////////// Dim intRowStart As Integer ' 行初期値 Dim intRowCnt As Integer ' 行カウント Dim str As Variant ' 取得文字列 Dim htmlDoc As HTMLDocument 'HTMLを操作するHTMLDocument型の変数 'objIEで読み込まれているHTMLドキュメントをセット Set htmlDoc = objIE.document intRowStart = rowcnt intRowCnt = rowcnt ' ランキング順位 For Each str In htmlDoc.getElementsByClassName("zg-badge-text") Cells(intRowCnt, 1).Value = str.innerHTML intRowCnt = intRowCnt + 1 Next intRowCnt = intRowStart ' タイトル For Each str In htmlDoc.getElementsByClassName("p13n-sc-truncated") Cells(intRowCnt, 2).Value = str.innerHTML intRowCnt = intRowCnt + 1 Next intRowCnt = intRowStart ' 価格 For Each str In htmlDoc.getElementsByClassName("p13n-sc-price") Cells(intRowCnt, 3).Value = str.innerHTML intRowCnt = intRowCnt + 1 Next End Sub Sub getpage(ByRef objIE As Object, strUrl As String) '//////////////////////////////////////////// ' IEを立ち上げる処理 ' 引数:IEオブジェクト, URL文字列 '//////////////////////////////////////////// ' objIEにInternetExplorerオブジェクトを作成 Set objIE = CreateObject("Internetexplorer.Application") ' IEを表示 objIE.Visible = True ' 開くページのURLを設定 objIE.navigate (strUrl) '読み込み待ち Call WaitResponse(objIE) End Sub Sub WaitResponse(objIE As Object) '//////////////////////////////////////////// ' IEの読み込み待ちを行う処理 '//////////////////////////////////////////// '読み込み待ち Do While objIE.Busy = True Or objIE.readyState < READYSTATE_COMPLETE DoEvents Loop End Sub |
実行してみると、全ページ分(全2ページ)データを取得できました!