paint-brush
Playwright: ブラウザ自動化ツールの最初のステップ@nfrankel
338 測定値
338 測定値

Playwright: ブラウザ自動化ツールの最初のステップ

Nicolas Fränkel7m2025/01/26
Read on Terminal Reader

長すぎる; 読むには

一部のメディアでは、必要なメトリクス用の HTTP API が提供されていません。Playwright は、Python を含むいくつかの言語 API を備えたブラウザ自動化ツールです。同期 API と非同期 API の 2 つの異なる API を提供します。
featured image - Playwright: ブラウザ自動化ツールの最初のステップ
Nicolas Fränkel HackerNoon profile picture

以前の会社では、Twitter、LinkedIn、Mastodon、Bluesky、Reddit などのソーシャル メディア全体のメトリクスを追跡するバッチ ジョブを開発しました。その後、自分の「ペルソナ」用にそれを複製できることに気付きました。問題は、一部のメディアが、必要なメトリクス用の HTTP API を提供していないことです。LinkedIn で必要なメトリクスは次のとおりです。


LinkedIn メトリクスダッシュボード


長い間検索しましたが、上記のメトリクスへの API アクセスは見つかりませんでした。長い間、毎朝手動でメトリクスをスクレイピングしていましたが、最終的にこの面倒な作業を自動化することにしました。そこで学んだことは次のとおりです。

背景

この仕事は Python で行われるため、同じ技術スタックを維持したいと考えています。簡単に調べた後、Python を含むいくつかの言語 API を備えたブラウザ自動化ツールであるPlaywright を見つけました。Playwright の主な使用例はエンドツーエンドのテストですが、テストコンテキスト外でブラウザを管理することもできます。


私は依存関係を管理するために Poetry を使用しています。Playwright のインストールは次のように簡単です:


 poetry add playwright


この時点で、Playwright は使用できる状態になっています。Playwright は、同期 API非同期 APIの 2 つの異なる API を提供しています。私の使用例では、最初の API で十分です。

足を濡らす

私は開発に段階的にアプローチするのが好きです。


以下は API の抜粋です:


APIモデルからの抜粋


これは次のコードに変換されます。


 from playwright.sync_api import Browser, Locator, Page, sync_playwright with (sync_playwright() as pw): #1 browser: Browser = pw.chromium.launch() #2 page: Page = browser.new_page() #3 page.goto('https://www.linkedin.com/login') #4 page.locator('#username').press_sequentially(getenv('LINKEDIN_USERNAME')) #5 page.locator('#password').press_sequentially(getenv('LINKEDIN_PASSWORD')) #5 page.locator('button[type=submit]').press('Enter') #6 page.goto('https://www.linkedin.com/dashboard/') #4 metrics_container: Locator = page.locator('.pcd-analytic-view-items-container') metrics: List[Locator] = metrics_container.locator('p.text-body-large-bold').all() #7 impressions = atoi(metrics[0].inner_text()) #8 # Get other metrics browser.close() #9
  1. playwrightオブジェクトを取得します。


  2. ブラウザ インスタンスを起動します。複数のブラウザ タイプが利用可能ですが、私は気まぐれで Chromium を選択しました。特定のブラウザを事前にインストールしておく必要があることに注意してください(例: playwright install --with-deps chromium


    デフォルトでは、ブラウザはヘッドレスで開き、表示されません。デバッグを容易にするために、最初は表示して実行することをお勧めします: headless = True


  3. 新しいブラウザウィンドウを開きます。


  4. 新しい場所に移動します。


  5. 指定された入力フィールドを見つけて、資格情報を入力します。


  6. 指定されたボタンを見つけて押します。


  7. 指定されたすべての要素を検索します。


  8. 最初の要素の内部テキストを取得します。


  9. クリーンアップするにはブラウザを閉じます。

クッキーの保存

上記は期待通りに動作しました。唯一の欠点は、スクリプトを実行するたびに LinkedIn からメールが届いたことです。


こんにちは、ニコラス。


<city>、<region>、<country> の新しいデバイス HeadlessChrome、<OS>で「Remember me」を正常に有効化しました。デバイスで「Remember me」がどのように機能するかについて詳しくは、こちらをご覧ください。


JavaCroカンファレンスではFabien Vauchellesにも会いました。彼は Web スクレイピングを専門としており、この分野のほとんどの人がブラウザ プロファイルを活用していると教えてくれました。実際、LinkedIn にログインすると、認証トークンが Cookie として保存され、期限が切れるまで再度認証する必要はありません。幸い、Playwright はlaunch_persistent_contextメソッドでそのような機能を提供しています。


上記のlaunch次のように置き換えることができます。


 with sync_playwright() as pw: playwright_profile_dir = f'{Path.home()}/.social-metrics/playwright-profile' context: BrowserContext = pw.chromium.launch_persistent_context(playwright_profile_dir) #1 try: #2 page: Page = context.new_page() #3 page.goto('https://www.linkedin.com/dashboard/') #4 if 'session_redirect' in page.url: #4 page.locator('#username').press_sequentially(getenv('LINKEDIN_USERNAME')) page.locator('#password').press_sequentially(getenv('LINKEDIN_PASSWORD')) page.locator('button[type=submit]').press('Enter') page.goto('https://www.linkedin.com/dashboard/') metrics_container: Locator = page.locator('.pcd-analytic-view-items-container') # Same as in the previous snippet except Exception as e: #2 logger.error(f'Could not fetch metrics: {e}') finally: #5 context.close()
  1. Playwright は指定されたフォルダーにプロファイルを保存し、実行ごとに再利用します。


  2. 例外処理を改善します。


  3. BrowserContextページを開くこともできます。


  4. ダッシュボードに移動しようとします。認証されていない場合は LinkedIn によってログイン ページにリダイレクトされ、その後認証できるようになります。


  5. 結果がどうであれ、コンテキストを閉じます。


この時点では、最初に両方の資格情報を使用して認証するだけで済みます。その後の実行では、状況によって異なります。

現実に適応する

上記のコードが確実に動作しないことに驚きました。最初の実行では動作し、その後の実行ではときどき動作しました。実行をまたいでブラウザ プロファイルを保存しているため、認証が必要な場合、LinkedIn はログインではなくパスワードのみを要求します。コードはログインを入力しようとするため、この場合は失敗します。修正は非常に簡単です。


 username_field = page.locator('#username') if username_field.is_visible(): username_field.press_sequentially(getenv('LINKEDIN_USERNAME')) page.locator('#password').press_sequentially(getenv('LINKEDIN_PASSWORD'))

結論

私は Python の専門家ではありませんが、Playwright で望みどおりの成果を上げることができました。同期 API を使うことを選んだのは、コードが少し理解しやすくなり、パフォーマンス要件もなかったからです。使用したのは Playwright が提供する基本機能だけです。Playwright ではテストのコンテキストでビデオを録画できます。これは、CI パイプラインの実行中にテストが失敗した場合に非常に便利です。


さらに進むには:



2024年1月19日にA Java Geekで最初に公開されました