「SeleniumのスクレイピングコードをPlaywrightに移行したら動かなくなった」——2026年8月時点でこの相談が増えている。Selenium 4.47(2026年8月10日リリース)とPlaywright 1.62(2026年7月リリース、約6週間サイクル)の仕様差が広がり、単純な書き換えでは待機処理とproxy設定の2箇所で必ずつまずく。本記事ではその2箇所に絞り、実際にどこをどう直せば動くようになるかをコード付きで解説する。

なぜ今Seleniumから移行する人が増えているのか

Selenium側では2026年7月11日リリースの4.46でJSONパーサーがRFC 8259準拠に強化されBiDiクラスがベータ化、8月10日リリースの4.47ではPythonバインディングでFirefoxのCDP(Chrome DevTools Protocol)アクセスがブロックされるなど、内部構造の変更が続いている。一方Playwrightはネイティブブラウザバイナリを直接操作するためChromeDriverのようなパスエラーが起きず、自動待機・高速実行・Trace Viewerといった運用面の強みが現場で評価されている。バージョン追従コストの差が、移行を後押しする最大の理由になっている。

書き換えポイント1:自動待機(auto-wait)の設計

Seleniumの明示的待機をそのまま持ち込むと壊れる

Seleniumでは要素の出現・クリック可能状態を自分で待つのが基本だった。

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

element = WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((By.CSS_SELECTOR, ".product-price"))
)
element.click()

Playwrightのlocatorはクリック前に「表示されている」「操作可能」「アニメーションが終わっている」などを自動でチェックしてから操作する。上のコードをそのまま`page.click()`だけに置き換えると、待機処理が二重になったり逆に待たずにタイムアウトすることがある。

from playwright.sync_api import sync_playwright

page.locator(".product-price").click()
# 特定条件まで待ちたい場合はwait_for_function()を使う
page.wait_for_function("() => document.querySelector('.product-price').innerText !== ''")

`wait_for_function()`はPlaywright 1.62で追加された比較的新しいAPIで、DOM側の状態変化を待つ用途に向く。Selenium時代の`WebDriverWait`+`expected_conditions`の組み合わせをすべて`wait_for_function()`かlocatorの自動待機に置き換えるのが移行時の基本方針になる。

暗黙的待機(implicit_wait)は概念ごと存在しない

Seleniumの`driver.implicitly_wait(10)`に相当するグローバル設定はPlaywrightにはない。移行時にこの行をコメントアウトしただけで放置すると、遅い要素だけタイムアウトするようになる。`page.set_default_timeout()`でページ単位のタイムアウトを設定し直す必要がある。

書き換えポイント2:proxy設定の書き方が根本的に違う

Seleniumはドライバ起動時にCapabilities経由でproxyを渡す方式で、ブラウザ全体に対して1つの設定しか持てないことが多い。

項目

Selenium

Playwright

設定単位

ドライバ(ブラウザ)全体

ブラウザ起動時 or コンテキスト単位

複数proxyの切り替え

ドライバの再起動が必要

`browser.new_context(proxy=...)`で並行実行可能

認証付きproxy

拡張機能や別ライブラリで回避することが多い

`proxy`辞書に`username`/`password`をそのまま渡せる

# Selenium: Optionsにproxyを渡す
from selenium.webdriver.common.proxy import Proxy, ProxyType
proxy = Proxy()
proxy.proxy_type = ProxyType.MANUAL
proxy.http_proxy = "user:pass@proxyhost:8080"
options.proxy = proxy
# Playwright: コンテキスト単位でproxyを分離できる
browser = p.chromium.launch()
context = browser.new_context(
    proxy={
        "server": "http://proxyhost:8080",
        "username": "user",
        "password": "pass",
    }
)

Playwrightはコンテキスト単位でproxyを持てるため、1つのブラウザプロセスから複数のproxyを並行運用できる。Selenium時代に「proxyを切り替えるたびにドライバごと再起動していた」処理を移行時に見直すと、実行速度が大きく改善するケースが多い。

アンチボット側の検知精度も同時に上がっている

移行作業と同時に押さえておくべきなのが、検知側の進化だ。CloudflareはAIクローラーを「Search」「Agent」「Training」の3種類に分類する仕組みを2026年7月1日から全顧客に提供しており、2026年9月15日以降は新規ドメインの広告表示ページで「Training」「Agent」に分類されたボットがデフォルトでブロックされる。DataDomeは2026年7月23日、320万のユニークIPから1880万回に及ぶチケット転売スクレイピングを検知・遮断したと報告している。

これらのTier-1アンチボットは行動バイオメトリクス・JA4+ TLSフィンガープリンティング・ブラウザエンジンの整合性チェックまで見ており、SeleniumかPlaywrightかというツール選択だけでは回避できない。CloudflareのUA偽装ブロック対策2026年8月版Playwright Turnstile回避の実測【26年8月】で実測した通り、自動待機やproxy設定を正しく書き換えたうえで、検知回避の設計は別レイヤーとして組む必要がある。

移行前に確認すべき規約・法令面のチェックリスト

  • 対象サイトのrobots.txtと利用規約に、自動アクセス・データ収集を明示的に禁止する条項がないか
  • 取得データに個人情報が含まれる場合、個人情報保護法の第三者提供・利用目的の制限に抵触しないか
  • 取得したデータを商用利用する場合、著作権法の複製権・公衆送信権との関係を整理しているか
  • 競合サイトの非公開情報を大量取得する場合、不正競争防止法上の「営業秘密」侵害に該当しないか

2026年8月時点で日本国内におけるスクレイピング特化の新たな法規制・判例は確認されていないが、既存の著作権法・個人情報保護法・不正競争防止法と各サイトの利用規約を個別に確認する原則は変わらない。ツールの書き換え作業よりも、この確認作業に時間がかかるケースが実務では多い。

それでも自前対応が大変な理由

ここまでの書き換えは一見「置換すれば終わり」に見えるが、実際にはSelenium 4.46/4.47のBiDi関連変更、Playwright 1.62の新APIへの追従、Cloudflare・DataDomeの検知アップデートへの追従が同時並行で発生する。Chrome自体も2026年8月6日リリースのバージョン151.0.7922.108/.109で41件(うちCritical 6件)の脆弱性修正が入っており、ブラウザ側の更新がスクレイピングコードの挙動に影響することもある。バージョン追従と規約確認を継続的に行う体制がないまま個人で運用すると、気づかないうちにコードが動かなくなる、あるいは規約違反のリスクを抱えたまま放置する事態になりやすい。

まとめ

SeleniumからPlaywrightへの移行で必ず書き換えが必要なのは、自動待機処理(WebDriverWait→locatorの自動待機・wait_for_function)とproxy設定(ドライバ全体→コンテキスト単位)の2箇所だ。同時に、Cloudflareのボット分類変更(2026年9月15日〜)やDataDomeの検知強化など、アンチボット側も進化を続けている。ツールの書き換えと検知回避、規約・法令の確認を継続的に行う運用体制まで含めて設計することが、移行を一度きりの作業で終わらせない鍵になる。