In meiner vorherigen Firma habe ich einen Batch-Job entwickelt, der Kennzahlen in sozialen Medien wie Twitter, LinkedIn, Mastodon, Bluesky, Reddit usw. verfolgte. Dann wurde mir klar, dass ich ihn für meine eigene „Persona“ duplizieren könnte. Das Problem ist, dass einige Medien keine HTTP-API für die Kennzahlen bereitstellen, die ich möchte. Hier sind die Kennzahlen, die ich auf LinkedIn haben möchte:
Ich habe lange gesucht, aber keinen API-Zugriff für die oben genannten Kennzahlen gefunden. Ich habe die Kennzahlen lange Zeit jeden Morgen manuell abgefragt und mich schließlich dazu entschlossen, diese mühsame Aufgabe zu automatisieren. Hier ist, was ich dabei gelernt habe.
Der Job ist in Python, also möchte ich im gleichen Technologie-Stack bleiben. Nach einer kurzen Recherche fand ich Playwright , ein Browser-Automatisierungstool mit einigen Sprach-APIs, darunter Python. Der Hauptanwendungsfall von Playwright sind End-to-End-Tests, aber es kann den Browser auch außerhalb eines Testkontexts verwalten.
Ich verwende Poetry, um Abhängigkeiten zu verwalten. Die Installation von Playwright ist so einfach wie:
poetry add playwright
An diesem Punkt ist Playwright einsatzbereit. Es bietet zwei verschiedene APIs, eine synchrone und eine asynchrone . Für meinen Anwendungsfall ist die erste Variante mehr als ausreichend.
Ich gehe die Entwicklung gerne schrittweise an.
Hier ist ein Auszug der API:
Es wird in den folgenden Code übersetzt:
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
Holen Sie sich ein Objekt playwright
.
Starten Sie eine Browserinstanz. Es stehen mehrere Browsertypen zur Verfügung. Ich habe mich spontan für Chromium entschieden. Beachten Sie, dass Sie den jeweiligen Browser zuvor installiert haben sollten, z. B. playwright install --with-deps chromium
.
Standardmäßig wird der Browser „headless“ geöffnet; er wird nicht angezeigt. Ich empfehle, ihn gleich zu Beginn sichtbar auszuführen, um das Debuggen zu erleichtern: headless = True
.
Öffnen Sie ein neues Browserfenster.
Navigieren Sie zu einem neuen Standort.
Suchen Sie die angegebenen Eingabefelder und füllen Sie sie mit meinen Anmeldeinformationen aus.
Suchen Sie die angegebene Taste und drücken Sie sie.
Lokalisieren Sie alle angegebenen Elemente.
Holen Sie sich den inneren Text des ersten Elements.
Schließen Sie zum Aufräumen den Browser.
Das Obige hat wie erwartet funktioniert. Der einzige Nachteil ist, dass ich jedes Mal, wenn ich das Skript ausführte, eine E-Mail von LinkedIn erhielt:
Hallo Nicolas,
Sie haben „Angemeldet bleiben“ erfolgreich auf einem neuen Gerät von HeadlessChrome, <OS> in <Stadt>, <Region>, <Land> aktiviert. Erfahren Sie mehr darüber, wie „Angemeldet bleiben“ auf einem Gerät funktioniert.
Ich habe auch Fabien Vauchelles auf der JavaCro -Konferenz getroffen. Er ist auf Web Scraping spezialisiert und hat mir erzählt, dass die meisten Leute in diesem Bereich Browserprofile nutzen. Wenn Sie sich bei LinkedIn anmelden, erhalten Sie tatsächlich ein Authentifizierungstoken, das als Cookie gespeichert wird, und Sie müssen es nicht erneut authentifizieren, bevor es abläuft. Glücklicherweise bietet Playwright eine solche Funktion mit seiner Methode launch_persistent_context
.
Wir können den obigen launch
durch Folgendes ersetzen:
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 speichert das Profil im angegebenen Ordner und verwendet es bei mehreren Durchläufen erneut.
Verbessern Sie die Ausnahmebehandlung.
Der BrowserContext
kann auch Seiten öffnen.
Wir versuchen, zum Dashboard zu navigieren. LinkedIn leitet uns auf die Anmeldeseite weiter, wenn wir nicht authentifiziert sind. Wir können uns dann authentifizieren.
Schließen Sie den Kontext, unabhängig vom Ergebnis.
An diesem Punkt müssen wir uns nur beim ersten Mal mit beiden Anmeldeinformationen authentifizieren. Bei nachfolgenden Durchläufen kommt es darauf an.
Ich war überrascht, dass der obige Code nicht zuverlässig funktionierte. Er funktionierte beim ersten Durchlauf und manchmal auch bei den darauffolgenden. Da ich das Browserprofil über mehrere Durchläufe hinweg speichere, fragt LinkedIn bei der Authentifizierung nur nach dem Passwort, nicht nach dem Login! Da der Code versucht, den Login einzugeben, schlägt er in diesem Fall fehl. Die Lösung ist ziemlich einfach:
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'))
Obwohl ich kein Python-Experte bin, habe ich mit Playwright erreicht, was ich wollte. Ich habe die Synchronisierungs-API bevorzugt, da der Code dadurch etwas leichter zu verstehen ist und ich keine Leistungsanforderungen habe. Ich habe nur die grundlegenden Funktionen von Playwright verwendet. Playwright ermöglicht die Aufzeichnung von Videos im Rahmen von Tests, was sehr nützlich ist, wenn ein Test während der Ausführung einer CI-Pipeline fehlschlägt.
Um weiter zu gehen:
Ursprünglich veröffentlicht auf A Java Geek am 19. Januar 2024