Skip to content

Add LinkedIn avatar downloader + Chrome-session auth (macOS)#294

Open
framallo wants to merge 2 commits into
joeyism:masterfrom
framallo:feat/avatar-skill
Open

Add LinkedIn avatar downloader + Chrome-session auth (macOS)#294
framallo wants to merge 2 commits into
joeyism:masterfrom
framallo:feat/avatar-skill

Conversation

@framallo

@framallo framallo commented Jul 4, 2026

Copy link
Copy Markdown

Add a LinkedIn avatar downloader with password-free Chrome-session auth (macOS)

This adds a small, self-contained way to save a profile's headshot as a real image file, plus a cookie-based auth path that reuses your already-logged-in Chrome — no LinkedIn password stored or typed.

Why

Every "obvious" way to grab a LinkedIn avatar is blocked:

Method Result
Read the <img> src and download it CDN URL is token-signed / filtered
fetch() the bytes in-page CORS blocked
Draw to <canvas>toDataURL() SecurityError: tainted canvas
Right-click → Save image as Native OS dialog, not scriptable
Profile "Save to PDF" Text-only résumé, no embedded image

The one thing that works: element-screenshot the rendered <img> with Playwright. This PR packages that.

What's included

  • core/chrome_cookies.pyget_chrome_linkedin_cookies(): reads the local Chrome cookie DB (copies the WAL so it works while Chrome is open) and decrypts li_at et al. with the Chrome Safe Storage key from the macOS Keychain. Returns Playwright-ready cookie dicts. macOS only (cleanly documented).
  • scrapers/avatar.pyAvatarScraper(page).download(url, out_path): navigates a profile, picks the largest square media.licdn.com image (the photo, not the cover banner or a thumbnail), and screenshots it at 2x. Returns {saved, path, rendered}; saved: False for ghost/no-photo profiles.
  • Exports wired into core/__init__.py, scrapers/__init__.py, and the top-level package.
  • samples/download_avatar.py — one-file CLI example.
  • skills/linkedin-avatar/SKILL.md + a README section.

Usage

from linkedin_scraper import BrowserManager, get_chrome_linkedin_cookies, AvatarScraper

cookies = get_chrome_linkedin_cookies()
async with BrowserManager(headless=True, device_scale_factor=2) as page:
    await page.context.add_cookies(cookies)
    result = await AvatarScraper(page).download(url, "out.png")

Notes

  • macOS-only for the Keychain decryption path; the AvatarScraper itself works with any authenticated context (Linux/Windows users can supply cookies their own way).
  • Cookies are read-only — the Chrome profile is never modified.
  • Reuse one context and pace requests; respects LinkedIn's throttling.

framallo and others added 2 commits July 3, 2026 18:17
- core/chrome_cookies.py: get_chrome_linkedin_cookies() decrypts cookies from a
  logged-in Chrome profile (macOS Keychain) so you can auth without a password.
- scrapers/avatar.py: AvatarScraper.download() element-screenshots the main
  square profile photo — the only reliable way to get a headshot file.
- samples/download_avatar.py + skills/linkedin-avatar/SKILL.md + README section.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drops core/chrome_cookies.py (get_chrome_linkedin_cookies) and its macOS
Keychain cookie decryption. AvatarScraper now authenticates with the
library's existing cross-platform helpers (login_with_cookie via LI_AT,
credentials, or manual login). Updates sample, skill, and README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant