PlaywrightでSelenium Gridに接続してスクレイピングするには?
小規模なスクレイピングであればご自身のコンピュータ上で行えば事足りますが、継続的なスクレイピング または 大規模なスクレイピングを実施する場合にはVPS等の外部のコンピュータに仕事を任せたいところです。また、同時にいくつかのサイトをスクレイピングしたいことでしょう。
そこで、Selenium Gridの登場です。
Playwrightからスクレイピングの指示を出し、実際のスクレイピング作業はSelenium経由で外部のChromeブラウザにお任せするということができます。
Selenium Gridとは?
Selenium Gridはスクレイピングの作業ノードを集約・接続できるツールです。
利用する際はたった一つのURL(Selenium Grid)に指示を投げるだけで、作業ノードを割り当ててくれて、それぞれ個別の作業をさせることができるようになります。自分で接続先を変更する必要がありませんから、規模の大きなスクレイピングが脳死でできるようになります。
また、Selenium4 から Dynamic Grid という最強機能が備わりました。
Dynamic Gridは、作業ノードを必要に応じて自動的に増やしたり破棄したりしてくれます。一度マシンを接続設定しておけばノード数の管理する必要がなくなりました。
▼Playwright と Selenium の役割の整理
Playwright
ブラウザのリモート操作指示とデータ解析などを担う。
Selenium(Dynamic Grid)
リモートブラウザとして、Playwrightから指示された仕事を代理で行う。
Dynamic Gridではノードを流動的に立ち上げたり、捨てたりを自動的にやってくれます。
▼ Playwrightの公式ドキュメント
Selenium Gridの環境を準備する
大まかな流れ
- 必要なファイル群をダウンロードする。
 - docker-compose-v3-dynamic-grid.ymlを編集してファイル名を変更する。
 - Dockerコンテナを立ち上げる。
 - ブラウザでSelenium Gridを表示する。
 
それではやっていきましょう。
1. 必要なファイル群をダウンロードする。
こちらのリポジトリをcloneするか、zip形式でダウンロードしてください。
ダウンロードした内容は展開しておきましょう。
ダウンロードした中身の内、必要なものは下記の通りです。
- NodeDockerフォルダ
 - docker-compose-v3-dynamic-grid.yml
 
これらをご自身のスクレイピングのプロジェクトにコピーしておきましょう。
2. docker-compose-v3-dynamic-grid.ymlを編集してファイル名を変更する。
docker-compose-v3-dynamic-grid.yml の記述のうち、
node-dockerサービスの環境変数として下記のような記述をしておきましょう。
version: "3"
services:
  node-docker:
    image: selenium/node-docker:4.17.0-20240123
    volumes:
      - ./assets:/opt/selenium/assets
      - ./NodeDocker/config.toml:/opt/bin/config.toml
      - /var/run/docker.sock:/var/run/docker.sock
    depends_on:
      - selenium-hub
    environment:
      - SE_EVENT_BUS_HOST=selenium-hub
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
      - SE_NODE_GRID_URL=http://localhost:4444
  selenium-hub:
    image: selenium/hub:4.17.0-20240123
    container_name: selenium-hub
    ports:
      - "4442:4442"
      - "4443:4443"
      - "4444:4444"
追記したのは - SE_NODE_GRID_URL=http://localhost:4444 この行です。
この記述が無いと、Chromedriverと呼ばれるWebDriverでChromeDevTools(CDT)の操作ができない(?)ため、WebSocketの確立エラーが発生するようです。
Playwrightからリモート操作する際に必要な記述ですので、忘れずに追記しておきましょう。
そして、 docker-compose-v3-dynamic-grid.yml というファイル名を docker-compose.yml というファイル名に変更しておきましょう。Dockerコンテナ立ち上げ時のコマンドを打つ際に、ファイル名を指定する必要がなくなり便利になります。
3.Dockerコンテナを立ち上げる。
ターミナルから下記を叩いてDockerコンテナを立ち上げます。
docker-compose up -d
これでコンテナが2つ立ち上がるはずです。
4. ブラウザでSelenium Gridを表示する。
ブラウザで http://localhost:4444/ にアクセスしてみてください。

こんなページが開き、Selenium Gridの画面と接続中のノードが表示されます!
これでSelenium Gridの準備が完了しました!
PlaywrightでSelenium Gridに接続してスクレイピングを実行する
おおまかな手順
- 
.envファイルを作成して記述する。 - dotenvをインストールする。
 - スクレイピングのコードを書く。
 
 1. .env ファイルを作成して記述する。
スクレイピングのプロジェクトのルートディレクトリに .env ファイルを作成して、下記を記述します。
SELENIUM_REMOTE_URL=http://localhost:4444/
Playwrightでは SELENIUM_REMOTE_URL という環境変数が指定されると、自動的にSelenium Gridに指示を飛ばすような動きをしてくれます。通常のスクレイピングと違うのはただこれだけです。Playwright凄い!!
2. dotenvをインストールする。
環境変数を適用させる必要があるので、dotenvをインストールしておきましょう。
npm install dotenv
3. スクレイピングのコードを書く。
下記のようなコードを書いてみました。
import "dotenv/config";
import { chromium } from "playwright";
(async () => {
  const browser = await chromium.launch({
    headless: false,
  });
  const context = await browser.newContext();
  const page = await context.newPage();
  await page.goto("https://yahoo.co.jp");
  const hoge = await context.newPage();
  // await context.close();
  // await browser.close();
})();
import "dotenv/config"; によって .env ファイルが読み込まれ環境変数が適用されます。
ほかの記述は単純なPlaywrightのスクレイピングのコードです。
最後の行の .close() のコードはわざとコメントアウトしています。というのも、動いているかどうかを目で見るためです。実際にスクレイピングするときはコメントアウトを解除しておく必要があります。
それでは実行してみましょう。
npx ts-node index.ts
で index.tsのスクレイピングコードを実行しました。

Session数が1増えているかと思います。
実際にスクレイピングの画面を確認してみましょう。

カメラのマークをクリックすると、下記画面のようにパスワードが聞かれます。
デフォルトでは secret という文字列がパスワードです。

入力して ACCEPTすると、

こんな感じで Yahoo!JAPANのタブと空タブが開いているはずです!
ホストマシンからDocker仮想マシンに指示が飛ばせていることがお分かり頂けるかと思います!
これでPlaywright + Selenium Grid のスクレイピング環境が整いました。
スクレイピングする際に知っておきたいこと
スクレイピングする前に知っておきたいことを上記記事にまとめました。
割とガチでスクレイピングする際は参考にしてみてください。
また、安定した優良な有料プロキシをお探しの方は WebShare をおすすめします。スクレイピングの際には僕も必ず利用する有料プロキシです。
- Premium Proxy
 - プロキシ数: 100個
 - BandWidth(帯域幅): 250GB
 - Automatic Refresh: No Refreshes
 - On-Demand Refresh: No Refreshes
 
こんな構成でプロキシを用意しても月額2.99ドルで使えます。
この価格は色々比較してきましたが、僕の中では最安値です!
プロキシを通して使いたい!
大規模なスクレイピングを行う場合、プロキシを使うことになるでしょう。
しかし、PlaywrightでSelenium Gridを通してプロキシを通すのはかなり困難です。
Selenium Gridを通さないのであれば下記のようなコードだけでベーシック認証が通ります。
  const browser = await chromium.launch({
    proxy: {
      server: "http://hoge:1234",
      username: "user_name",
      password: "pass_word",
    },
  });
プロキシのホストまではSelenium Gridに渡してくれるのですが、
ユーザー名とパスワードは渡してくれませんでした。
これは args として --proxy-server= や --proxy-auth= を使ったり、 --allow-cross-origin-auth-prompt や --ignore-certificate-errors-spki-list を適用しても解決できません。
ではどうやってプロキシのベーシック認証問題を解決するか?
解決策としては下記の2つあります。
- Chrome拡張機能を動的に生成して認証を通す
 - プロキシサービスのIP認証を設定する
 
前者は結構面倒くさいのと複雑化するので極力避けたいところです。
となると、消去法でIP認証を使うことになりますね。

ぼくが使ってる有料プロキシ「WebShare」にはIP認証機能が備わっています。そして、APIでIPアドレスを作成・削除・リスト読み込みもできます。
VPSなどでスクレイピングするのであれば基本的にIPアドレスは変わらないので手動でIP認証してしまってもいいと思います。ローカル環境が動的IPであれば、WebshareのAPI経由でIPアドレスを登録するようにプログラミングしても良いでしょう。この辺りはご自身の最適な手段を選んでください。
Selenium Gridを使うならIP認証かなり便利なので積極的に使っていきましょう!
IP認証 | Playwright でプロキシを使う例
  const browser = await chromium.launch({
    proxy: {
      server: "http://hoge:port",
    },
  });
記述もすごくシンプルになります。