Metadata-Version: 2.5
Name: linkfetch
Version: 0.1.3
Summary: Capture your own LinkedIn profile on your own computer and turn it into structured profile files
Project-URL: Homepage, https://github.com/Prosperis/linkfetch
Project-URL: Issues, https://github.com/Prosperis/linkfetch/issues
Author: Prosperis
License-Expression: MIT
License-File: LICENSE
Keywords: cv,export,linkedin,playwright,profile,resume
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business
Requires-Python: >=3.10
Requires-Dist: lxml>=5.0
Requires-Dist: playwright>=1.44
Requires-Dist: pydantic>=2.6
Requires-Dist: pyyaml>=6.0
Requires-Dist: rich>=13.7
Requires-Dist: tomli>=2.0; python_version < '3.11'
Requires-Dist: typer>=0.12
Provides-Extra: browser
Provides-Extra: dev
Requires-Dist: pytest-mock>=3.12; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# linkfetch

[![PyPI](https://img.shields.io/pypi/v/linkfetch)](https://pypi.org/project/linkfetch/)
[![Python](https://img.shields.io/pypi/pyversions/linkfetch)](https://pypi.org/project/linkfetch/)
[![Tests](https://github.com/Prosperis/linkfetch/actions/workflows/test.yml/badge.svg)](https://github.com/Prosperis/linkfetch/actions/workflows/test.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)

Capture **your own** LinkedIn profile on **your own computer** and turn it into
structured profile files — every role, description, skill, project,
certification and more — as plain YAML you can keep, edit, version or feed to
any other tool.

**In:** your LinkedIn profile address. **Out:** one YAML file per profile
section, plus `linkfetch-profile.zip` bundling them.

LinkedIn's official data export leaves out details the profile page shows.
linkfetch reads the rendered pages instead, in a real browser window that you
log into yourself.

## What it does and does not do

- **Runs only on your machine.** linkfetch is not a website or a service. It
  sends your data nowhere; the files it writes stay in a folder on your
  computer until you choose to upload them.
- **Reads only your own profile**, in a browser you log into. It never sees
  your password: you type it into LinkedIn's own login page.
- **Deterministic, no AI.** Every field comes straight from the page.
- **Open source** (MIT), so you can read exactly what it does.

## Install

You need Python 3.10 or newer and [uv](https://docs.astral.sh/uv/) (or
[pipx](https://pipx.pypa.io/)).

```bash
uv tool install linkfetch        # or: pipx install linkfetch
linkfetch doctor                 # shows where data is kept and whether Playwright and a login exist
linkfetch install-browser        # one-time download of the browser linkfetch drives (~150 MB)
```

## Use

```bash
linkfetch login                       # a browser window opens; log in to LinkedIn and it closes by itself
linkfetch run --vanity your-name      # capture your profile and build the files
```

`your-name` is the part after `/in/` in your profile address:
`linkedin.com/in/your-name`.

`run` visits each section of your profile (experience, education, skills, …),
expands every "see more", saves the pages, and turns them into one YAML file
per section plus **`linkfetch-profile.zip`**. `linkfetch` prints where they
are. See [Output](#output) for what they contain.

## Where your data is kept

Installed with `uv tool` or `pipx`, linkfetch keeps everything in your user
data folder:

| OS | Folder |
|---|---|
| Windows | `%LOCALAPPDATA%\linkfetch` |
| macOS | `~/Library/Application Support/linkfetch` |
| Linux | `$XDG_DATA_HOME/linkfetch` (usually `~/.local/share/linkfetch`) |

Set `LINKFETCH_HOME` to use a different folder. Inside it:

- `data/browser/` — the browser profile that keeps you logged in to LinkedIn.
  Treat it like a password; delete it to log out.
- `data/captures/` — the saved profile pages.
- `data/output/` — the YAML files and `linkfetch-profile.zip`.

Delete the folder to remove everything linkfetch stored.

## Commands

| Command | What it does |
|---|---|
| `linkfetch install-browser` | Download the browser linkfetch drives (one time, and again if an upgrade asks) |
| `linkfetch doctor` | Show the data folders and check Playwright and your login |
| `linkfetch login` | Open a browser window to log in to LinkedIn once |
| `linkfetch capture --vanity <you>` | Save your profile pages (needs the browser) |
| `linkfetch parse` | Turn saved pages into YAML and the ZIP (no browser; re-runnable) |
| `linkfetch run --vanity <you>` | `capture` then `parse` |

Use `--section experience --section skills` to limit a run to some sections,
and `parse --no-zip` to skip the ZIP.

## Output

Written to `data/output/` inside the data folder.

| File | Contains |
|---|---|
| `basics.yaml` | name, headline, location, about, contact links |
| `experiences.yaml` | one entry per role: company, title, dates, location, description bullets, skills used |
| `education.yaml` | school, degree, field, dates, activities |
| `skills.yaml` | skill name, and where you used it |
| `projects.yaml` | name, role, dates, description, links |
| `certifications.yaml` | name, issuer, issue/expiry dates, credential id and link |
| `awards.yaml` | honors & awards: name, issuer, date |
| `languages.yaml` | language and proficiency |
| `courses.yaml` | course name and number |
| `patents.yaml` | title, number, status, date, summary |
| `recommendations.yaml` | author, their title, relationship, text |
| `volunteering.yaml` | organization, role, cause, dates, summary |
| `honors.yaml` | a fuller copy of honors & awards, with descriptions |
| `linkfetch-profile.zip` | every file above except `honors.yaml`, in one archive |

Each file holds its section under a top-level key named after the file:

```yaml
experiences:
  - id: example-co-senior-engineer
    org: Example Co
    location: Austin, Texas, United States
    positions:
      - title: Senior Engineer
    timeline:
      start: Mar 2022
      end: Present
    bullets:
      - Led the migration of the billing platform
    tech:
      - TypeScript
```

Several roles at one company become separate entries — each with its own
title, dates and bullets — under the company's name. Empty fields are left out.
`id` values are stable slugs, so re-running produces small, reviewable diffs.

## How it works

1. **Capture** (needs the browser, runs rarely): a persistent Chromium profile
   you logged into visits each section's details page
   (`/in/<you>/details/experience/`, …), expands collapsed content, and saves
   the rendered HTML.
2. **Parse** (pure, offline): reads the saved HTML with `lxml` and writes YAML.
   If LinkedIn changes its pages, a parser fix plus `linkfetch parse` is enough
   — no need to capture again.

## Development

```bash
git clone https://github.com/Prosperis/linkfetch
cd linkfetch
uv venv && uv pip install -e ".[dev]"
uv run linkfetch install-browser
uv run pytest
```

A checkout keeps its data in `data/` next to `config.toml`, which also holds
browser settings (headless mode, timeouts, scroll pacing). Test fixtures are
anonymized excerpts of LinkedIn's page structure.

## Releasing

Bump `version` in `pyproject.toml`, commit, then push a matching tag:

```bash
git tag v0.1.1 && git push origin v0.1.1
```

The Release workflow tests, builds and publishes to PyPI through trusted
publishing (no stored token), then creates the GitHub release.

## Legal note

LinkedIn's User Agreement restricts automated access. linkfetch is meant for
**personal use on your own profile**: it uses a browser you logged into, moves
at a human pace, reads only your own data and stores nothing remotely. Use it
on your own account and at your own discretion.

## License

[MIT](LICENSE) © Prosperis
