Metadata-Version: 2.4
Name: jobcore
Version: 0.2.0
Summary: A lightweight Python client for job listings. No API key, no headless browser, no scraping service.
Author: Michael Danylchuk
License: MIT
Project-URL: Homepage, https://github.com/Mikedan37/jobcore
Project-URL: Issues, https://github.com/Mikedan37/jobcore/issues
Keywords: apple,jobs,careers,job-board,scraper
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
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 :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.24.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Dynamic: license-file

# jobcore

[![PyPI](https://img.shields.io/pypi/v/jobcore?color=blue)](https://pypi.org/project/jobcore/)
[![Python](https://img.shields.io/pypi/pyversions/jobcore)](https://pypi.org/project/jobcore/)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://opensource.org/licenses/MIT)

A lightweight Python client for job listings. No API key, no browser automation.

Currently supports Apple career listings (jobs.apple.com). More sources planned.

## Install

Available on [PyPI](https://pypi.org/project/jobcore/):

```bash
pip install jobcore
```

Or install from source:

```bash
git clone https://github.com/Mikedan37/jobcore.git
cd jobcore
pip install -e .
```

Requires Python 3.10+ and [httpx](https://www.python-httpx.org/).

## Quick example

```python
from jobcore import JobCoreClient

client = JobCoreClient()

for job in client.search(query="iOS engineer", limit=5):
    print(f"{job.title} — {job.team.name}")
    print(f"  {job.location} · {job.posting_date}")
    print(f"  {job.url}")
    print()

client.close()
```

## CLI

~6,000+ live positions across teams and locations.

```bash
jobcore count                          # total open positions
jobcore search "Swift"                 # search by keyword
jobcore search --team "Software"       # filter by team
jobcore search "iOS" --location "US"   # combine filters
jobcore page 5                         # fetch a specific page
jobcore dump > jobs.jsonl              # all jobs as JSON lines
```

Or via module: `python -m jobcore count`

## Why this exists

Major employers don't always provide public job APIs.

This package gives you a clean, stable interface over public job listings so you can:

- search roles programmatically
- build job matching pipelines
- automate job discovery workflows

One dependency (httpx). No Selenium. No API key.

## What this does

- Fetches job listings from public career pages
- Parses structured job data from server-rendered HTML (no headless browser)
- Returns typed Python models (`Job`, `JobCorePage`)
- Handles pagination, retries, and rate limiting
- Provides a small CLI for quick lookups and bulk export

## What this does NOT do

- Does not apply to jobs on your behalf
- Does not bypass authentication or access controls
- Does not scrape aggressively or circumvent rate limits
- Does not enrich, score, or rank jobs

## Responsible use

This library parses data already served to standard browser requests. Built-in safeguards:

- **0.5s default delay** between page requests. Do not set it to zero.
- **3 retries max** on transient failures. No infinite loops.
- **Honest User-Agent** with a project URL. Do not spoof it.

If a source changes their site structure or blocks automated access, this library will stop working. That is their right. File an issue and we will adapt.

## API reference

### JobCoreClient

```python
client = JobCoreClient(delay=0.5, retries=3, timeout=30.0)
```

| Method | Returns | Description |
|--------|---------|-------------|
| `search(query=, location=, team=, limit=)` | `list[Job]` | Search with client-side filtering |
| `search_page(page=1)` | `JobCorePage` | Fetch a single page (20 jobs) |
| `iter_jobs(max_pages=300)` | `Iterator[Job]` | Auto-paginate all jobs |
| `get_total_count()` | `int` | Total open positions |
| `close()` | — | Close HTTP client |

Supports context manager: `with JobCoreClient() as client: ...`

### Job

| Field | Type | Description |
|-------|------|-------------|
| `position_id` | `str` | Unique position ID |
| `title` | `str` | Job title |
| `summary` | `str` | 2-3 paragraph description |
| `url` | `str` | Direct link to posting |
| `posted_at` | `datetime?` | UTC timestamp |
| `posting_date` | `str` | Human-readable date |
| `team` | `JobTeam` | Department (name, code) |
| `locations` | `list[JobLocation]` | One or more locations |
| `home_office` | `bool` | Remote-eligible |
| `weekly_hours` | `int` | 40 = full-time |

Properties: `location` (primary as string), `is_remote`, `is_part_time`

### JobCorePage

| Field | Type | Description |
|-------|------|-------------|
| `jobs` | `list[Job]` | Up to 20 jobs |
| `total_records` | `int` | Total matching jobs |
| `page` | `int` | Current page (1-indexed) |

Properties: `total_pages`, `has_next`

## Development

```bash
git clone https://github.com/Mikedan37/jobcore.git
cd jobcore
pip install -e ".[dev]"
pytest tests/ -v              # 32 tests, ~0.5s, fully offline
```

Tests parse saved HTML fixtures. No network calls. If a source changes their site and tests break, re-capture the fixture and update the parser.

## Limitations

- **Client-side filtering.** Source pages may not support server-side text queries. `search()` fetches pages and filters locally.
- **Summaries only.** The `summary` field is from the search listing. Full detail pages are not fetched.
- **HTML parsing is inherently fragile.** If a source redesigns their site, the parser will break. File an issue.

## Maintained by

Maintained by Danylchuk Studios, LLC ([Seeker](https://www.seekerscore.com) project).

Unofficial job data tooling. Not affiliated with any company whose listings are accessed.

Intended for personal use, research, and tooling. Not for high-volume scraping or commercial redistribution of job listings.

## License

MIT
