🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Excel VBA で Web スクレイピング — Internet Explorer を使わずに Web サイトからデータを取得する方法

|

Excel VBA で Web スクレイピング — Internet Explorer を使わずに Web サイトからデータを取得する方法

TL;DR — スクレイピングのマクロが受け取るのは、あなたが見ているページではなく、サーバーが送ってきた HTML です。ブラウザーはページが届いたあとに JavaScript を実行し、目的の表はその時点で作られることが多いので、VBA がダウンロードするものには決して現れません。まず確認してください。ページのソースを表示(Ctrl+U)を開き、必要な値を検索します。そこにあれば、XMLHTTP でページをダウンロードし、htmlfile のドキュメントで読み取ります。なければ、そのページは JSON リクエストでデータを読み込んでいるので、そのリクエストを直接呼び出すほうが、どんなスクレイピングよりも簡単で安定しています。Internet Explorer による自動操作は、もう選択肢になりません。

Dim http As Object, doc As Object
Set http = CreateObject("MSXML2.XMLHTTP.6.0")
http.Open "GET", "https://example.com/prices", False
http.send
Set doc = CreateObject("htmlfile")
doc.body.innerHTML = http.responseText
Debug.Print doc.getElementsByTagName("table").Length & " tables found"

この記事は、Web のデータを Excel に取り込む シリーズの第三回です。VBA の HTTP リクエスト がリクエストを、VBA の JSON 解析 が構造化されたレスポンスを扱い、この記事ではコードではなく人のために書かれたページを扱います。シリーズを貫く考え方は、Web リクエストが渡してくれるのはデータではなくテキストだ ということです。サーバーとセルの間には、あなたが責任を持つ三つの変換があります。バイト列からテキストへ、テキストから構造へ、構造からグリッドへ。 スクレイピングは、その構造がそもそもあなた向けに作られていない場合です。

この記事で学べること

  • 考え方の軸:サーバーが送ってきた HTML
  • 10 秒テスト:ページのソースを表示
  • データがソースにないとき:JSON を探す
  • Internet Explorer や Selenium を使わない理由
  • htmlfile で HTML の表を読む
  • 取得した数値はテキストである
  • meta charset による文字化け
  • Power Query と、礼儀正しいスクレイピング

考え方の軸:サーバーが送ってきた HTML

ブラウザーはページに対して二つのことをします。HTML をダウンロードし、次にページの JavaScript を実行します。JavaScript は多くの場合、さらにデータを取得して、表や価格や一覧を画面上に組み立てます。あなたが見ているのは、この両方の段階の結果です。VBA が HTTP リクエストでダウンロードするのは最初の段階だけ、つまり サーバーが送ってきたままの HTML です。

だからこそ、スクレイピングでいちばん多い不満は「コードは表を見つけられないのに、自分には表が見えている」なのです。どちらの言い分も正しいのです。表はブラウザーの動いているページには存在し、サーバーが送ってきた HTML には存在しません。どんなセレクターも、待機も、再試行もこれを直せません。データはダウンロードしたものの中に、最初からなかったのですから。

10 秒テスト:ページのソースを表示

コードを書く前に、ブラウザーでページを開いて Ctrl+U(ページのソースを表示)を押してください。サーバーが送ってきたままの HTML、つまり VBA が受け取るのと同じものが表示されます。その中を(Ctrl+F で)検索し、価格や名前など、ページ上に見えている値を探します。

  • 見つかった場合: データはサーバーの HTML の中にあります。後述の XMLHTTP と htmlfile でスクレイピングします。
  • 見つからない場合: JavaScript が読み込んでいます。次のセクションに進んでください。

このテストに 検証(F12 の「要素」タブ)を使ってはいけません。検証が見せるのは JavaScript の実行後の動いているページなので、どちらの場合でもデータが表示されてしまいます。

データがソースにないとき:JSON を探す

JavaScript で表を組み立てるページは、データをどこかから取得しているはずで、それはほぼ必ず同じサイトへの JSON リクエストです。それを見つけます。

  1. ブラウザーの開発者ツール(F12)を開き、ネットワーク タブに移ります。
  2. Fetch/XHR で絞り込み、ページを再読み込みします。
  3. リクエストを順にクリックし、レスポンス を確認します。そのどれかに、目的のデータが JSON として入っています。
  4. その URL をコピーし、VBA の HTTP リクエスト のとおりに VBA から呼び出し、VBA の JSON 解析 で解析します。

この方法は、スクレイピングでうまくいく場合でも、スクレイピングより優れています。JSON には表の位置ではなくフィールド名があり、数値に通貨記号が付いておらず、ページのデザインよりも変更の頻度が低いからです。この方法に頼る前に、サイトの利用規約を確認してください。ドキュメント化されていないエンドポイントは、予告なく変わることもあります。

Internet Explorer や Selenium を使わない理由

古いチュートリアルでは、CreateObject("InternetExplorer.Application") で VBA からブラウザーを操作しています。Internet Explorer は 2022 年 6 月にサポートが終了しました。もうサポートされておらず、最近の Web サイトはますます Internet Explorer では動かなくなっています。これを使って新しい仕事を始めるのはやめ、依存しているマクロは置き換える計画を立ててください。

VBA でよく使われる代替手段の Selenium Basic は、2016 年以降リリースがなく、インストールされている Chrome や Edge のバージョンに合ったブラウザードライバーが必要です。ブラウザーが更新されるたびに、ユーザーのマシンでマクロが壊れる可能性があります。JavaScript がないと動かず、呼び出せるデータリクエストもないページには、今でも正しい道具になりえますが、既定ではなく最後の手段として扱ってください。

htmlfile で HTML の表を読む

サーバーの HTML の中にあるデータなら、ブラウザーは要りません。ページをダウンロードして htmlfile オブジェクトに読み込めば、Web ページのように検索できるドキュメントが手に入ります。

Sub ScrapeFirstTable(ByVal url As String, ByVal target As Range)
    Dim http As Object, doc As Object, tbl As Object
    Dim out() As Variant, r As Long, c As Long, nCols As Long

    Set http = CreateObject("MSXML2.XMLHTTP.6.0")
    http.Open "GET", url, False
    http.setRequestHeader "User-Agent", "Mozilla/5.0"
    http.send
    If http.Status <> 200 Then Err.Raise vbObjectError + 514, , "HTTP " & http.Status

    Set doc = CreateObject("htmlfile")
    doc.body.innerHTML = http.responseText
    If doc.getElementsByTagName("table").Length = 0 Then Err.Raise vbObjectError + 515, , "No table"
    Set tbl = doc.getElementsByTagName("table")(0)

    nCols = 0
    For r = 0 To tbl.Rows.Length - 1
        If tbl.Rows(r).Cells.Length > nCols Then nCols = tbl.Rows(r).Cells.Length
    Next r
    ReDim out(1 To tbl.Rows.Length, 1 To nCols)
    For r = 0 To tbl.Rows.Length - 1
        For c = 0 To tbl.Rows(r).Cells.Length - 1
            out(r + 1, c + 1) = Trim$(tbl.Rows(r).Cells(c).innerText)
        Next c
    Next r
    target.Resize(UBound(out, 1), nCols).Value = out
End Sub

大事な点が三つあります。HTML ドキュメントから得られるコレクション(Rows、Cells、getElementsByTagName)は、Excel の大半とは違って 0 から始まります。行ごとにセルの数が違うことがあるので、配列はいちばん広い行に合わせて確保します。そして表全体を一度にシートへ書き込みます。

特定の要素を探すときは、getElementById と getElementsByTagName に頼ってください。Windows と Office のビルドによっては、遅延バインディングで作った htmlfile ドキュメントが古い互換モードで動き、querySelector や getElementsByClassName のような新しいメソッドが存在しないことがあります。そのため、これらに頼ったコードは、あるマシンでは動き、別のマシンでは動きません。クラスで絞り込むときは、タグをループして .className を確認してください。

「最初の表」を選ぶのは、どんなスクレイパーでもいちばんの弱点です。サイトがリニューアルされて目的の表の上に別の表が加わると、マクロは黙って間違った表を読みます。表に id があればそれを使い、なければ、表を信用する前に見出しセルのテキストを確認してください。

取得した数値はテキストである

innerText でページから取り出したものはすべて文字列で、そのサイトを読む人向けの書式になっています。ドイツのサイトなら 1.234,56 €、フランスのサイトなら 1 234,56 €、アメリカのサイトなら $1,234.56、日本のサイトなら 1,234円 といった具合です。テキストのままセルに書き込んでも合計できません。CDbl や Val で変換すると、ユーザーの地域設定によって、間違った数値になるかエラーになります。日本の PC でも、ヨーロッパのサイトを読めば、あるいはドイツやフランスの同僚の PC で実行すれば、この問題にぶつかります。

変換は、ユーザーの書式ではなく サイトの 書式に合わせて行います。通貨記号と桁区切り記号を取り除き、小数点の記号をピリオドにしてから Val を使います。

Function ParseScraped(ByVal s As String, ByVal thousandsSep As String, ByVal decimalSep As String) As Variant
    s = Replace(s, ChrW(160), "")          ' ノーブレークスペース
    s = Replace(s, ChrW(8239), "")         ' 幅の狭いノーブレークスペース
    s = Replace(s, " ", "")
    s = Replace(s, ChrW(8364), ""): s = Replace(s, "$", "")   ' ユーロ記号
    If thousandsSep <> "" Then s = Replace(s, thousandsSep, "")
    s = Replace(s, decimalSep, ".")
    If s Like "*[!0-9.-]*" Or s = "" Then ParseScraped = CVErr(xlErrValue) Else ParseScraped = Val(s)
End Function

v = ParseScraped(cellText, ".", ",")   ' ドイツのサイトの "1.234,56" -> 1234.56

二つのノーブレークスペースが隠れた落とし穴です。フランスなどヨーロッパのサイトでは、これで桁を区切ることがよくあり、見た目は普通のスペースとまったく同じで、Trim では取り除けません。貼り付けたデータに同じ文字が混じる場合については VBA の Trim を参照してください。

meta charset による文字化け

responseText は、サーバーの HTTP ヘッダーにある文字セットを使ってページをデコードします。古いサイトの多くは、文字コードを HTML の中 で <meta charset> タグによってのみ宣言しており、XMLHTTP はこのタグを読みません。ブラウザーでは問題なく見えるページが、VBA には é の代わりに é として、あるいは日本語のテキストの代わりに四角として届きます。shift_jis を <meta charset> でしか宣言していない日本語のサイトは、まさにこのケースです。

ソースに <meta charset="windows-1252"> や <meta charset="shift_jis"> のタグがあり、テキストが文字化けしているなら、VBA の HTTP リクエスト の ADODB.Stream を使う関数で http.responseBody をその文字セットでデコードし、結果を doc.body.innerHTML に渡してください。

Power Query と、礼儀正しいスクレイピング

更新したい静的な HTML の表なら、Excel にはすでにスクレイパーがあります。データ > Web から(Power Query)はページ上の表を一覧にし、選んだ表を読み込み、VBA なしでクリック一つで更新できます。サーバーの HTML を読む点は同じなので限界も同じですが、うまくいく場合は保守するコードが少なくて済みます。VBA を使うのは、ロジックが必要なときです。URL の一覧、ログイン、複数ページの結合などです。

そして、礼儀正しくスクレイピングしてください。1 ページにつきリクエストは 1 回、ページの間には待ち時間を入れ(VBA の Wait を参照)、取得済みのものは再ダウンロードせず、最初にサイトの利用規約と robots.txt を確認します。1 秒に 100 回リクエストを送るマクロはオフィスの IP アドレスをブロックさせ、そうなれば誰のマクロも動かなくなります。

判断の分かれ目:スクレイピングは誰も署名していない契約

API は約束です。提供者がドキュメントを書き、壊さないように努めます。Web ページは何も約束しません。デザイナーは明日にも表を追加し、クラス名を変え、価格を JavaScript に移すことができ、そのときマクロはエラーも出さずに壊れるか、もっと悪いことに間違った列を読みます。

だから、手に入るなかでいちばん安定したデータ源を選んでください。まず公式の API、次にページの裏にある JSON リクエスト、次に静的な表に対する Power Query、次に XMLHTTP と htmlfile、そしてブラウザーの自動操作は最後です。 どれを選ぶにしても、スクレイパーには書き込む前に見つけたもの(見出しのテキスト、行数)を確認させてください。そうすれば、リニューアルは間違った数値ではなくエラーを生みます。

ExcelMaster の活用

スクレイパーは静かに壊れます。レイアウトが変わる、数値が別の国の書式で返ってくる、テキストが文字化けして届く。

ExcelMaster はコードを書く前にサーバーが実際に返すものを確認し、JavaScript のページの裏にあるデータリクエストを探し、取得した数値をサイトの書式に合わせて変換するので、シートには本物の数値として届きます。

よくある質問

VBA で Web サイトのデータを Excel にスクレイピングするには?

MSXML2.XMLHTTP.6.0 でページをダウンロードし、responseText を CreateObject("htmlfile") に読み込み、getElementsByTagName("table") で表を見つけ、各セルの innerText を配列に読み込んで、その配列をシートに書き込みます。

ページ上に見えているデータを VBA のスクレイパーが見つけられないのはなぜですか?

そのデータは、ページの読み込み後に JavaScript が組み立てているので、VBA がダウンロードする HTML には入っていないからです。ブラウザーの ネットワーク タブで JSON リクエストを見つけ、それを直接呼び出してください。

VBA の Web スクレイピングに今でも Internet Explorer は使えますか?

おすすめしません。Internet Explorer は 2022 年 6 月にサポートが終了し、もうサポートされていません。静的なページには XMLHTTP と htmlfile を、動的なページにはそのページの JSON リクエストを使ってください。

取得した数値が Excel で数値にならないのはなぜですか?

innerText は常にテキストを返し、その書式はサイトの国に合わせたものだからです。通貨記号と、ノーブレークスペースを含む桁区切り記号を取り除き、小数点の記号をピリオドに変えてから Val で変換してください。

Web スクレイピングには VBA より Power Query のほうが良いですか?

更新したい静的な表なら、そのとおりです。データ > Web から ならコードは要りません。多数のページをループする、ログインする、リクエストの間にロジックを挟む、といった必要があるときに VBA を使ってください。

検証環境

検証環境: Excel 365 (Windows 11)、VBA 7.1 — 最終確認 2026-10-05。

関連ガイド: VBA の HTTP リクエスト · VBA の JSON 解析 · VBA の Trim 関数 · VBA の Wait · VBA の 2 次元配列 · VBA の Replace 関数 · VBA の Like 演算子 · VBA の CreateObject