Excelでの集計やレポート作成が当たり前になった現場ほど、「データ取得だけが手作業」のボトルネックが残りがちです。Webシステムから数字を拾って、Excelに貼って、整形して…という流れを毎日・毎週繰り返していると、どこかでミスも起きます。そこで候補に上がるのが、VBAでChromeを操作して必要な情報を取得する“ブラウザ操作型スクレイピング”です。
ただし、Chrome操作は「コードを書けば終わり」ではありません。環境依存(バージョン差・社内PC制限・プロキシ・MFA)で詰まりやすく、運用設計が甘いとすぐ壊れます。この記事では、環境設定の考え方と、実務で壊れにくいサンプルコードの“型”をまとめます。
目次
- ✅ まず押さえる:VBA×Chrome操作の現実と前提
- ・VBAでのWeb取得は大きく2系統
- ✅ 環境設定:動く状態を“固定”するのが最優先
- ・最低限そろえるもの(考え方)
- ・運用が壊れない配置の基本
- ✅ 実務で壊れにくい設計のコツ:待機と例外を先に設計する
- ・待機の基本方針
- ・ログ(最低限)
- ✅ サンプル:Chromeを起動し、一覧テーブルから値を取得する
- ・なぜこの構成か(設計意図)
- ✅ 実装:Driverパスを相対で固定し、生成と終了を堅くする
- ・別案とのメリット差
- ✅ 待機の型:Sleepではなく“要素が出たか”で待つ
- ✅ データ取得:行を“文字列で返す”ところから始める
- ✅ 実務で詰まりやすいポイントと回避策
- ・Chrome更新で突然動かない
- ・待機が不安定で落ちる
- ・HTMLが変わって取れない
- ✅ 応用:ログインや複雑ページは“自動化範囲”を区切る
- ・現実的な落とし所の例
- ✅ まとめ:Chrome操作スクレイピングは環境と待機が8割
✅ まず押さえる:VBA×Chrome操作の現実と前提
Chrome操作をVBAでやると聞くと、「Webページを開いてクリックして、値を取る」だけに見えますが、実務ではそこが一番簡単です。詰まるのは、環境・権限・更新頻度・待機の設計です。特にChromeは自動更新されやすく、昨日動いたものが今日止まることがあります。さらに、ログインが絡むとMFAやCAPTCHAで“自動化できない仕様”にぶつかることもあります。だから最初に決めるべきは、テクニックではなく「どこまでを自動化対象にするか」です。対象を誤ると、作ったマクロが資産ではなく負債になります。まずは前提を揃えたうえで、現実的に回る設計に寄せていきましょう。
・VBAでのWeb取得は大きく2系統
- ブラウザ操作型(Chromeを実際に動かす):ログイン後の画面、JavaScriptで生成される表などに強い
- HTTP取得型(XMLHTTP等でHTMLを取る):静的ページやAPI寄りの取得に強い(軽い・速い・壊れにくい)
この記事は「Chromeを動かす」前提で進めつつ、最後に「ブラウザを動かさず済むならそちらが堅い」判断も添えます。
✅ 環境設定:動く状態を“固定”するのが最優先
環境設定で重要なのは「インストール手順」そのものではなく、動作条件を固定して再現できる状態にすることです。Chrome操作はWebDriver(ChromeDriver)に依存し、ブラウザ更新とズレると動かなくなります。つまり、運用で壊れる原因の多くはコードではなく“バージョン差”です。ここを曖昧にしたまま配布すると、他PCで再現しません。さらに社内PCだと、管理者権限・セキュリティソフト・プロキシで導入が止まることもあります。だから実務では「導入の簡単さ」より「運用で壊れない形」を優先します。以下は、その前提での設定観点です。
・最低限そろえるもの(考え方)
- Chrome(既に入っていることが多い)
- ChromeDriver(Chromeと整合する版)
- VBAからWebDriverを操作するためのライブラリ(Selenium系のVBAバインディング等)
- 配置ルール(どこにDriverを置くか、パスをどう扱うか)
・運用が壊れない配置の基本
- PCごとのDownloadsに置かない(人によって場所がバラける)
- ブックと同じフォルダ配下に固定する(配布・移行がラク)
- Driverのパスをコードで組み立てる(環境差に強くなる)
✅ 実務で壊れにくい設計のコツ:待機と例外を先に設計する
Chrome操作の失敗原因は、クリックや取得の書き方よりも「待機が甘い」ことがほとんどです。画面の読み込みはネットワーク・PC性能・サイト側負荷で揺れます。固定のSleepを入れても、速い日はムダに遅く、遅い日は間に合わず失敗します。結果、再実行や手作業が混ざり、現場では使われなくなります。だから、待機は“時間”ではなく“状態”で判定する方が安定します。さらに、失敗したときに原因が追えないと運用不能になります。ここを先に固めるだけで、同じコードでも実務耐久が変わります。
・待機の基本方針
- 原則:要素が出るまで待つ(クリック対象・取得対象)
- タイムアウトを必ず設ける(永久待ちを防ぐ)
- リトライは回数を固定(無限ループにしない)
・ログ(最低限)
- いつ、どのURLで、どの要素待ちで落ちたか
- 取れた件数/0件だったか
- エラー内容(Err.Number / Err.Description)
✅ サンプル:Chromeを起動し、一覧テーブルから値を取得する
サンプルは「ログインなし」「テーブルから行を拾う」だけに絞ります。実務でログインが必要な場合でも、まずは“取得の型”を固めてからログインに拡張した方が安全です。いきなりログイン+遷移+取得を全部盛ると、どこが原因で落ちたか分からなくなります。実務では切り分け可能な粒度で作るほど、保守がラクです。ここでは、コードを一発芸にせず、再利用できる関数構成にします。ブック配布を想定し、Driverパスも相対で組み立てます。最後に、別案(待機のやり方)も併記します。
前提:VBAからWebDriverを操作できる参照設定(Selenium系ライブラリなど)が済んでいる想定です。
※ライブラリ名や参照名は環境で異なるため、ここでは「設計と型」を重視して書きます。
Option Explicit
'========================
' エントリーポイント
'========================
Public Sub Scrape_SampleTable()
Dim driver As Object
Dim targetUrl As String
Dim rows As Collection
Dim i As Long
targetUrl = "https://example.com/list" ' サンプルURL(置き換え前提)
On Error GoTo EH
Set driver = CreateChromeDriver(GetDriverPath())
driver.Get targetUrl
' 「テーブルが描画されるまで」待つ(状態待機)
WaitForElement driver, "css=table.data tbody tr", 15
Set rows = GetTableRows(driver, "css=table.data tbody tr")
If rows.Count = 0 Then
Debug.Print "取得0件:URL=" & targetUrl
GoTo FIN
End If
For i = 1 To rows.Count
Debug.Print rows(i) ' ここでは取得した文字列を出力(必要に応じてシートへ)
Next
FIN:
SafeQuitDriver driver
Exit Sub
EH:
Debug.Print "エラー:" & Err.Number & " / " & Err.Description & " / URL=" & targetUrl
SafeQuitDriver driver
End Sub
・なぜこの構成か(設計意図)
- Driver生成・待機・取得・終了を分離して、トラブル箇所を特定しやすくしています。
- 実務で一番多い失敗(待機不足)を、
WaitForElementに集約して“型”で解決します。 SafeQuitDriverを必ず通すことで、Chromeが裏で増殖する事故を防ぎます(運用で超重要)。
Chrome操作のスクレイピングでは、
ページの描画やJavaScriptの実行が終わる前に次の処理へ進んでしまい、
「昨日は動いたのに今日は落ちる」といった不安定さが起きがちです。
単なる Sleep ではなく、
処理が完了したタイミングを正しく待つ設計を理解しておくと、
スクレイピングの安定性は大きく変わります。
VBAでの待機・同期制御の考え方と実務での使い分けは、
以下の記事で詳しく整理しています。
→ 【VBA】処理が終わってから次の処理を実行する方法|DoEvents・待機・同期制御の基本と実例
✅ 実装:Driverパスを相対で固定し、生成と終了を堅くする
ここを適当にすると「自分のPCでは動く」止まりになります。配布・引き継ぎ・PC交換が発生した時点で破綻します。実務での価値は、動くことより“同じ状態を再現できること”です。特にDriverの置き場所がバラバラだと、問い合わせ対応に時間が溶けます。だから、ブックと同階層に \tools\chromedriver\ のような固定ルールを作るのが安全です。さらに終了処理が漏れると、Chromeプロセスが残ってPCが重くなりクレームになります。運用を想定すると、ここが最重要の土台です。
Private Function GetDriverPath() As String
' このブックと同じフォルダ配下にDriverを置く想定
' 例:<ブックフォルダ>\tools\chromedriver\chromedriver.exe
Dim baseDir As String
baseDir = ThisWorkbook.Path
GetDriverPath = baseDir & "\tools\chromedriver\chromedriver.exe"
End Function
Private Function CreateChromeDriver(ByVal driverPath As String) As Object
' 環境により生成方法は異なるため、ここは「生成を1か所に閉じる」のがポイント
' 例:Selenium系なら ChromeOptions を渡す、Service を作る等に発展させられる
Dim drv As Object
' ここは利用ライブラリに合わせて置換してください
' Set drv = New ChromeDriver
' drv.SetCapability "webdriver.chrome.driver", driverPath
Set drv = CreateObject("Selenium.ChromeDriver") ' 例(環境差あり)
drv.AddArgument "--disable-gpu"
drv.AddArgument "--no-sandbox"
drv.Start "chrome", driverPath
Set CreateChromeDriver = drv
End Function
Private Sub SafeQuitDriver(ByVal driver As Object)
On Error Resume Next
If Not driver Is Nothing Then
driver.Quit
End If
On Error GoTo 0
End Sub
・別案とのメリット差
- べた書きで
driver.Startしてdriver.Quitを書くより、生成・終了を関数化した方が流用しやすいです。 - 将来「ヘッドレス」「ダウンロード設定」「プロファイル指定」等を入れたくなったときも、変更箇所が
CreateChromeDriverに閉じます。
✅ 待機の型:Sleepではなく“要素が出たか”で待つ
待機はスクレイピングの品質を決めます。固定Sleepは、環境が少し変わるだけで崩れます。実務ではサイトが重い日もあれば軽い日もありますし、社内ネットワークの遅延もあります。見た目が表示されていても、クリックできる状態になっていないこともあります。だから「要素が存在するまで待つ」「タイムアウトしたら失敗として扱う」という型が必要です。これを共通関数にしておくと、全ての処理が安定します。ここをケチると、結局“手動確認”が必要になり自動化の意味が消えます。
Private Sub WaitForElement(ByVal driver As Object, ByVal selector As String, ByVal timeoutSec As Long)
Dim startTime As Single
startTime = Timer
Do
If ExistsElement(driver, selector) Then Exit Sub
DoEvents
If Timer - startTime > timeoutSec Then
Err.Raise vbObjectError + 1000, "WaitForElement", "タイムアウト:" & selector
End If
Loop
End Sub
Private Function ExistsElement(ByVal driver As Object, ByVal selector As String) As Boolean
On Error GoTo EH
' 例:selector形式 "css=..." を想定(運用時に統一すると保守がラク)
Dim byCss As String
byCss = Replace(selector, "css=", vbNullString)
Dim el As Object
Set el = driver.FindElementByCss(byCss)
ExistsElement = Not (el Is Nothing)
Exit Function
EH:
ExistsElement = False
End Function
✅ データ取得:行を“文字列で返す”ところから始める
いきなりセルに書くと、途中で落ちたときに「どこまで取れたか」が曖昧になります。まずは取得結果をコレクションで返し、呼び出し側で出力先(Debug/Sheet/CSV)を決める方が再利用しやすいです。実務では取得先が変わることがよくあります(別シート、別ブック、DB、CSVなど)。取得関数が“出力まで面倒を見る”と流用しづらくなります。また、HTML構造は変わるので、セレクタは1か所に寄せるのが安全です。最初は「1行=1レコード」のシンプルな形で十分です。安定してから列分解や型変換を足していきましょう。
Private Function GetTableRows(ByVal driver As Object, ByVal rowSelector As String) As Collection
Dim results As New Collection
Dim byCss As String
byCss = Replace(rowSelector, "css=", vbNullString)
Dim elements As Object
Set elements = driver.FindElementsByCss(byCss)
Dim i As Long
For i = 1 To elements.Count
results.Add Trim$(elements(i).Text)
Next
Set GetTableRows = results
End Function
✅ 実務で詰まりやすいポイントと回避策
Chrome操作は、動かすだけなら簡単でも、運用で詰まるポイントが決まっています。たとえばログインが絡むと、MFAやワンタイムコードで“人間の操作”が必須になることがあります。規約や社内監査の観点で、自動ログインが禁止されるケースもあります。また、サイト側のHTMLが少し変わるだけで、セレクタが壊れます。さらに、取得データが0件でも“正常”な日があるなら、0件をエラー扱いすると運用が回りません。こうした現場都合をコード設計に反映しないと、結局「手作業+マクロ」の中途半端になります。ここでは、先に潰しておくべき論点を整理します。
・Chrome更新で突然動かない
- DriverとChromeの整合が崩れるのが典型原因です
- 対策:Driverをブック配下に固定し、更新手順(誰が、いつ、どう差し替えるか)を決める
・待機が不安定で落ちる
- 対策:Sleepではなく
WaitForElementのような“状態待機”に統一 - タイムアウトしたら、URL・セレクタ・時間をログに残す
・HTMLが変わって取れない
- 対策:セレクタをコード内に散らさず、定数や関数に寄せる
- 「取得できない=即バグ」ではなく、サイト変更の可能性を前提にする
✅ 応用:ログインや複雑ページは“自動化範囲”を区切る
ここから先は、テクニックより判断の話が重要です。ログインが必要な業務ほど自動化したくなりますが、MFAやCAPTCHAがあると「自動化できないこと」があります。無理に突破しようとすると、運用が危険になったり、規約違反・監査NGにつながります。実務では、ログインは人が行い、その後の繰り返し作業だけ自動化する、という分割が現実的なことも多いです。たとえば「ログイン後の一覧ページへ遷移したらボタン1つで取得」なら、効果は十分出ます。全部自動化できなくても、ボトルネックが減れば勝ちです。自動化は“完璧”より“安定して回る”を優先しましょう。
・現実的な落とし所の例
- ログインは手動(最初の1回) → 取得・転記・整形は自動
- 取得は自動 → 最終チェックと送信は人(責任分界)
✅ まとめ:Chrome操作スクレイピングは環境と待機が8割
- Chrome操作は「コード」より「環境固定」と「待機設計」が重要
- Driverの配置は相対パスで統一し、配布・更新の運用を作る
- Sleep頼みをやめ、要素の出現を待つ“状態待機”にする
- 取得ロジックは「取得」と「出力」を分離して再利用性を上げる
- ログインや監査が絡む場合は、自動化範囲を区切って運用を成立させる
Chromeスクレイピングは、うまく設計すると「毎日の手作業」を確実に減らせます。逆に、環境や待機を軽視すると、壊れて直す時間の方が増えます。まずは小さく安定させ、型を固めてから拡張していくのが、実務で成功しやすい進め方です。