以前の会社では、Twitter、LinkedIn、Mastodon、Bluesky、Reddit などのソーシャル メディア全体のメトリクスを追跡するバッチ ジョブを開発しました。その後、自分の「ペルソナ」用にそれを複製できることに気付きました。問題は、一部のメディアが、必要なメトリクス用の HTTP API を提供していないことです。LinkedIn で必要なメトリクスは次のとおりです。
長い間検索しましたが、上記のメトリクスへの API アクセスは見つかりませんでした。長い間、毎朝手動でメトリクスをスクレイピングしていましたが、最終的にこの面倒な作業を自動化することにしました。そこで学んだことは次のとおりです。
この仕事は Python で行われるため、同じ技術スタックを維持したいと考えています。簡単に調べた後、Python を含むいくつかの言語 API を備えたブラウザ自動化ツールであるPlaywright を見つけました。Playwright の主な使用例はエンドツーエンドのテストですが、テストコンテキスト外でブラウザを管理することもできます。
私は依存関係を管理するために Poetry を使用しています。Playwright のインストールは次のように簡単です:
poetry add playwright
この時点で、Playwright は使用できる状態になっています。Playwright は、同期 APIと非同期 APIの 2 つの異なる 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
playwright
オブジェクトを取得します。
ブラウザ インスタンスを起動します。複数のブラウザ タイプが利用可能ですが、私は気まぐれで Chromium を選択しました。特定のブラウザを事前にインストールしておく必要があることに注意してください(例: playwright install --with-deps chromium
。
デフォルトでは、ブラウザはヘッドレスで開き、表示されません。デバッグを容易にするために、最初は表示して実行することをお勧めします: headless = True
。
新しいブラウザウィンドウを開きます。
新しい場所に移動します。
指定された入力フィールドを見つけて、資格情報を入力します。
指定されたボタンを見つけて押します。
指定されたすべての要素を検索します。
最初の要素の内部テキストを取得します。
クリーンアップするにはブラウザを閉じます。
上記は期待通りに動作しました。唯一の欠点は、スクリプトを実行するたびに 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()
Playwright は指定されたフォルダーにプロファイルを保存し、実行ごとに再利用します。
例外処理を改善します。
BrowserContext
ページを開くこともできます。
ダッシュボードに移動しようとします。認証されていない場合は LinkedIn によってログイン ページにリダイレクトされ、その後認証できるようになります。
結果がどうであれ、コンテキストを閉じます。
この時点では、最初に両方の資格情報を使用して認証するだけで済みます。その後の実行では、状況によって異なります。
上記のコードが確実に動作しないことに驚きました。最初の実行では動作し、その後の実行ではときどき動作しました。実行をまたいでブラウザ プロファイルを保存しているため、認証が必要な場合、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で最初に公開されました