Developer Advocate, eternal learner, author
U svojoj prethodnoj kompaniji razvio sam grupni posao koji je pratio metriku na društvenim medijima, kao što su Twitter, LinkedIn, Mastodon, Bluesky, Reddit, itd. Tada sam shvatio da mogu da ga dupliram za svoju „personu“. Problem je u tome što neki mediji ne pružaju HTTP API za metriku koju želim. Evo metrike koju želim na LinkedInu:
LinkedIn metrička kontrolna tabla
Dugo sam tražio, ali nisam našao API pristup za gornju metriku. Svako jutro sam dugo vremena ručno strugao metriku i konačno odlučio automatizirati ovaj dosadan zadatak. Evo šta sam naučio.
Posao je u Pythonu, tako da želim da ostanem u istom tehnološkom steku. Nakon brzog istraživanja, pronašao sam Playwright , alat za automatizaciju pretraživača sa nekoliko jezičkih API-ja, uključujući Python. Primarni slučaj upotrebe Playwright-a je testiranje s kraja na kraj, ali takođe može upravljati pretraživačem izvan konteksta testiranja.
Koristim Poetry za upravljanje ovisnostima. Instalacija Playwright-a je jednostavna kao:
poetry add playwright
U ovom trenutku, Playwright je spreman za upotrebu. Nudi dva različita API-ja, jedan sinhroni i jedan asinhroni . Zbog mog načina upotrebe, prvi okus je više nego dovoljan.
Volim postepeno pristupiti razvoju.
Evo izvoda API-ja:
Izvod iz API modela
Prevodi se u sljedeći kod:
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
Nabavite predmet playwright
.
Pokrenite instancu pretraživača. Dostupno je više tipova pretraživača; Odabrao sam Chromium iz hira. Imajte na umu da ste prethodno trebali instalirati određeni pretraživač, tj . playwright install --with-deps chromium
.
Podrazumevano, pretraživač se otvara bez glave ; ne pojavljuje se. Savjetovao bih da ga pokrenete vidljivo na početku radi lakšeg otklanjanja grešaka: headless = True
.
Otvorite novi prozor pretraživača.
Navigirajte do nove lokacije.
Pronađite navedena polja za unos i popunite ih mojim akreditivima.
Pronađite određeno dugme i pritisnite ga.
Pronađite sve navedene elemente.
Dobijte unutrašnji tekst prvog elementa.
Zatvorite pretraživač da očistite.
Gore navedeno je funkcioniralo kako se očekivalo. Jedina mana je što sam svaki put kada sam pokrenuo skriptu primao e-poštu od LinkedIn-a:
zdravo Nicolas,
Uspješno ste aktivirali Zapamti me na novom uređaju HeadlessChrome, <OS> u <grad>, <regija>, <zemlja> . Saznajte više o tome kako Zapamti me radi na uređaju.
Također sam upoznao Fabiena Vauchellesa na konferenciji JavaCro . Specijalizirao se za web scraping i rekao mi je da većina ljudi u ovoj oblasti koristi profile pretraživača. Zaista, ako se prijavite na LinkedIn, dobit ćete token za autentifikaciju pohranjen kao kolačiće i nećete ga morati ponovo autentifikovati prije nego što istekne. Na sreću, Playwright nudi takvu funkciju svojom metodom launch_persistent_context
.
Gornje launch
možemo zamijeniti sljedećim:
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 će pohraniti profil u navedenu mapu i ponovo ga koristiti tokom izvođenja.
Poboljšajte rukovanje izuzetcima.
BrowserContext
također može otvarati stranice.
Pokušavamo doći do kontrolne table. LinkedIn će nas preusmjeriti na stranicu za prijavu ako nismo autentificirani; onda možemo da se autentifikujemo.
Zatvorite kontekst bez obzira na ishod.
U ovom trenutku, potrebno je samo da se autentifikujemo sa oba akreditiva prvi put. Zavisi od narednih vožnji.
Bio sam iznenađen kada sam vidio da gornji kod ne radi pouzdano. Upalilo je u prvoj vožnji, a ponekad iu sljedećim. Budući da pohranjujem profil pretraživača u svim radnjama, kada trebam da se autentifikujem, LinkedIn traži samo lozinku, a ne i login! Pošto kod pokušava da unese prijavu, u ovom slučaju ne uspeva. Popravak je prilično jednostavan:
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'))
Iako nisam stručnjak za Python, uspeo sam da postignem ono što sam želeo sa Playwrightom. Radije sam koristio API za sinhronizaciju jer on čini kod malo lakšim za razmišljanje, a nemam nikakve zahtjeve za performansama. Koristio sam samo osnovne funkcije koje nudi Playwright. Playwright dozvoljava snimanje video zapisa u kontekstu testova, što je vrlo korisno kada test ne uspije tokom izvršavanja CI pipelinea.
Da idemo dalje:
Originalno objavljeno na A Java Geek 19. januara 2024