会社のPCなどでは自由にseleniumをインストールできなかったり、ドライバをダウンロードできないかもしれません。
そのような場合、どうすればWebスクレイピングで業務を自動化できるのでしょうか?
今回はVBAをを用いて、seleniumやWebドライバを使用せずにWebサイトにPost通信し、結果をシートに書き込む方法をご紹介します。
さっそくやってみましょう。
高精度計算サイトに値をPOSTで渡して計算結果を取得してみよう
今回はこちらのサイトに対してWebスクレイピングをしてみましょう。
こちらのサイトでは一辺の長さを入力すると、三角形の面積や高さを計算してくれます。
VBAから一辺の長さをサイトに渡して、計算結果を受け取り、Excelに書き込んでみたいと思います。
手順① Webスクレイピングが許可されているか確認する
さっそくWeb情報をVBAから取得したいところですが、その前にそのサイトがWebスクレイピングを許可しているか確認しなけばいけません。
確認方法は、Webスクレイピング先のサイトURLの最初の ” / ” の後に robots.txt と打ち込んでエンターを押します。
例えば本サイトの確認方法は 「https://jitantech.com/robots.txt」 とURLバーに打ち込んでエンターを押します。
すると、次の画面が表示されます。
Disallow(許可しない)の部分に注目します。
この例では 「/wp-admin/」 となっています。これは本サイトでは「https://jitantech.com/wp-admin/」の階層の全てのファイルがWebスクレイピングで許可されていないということです。
ですので、例えば「https://jitantech.com/wp-admin/○○.html」というページはWebスクレイピングができません。
では次にVBAで実際にWebスクレイピングをしていきます。
そもそも robots.txt が配置されていないサイトもあります。
その場合は利用規約などをよく読んでWebスクレイピングするか判断しましょう。
手順② プログラム画面の表示
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 |
' Sleep関数を使用するための宣言 Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As Long) Sub httpPost() ' サーバーにアクセスするためのオブジェクトを作成 Set client = CreateObject("MSXML2.ServerXMLHTTP") ' WebページへPOST通信 client.Open "POST", "https://keisan.casio.jp/exec/system/1161228787", False ' 相手サーバーへの負荷考慮 Sleep 2000 ' Webページに値を渡す(渡す文字列はWebページごとに変更が必要) client.Send "var_a=500" ' 読み込みが完了するまで待機 Do While client.ReadyState < 4 DoEvents Loop ' リクエストが正常に処理できた場合 If client.Status = 200 Then ' 空のHTMLドキュメントを生成 Set htmldoc = CreateObject("htmlfile") ' HTMLドキュメントにWebページの情報を書き込む htmldoc.write client.responseText ' ワンクッション挟む DoEvents ' 取得した結果をセルに書き込み(getElementByIdの値はWebページごとに変更が必要) Cells(1, 1) = htmldoc.getElementById("ans0").outerText Cells(2, 1) = htmldoc.getElementById("ans1").outerText Cells(3, 1) = htmldoc.getElementById("ans2").outerText End If End Sub |
解説
ここからプログラムの解説になりますが、必要ない場合は次の手順へ進みましょう!
‘ Sleep関数を使用するための宣言
Declare PtrSafe Sub Sleep Lib “kernel32” (ByVal ms As Long)
まずはSleep関数(プログラムの実行を指定した秒数停止する)を使用するための宣言をしています。
‘ サーバーにアクセスするためのオブジェクトを作成
Set client = CreateObject(“MSXML2.ServerXMLHTTP”)
「MSXML2.ServerXMLHTTP」オブジェクトを作成しています。このオブジェクトは異なるサーバー間でHTTPアクセスのメソッド(OpenメソッドでWebサーバーと通信したり、Sendメソッドで値を渡したりする)などを持っています。
‘ WebページへPOST通信
client.Open “POST”, “https://keisan.casio.jp/exec/system/1161228787”, False
指定したURLに対してPOST通信を行います。Falseとしているのは非同期通信を行わないためです。非同期通信とは、相手のWebサーバーからの応答を待たずに次の処理を進めることです。Webシステムを開発する場合にはよく使用されますが、今回は使用しません。
Sleep 2000
Sleep関数を使用して、処理を2秒間停止しています。
Openの後に続けざまにSendするのではなく、2秒間間を置くことで相手サーバーへの負荷を軽減しています。
繰り返し処理などで、連続してWebサーバーから値を取得する場合などには、必ず入れることをおすすめします。
client.Send “var_a=500”
ここでは相手サーバーに値を渡しています。
ここは少し詳しく解説しようと思います。
「var_a」とは高精度計算サイトの「一辺の長さ」を入れるインプットボックスの名前です。
例えば、高精度計算サイトは次の画像のような画面構成になっています。
通常の操作では、辺の長さaに値を入力して計算ボタンを押すと、面積Sや長さL、高さhに結果が表示されます。
プログラムから「辺の長さa」に値を設定するには、辺の長さaのHTMLタグを調べて、インプットボックスの名前(name)を取得する必要があります。
以下はChromeブラウザの場合で、HTMLタグを調べる手順です。
インプットボックスにマウスを当てて右クリック ⇒ 検証をクリックします。
すると次の画面が表示されます。
これはWebサイトのソースコードです。
そしてフォーカスされた部分を見ると、ID= “var_a” となっています。
ですのでWebサイトに対して var_a = 500 という値を渡すと、Webサイト側は 辺の長さa に 500 が入力されたという風に受け取るのです。
‘ 読み込みが完了するまで待機
Do While client.ReadyState < 4
DoEvents
Loop
Do While ○○ とは、○○の間は処理を続けるという意味です。
つまり client.ReadyState < 4 間は ループ処理を繰り返すということです。
ReadyStateは通信の状態を表します。値は次の表のように変化します。
操作が完了すると client.ReadyState = 4 となるためループが終了して、次の処理に進みます。
DoEvents とは OSが他のイベントも処理できるようにします。これがない場合、ループ処理の実行中はユーザが他の操作を行うことができません。
‘ リクエストが正常に処理できた場合
If client.Status = 200 Then
client.Status = 200 とは 通信のリクエストが成功したことを表しています。200(成功)の場合にのみ処理を継続します。
Statusの値は通常のHTTP通信で返される結果です。例えばWebページが見つからなかった場合は 404(Not Found)になります。
‘ 空のHTMLドキュメントを生成
Set htmldoc = CreateObject(“htmlfile”)
CreateObject(“htmlfile”) でHTML文書を操作するためのオブジェクトを生成しています。
それを htmldoc という変数に入れています。これにより、htmldoc.getElementById(“ここにHTMLのIDを入れる”)とすることで、目的のインプットボックスの値を取得することができます。これは後で説明します。
‘ HTMLドキュメントにWebページの情報を書き込む
htmldoc.write client.responseText
先ほど作成したHTML文書を操作するためのオブジェクト(htmldoc)に、Webサーバーから取得したHTML文書(client.responseText)を書き込みます。
Webサーバーから取得したHTML文書はただのテキスト文字列なので、もし目的のインプットボックスの値を取得したいといった場合、HTML文書を1文字1文字解析して目的のインプットボックスを探さなければなりません。しかしHTML文書を操作するためのオブジェクト(htmldoc)を使用しているので、htmldoc.getElementById(“○○”)とするだけで目的のインプットボックスの値を取得できるのです。
‘ ワンクッション挟む
DoEvents
この記述がないとエラーになる場合がありました。
htmldoc.write client.responseText の書込み直後に htmldoc.getElementById(“ans0”).outerText でHTML文書にアクセスしてしまうとオブジェクトの生成が間に合わず、エラーとなったと予想します。
‘ 取得した結果をセルに書き込み(getElementByIdの値はWebページごとに変更が必要)
Cells(1, 1) = htmldoc.getElementById(“ans0”).outerText
Cells(2, 1) = htmldoc.getElementById(“ans1”).outerText
Cells(3, 1) = htmldoc.getElementById(“ans2”).outerText
ようやく目的の値を取得する部分にきました。
ここでは htmldoc.getElementById(“ans0”).outerText により ID = ans0 の テキスト部分を取得しています。
先ほどの手順(インプットボックス上で右クリック⇒検証)でしたべたIDは次の通りでした。
そして実際のHTMLは次の通りです。
つまり面積Sの右にある 枠 のIDは ans0 でそこには 108,253.1754306 という値が入っており、これが辺の長さa=500の場合の面積の計算結果ということです。
この計算結果をエクセルシートの1~3行目に記載します。
実行結果
プログラムを実行すると1行目に面積、2行名に周囲の長さ、3行目に高さが書き込まれています。
もし高精度計算サイトに普通に画面から操作して辺の長さaに500を入力した場合は次の通りになります。
画面を操作せずに、辺の長さを500とした時の計算結果をExcelに書き込むことができました!
まとめ
いかがだったでしょうか。
今回のプログラムを利用することでWebサーバーに櫃ような情報を渡して、その結果をWebサーバーから受け取ることができました。
Excelがインストールされているパソコンであれば、ほかに何もインストールすることなく動作します。
本プログラムを利用して、皆様の業務が時短できることを願っています。
ご不明な点がございましたら気軽にコメントをよろしくお願いいたします。
コメント