{"id":50902454,"url":"https://github.com/delitamakanda/jobs-scraper","last_synced_at":"2026-06-16T04:02:18.947Z","repository":{"id":358819360,"uuid":"1134990185","full_name":"delitamakanda/jobs-scraper","owner":"delitamakanda","description":"AI-powered career assistant for senior Angular developers. Analyze job offers, generate interview prep, match skills, and manage applications with Django, Angular, and OpenAI.","archived":false,"fork":false,"pushed_at":"2026-05-26T17:38:07.000Z","size":222,"stargazers_count":0,"open_issues_count":55,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-26T18:24:21.893Z","etag":null,"topics":["ai","angular","django","django-rest-framework","tailwindcss"],"latest_commit_sha":null,"homepage":"https://delitamakanda.github.io/jobs-scraper","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/delitamakanda.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-01-15T13:44:24.000Z","updated_at":"2026-05-26T16:44:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/delitamakanda/jobs-scraper","commit_stats":null,"previous_names":["delitamakanda/jobs-scraper"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/delitamakanda/jobs-scraper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delitamakanda%2Fjobs-scraper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delitamakanda%2Fjobs-scraper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delitamakanda%2Fjobs-scraper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delitamakanda%2Fjobs-scraper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/delitamakanda","download_url":"https://codeload.github.com/delitamakanda/jobs-scraper/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delitamakanda%2Fjobs-scraper/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34390052,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-16T02:00:06.860Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","angular","django","django-rest-framework","tailwindcss"],"created_at":"2026-06-16T04:02:14.383Z","updated_at":"2026-06-16T04:02:18.936Z","avatar_url":"https://github.com/delitamakanda.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Jobs Scraper / Career Agent API [![Deploy Frontend](https://github.com/delitamakanda/jobs-scraper/actions/workflows/deploy-frontend.yml/badge.svg?branch=main\u0026event=push)](https://github.com/delitamakanda/jobs-scraper/actions/workflows/deploy-frontend.yml)\n\nDjango REST API for collecting job offers, extracting job details from URLs, and matching offers against a candidate profile with AI-assisted analysis.\n\n## What it does\n\n- Stores job offers per authenticated user.\n- Imports job pages from a URL and detects LinkedIn, HelloWork, or a generic source.\n- Parses HTML with BeautifulSoup/lxml and saves normalized job metadata.\n- Uses an OpenAI-compatible chat client to extract skills, seniority, domain summaries, and red flags.\n- Computes profile/job matches from a candidate's stored skills.\n- Tracks saved/applied/interview/rejection/offer application status in the data model.\n\n## Tech stack\n\n- Python 3.14+\n- Django 6.0\n- Django REST Framework\n- SQLite for local development\n- Requests, BeautifulSoup, and lxml for scraping/parsing\n- OpenAI Python SDK configured for Tongyi/Qwen-compatible endpoints\n\n## Project layout\n\n```text\n.\n├── apps/\n│   ├── accounts/       # Authentication app placeholder\n│   ├── ai/             # LLM client, job analyzer, matching helpers, prompts\n│   ├── applications/   # Application tracking model\n│   ├── core/           # Shared/core app placeholder\n│   ├── jobs/           # Job offer API, serializers, models, import services\n│   └── profiles/       # Candidate profile model\n├── config/             # Django settings and root URL configuration\n├── manage.py\n├── requirements.txt\n├── requirements-dev.txt\n└── pyproject.toml\n```\n\n## Prerequisites\n\n- Python 3.14 or newer.\n- A Tongyi/Qwen-compatible API key and base URL if you want to use job analysis or URL import, because imports call the analyzer after parsing.\n\n## Quick start\n\n1. Clone the repository and enter it:\n\n   ```bash\n   git clone \u003crepo-url\u003e\n   cd jobs-scraper\n   ```\n\n2. Create and activate a virtual environment:\n\n   ```bash\n   python3.14 -m venv .venv\n   source .venv/bin/activate\n   ```\n\n3. Install dependencies:\n\n   ```bash\n   pip install -r requirements.txt\n   ```\n\n4. Configure environment variables for AI-backed analysis:\n\n   ```bash\n   export TONGYI_API_KEY=your_api_key\n   export TONGYI_API_URL=https://your-openai-compatible-endpoint/v1\n   export TONGYI_MODEL=qwen-plus\n   ```\n\n   The settings module has development defaults for these values, but real analysis calls require valid credentials.\n\n5. Run database migrations:\n\n   ```bash\n   python manage.py migrate\n   ```\n\n6. Create an admin user:\n\n   ```bash\n   python manage.py createsuperuser\n   ```\n\n7. Start the development server:\n\n   ```bash\n   python manage.py runserver\n   ```\n\n   The API will be available at `http://127.0.0.1:8000/`.\n\n## Authentication\n\nThe API uses Django REST Framework token authentication and requires authenticated requests by default.\n\nCreate or retrieve a token for a user from the Django shell:\n\n```bash\npython manage.py shell\n```\n\n```python\nfrom django.contrib.auth import get_user_model\nfrom rest_framework.authtoken.models import Token\n\nuser = get_user_model().objects.get(username=\"\u003cusername\u003e\")\ntoken, _ = Token.objects.get_or_create(user=user)\nprint(token.key)\n```\n\nUse the token in API requests:\n\n```http\nAuthorization: Token \u003ctoken\u003e\n```\n\n## API endpoints\n\n### Jobs\n\nBase path: `/api/jobs/`\n\n| Method | Path | Description |\n| --- | --- | --- |\n| `GET` | `/api/jobs/` | List the authenticated user's job offers. |\n| `POST` | `/api/jobs/` | Create a job offer manually. |\n| `GET` | `/api/jobs/{id}/` | Retrieve a job offer. |\n| `PUT/PATCH` | `/api/jobs/{id}/` | Update a job offer. |\n| `DELETE` | `/api/jobs/{id}/` | Delete a job offer. |\n| `POST` | `/api/jobs/import-url/` | Import, parse, analyze, and save a job offer from a URL. |\n| `POST` | `/api/jobs/{id}/analyze/` | Re-run AI analysis for a saved job offer. |\n| `POST` | `/api/jobs/{id}/match/` | Match a saved job offer against the authenticated user's candidate profile. |\n\nExample: import a job URL\n\n```bash\ncurl -X POST http://127.0.0.1:8000/api/jobs/import-url/ \\\n  -H \"Authorization: Token \u003ctoken\u003e\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\":\"https://example.com/jobs/frontend-developer\"}'\n```\n\nExample: create a job manually\n\n```bash\ncurl -X POST http://127.0.0.1:8000/api/jobs/ \\\n  -H \"Authorization: Token \u003ctoken\u003e\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"title\": \"Senior Angular Developer\",\n    \"company\": \"Example Co\",\n    \"url\": \"https://example.com/jobs/123\",\n    \"raw_description\": \"We are looking for a senior Angular developer...\",\n    \"location\": \"Remote\"\n  }'\n```\n\n### Other mounted API paths\n\nThese paths are registered in the root URL configuration, but their routers currently do not expose viewsets:\n\n- `/api/auth/`\n- `/api/ai/`\n- `/api/profile/`\n- `/api/applications/`\n\n## Main data models\n\n### JobOffer\n\nStores scraped or manually entered job data including source, title, company, URL, raw description, location, remote policy, contract type, skill lists, seniority, business domain, AI summary, and red flags.\n\n### JobMatch\n\nStores a computed match score and generated guidance for a `JobOffer`.\n\n### Candidate\n\nStores a user's candidate profile, skills, target locations, remote preference, industries, projects, and salary range.\n\n### Application\n\nStores status and follow-up metadata for an application tied to a `JobOffer`.\n\n## AI behavior\n\n`apps.ai.services.llm_client.LLMClient` uses the OpenAI Python SDK with configurable `api_key`, `base_url`, and model. The analyzer prompts the model to return valid JSON with extracted skills, seniority, business domain, summary, and red flags, then persists those fields on the job offer.\n\n## Development commands\n\nRun Django checks:\n\n```bash\npython manage.py check\n```\n\nRun tests:\n\n```bash\npython manage.py test\n```\n\nCreate migrations after model changes:\n\n```bash\npython manage.py makemigrations\n```\n\nApply migrations:\n\n```bash\npython manage.py migrate\n```\n\n## Notes and current limitations\n\n- The project is configured for local development with SQLite and `DEBUG = True`.\n- Token authentication is enabled, but the accounts app does not currently expose login, registration, or token creation endpoints.\n- URL import depends on the target site allowing HTML access. Some sites, including LinkedIn, may return limited content or block scraping.\n- The import flow immediately runs AI analysis, so invalid AI credentials can cause URL import to fail after parsing.\n- `requirements-dev.txt` is currently empty; add linting/type-checking/test tooling there as the development workflow grows.\n\n## License\n\nThis project is licensed under the terms in [`LICENSE`](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdelitamakanda%2Fjobs-scraper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdelitamakanda%2Fjobs-scraper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdelitamakanda%2Fjobs-scraper/lists"}