Standalone, reusable web scraping services for GitHub, Dev.to, and Medium — extracted from the ResuMesh project.
Project description
resumesh-scrapers
Enterprise-Grade, Standalone, and Decoupled Web Scraping Engines for Portfolio Building
resumesh-scrapers is a clean, modular, and robust Python library containing standalone scraping services for GitHub, Dev.to, Medium, Substack, Behance, NPM, and PyPI platforms. Originally developed as part of the ResuMesh ecosystem, it has been decoupled to serve as a reusable package for any resume, portfolio, or profile aggregator project.
🚀 Key Features
- Robust Core Network Engine: Centralized HTTP request handling with standard retry mechanisms powered by
tenacityand structured logging. - Fully Decoupled Models: Independent, clean data validation using
pydanticv2, keeping data structures separated from database constraints. - Extensible Architecture: Platform scrapers are isolated in a plug-and-play layout under
platforms/allowing quick addition of new integrations (e.g. LinkedIn, GitLab). - Detailed Exceptions: Standardized exceptions hierarchy inheriting from
ScraperErrorwith HTTP status code details.
🛠️ Installation
pip install resumesh-scrapers
For Local Development (Editable mode)
git clone https://github.com/AtaCanYmc/resumesh-scrapers.git
cd resumesh-scrapers
pip install -e .
💡 Quick Start
Here is a simple example showing how to scrape your repository and blog statistics:
import asyncio
from resumesh_scrapers import (
GitHubScraper,
DevToScraper,
MediumScraper,
SubstackScraper,
BehanceScraper,
GitHubRepositoryModel,
DevToArticleModel,
MediumEntryModel,
SubstackEntryModel,
BehanceProjectModel,
)
async def main():
# 1. Scraping GitHub Repositories
github = GitHubScraper()
repos: list[GitHubRepositoryModel] = await github.fetch_data(
username="octocat",
pat="ghp_...", # optional PAT token to bypass rate limit
include_forks=False
)
print(f"Fetched {len(repos)} repositories.")
# 2. Scraping Dev.to Articles
devto = DevToScraper()
devto_posts: list[DevToArticleModel] = await devto.fetch_data("atacanymc")
print(f"Fetched {len(devto_posts)} Dev.to articles.")
# 3. Scraping Substack Publications
substack = SubstackScraper()
substack_posts: list[SubstackEntryModel] = await substack.fetch_data("atacan")
print(f"Fetched {len(substack_posts)} Substack posts.")
# 4. Scraping Behance Projects
behance = BehanceScraper()
behance_projects: list[BehanceProjectModel] = await behance.fetch_data(
username="atacanymc",
api_key="your_behance_api_key" # optional, falls back to HTML scraping if not provided
)
print(f"Fetched {len(behance_projects)} Behance projects.")
if __name__ == "__main__":
asyncio.run(main())
🗺️ Clean Architecture
The codebase has been refactored to enforce separation of concerns, decoupling models, platforms, and network layers:
src/resumesh_scrapers/
├── core/ # Shared network and utility systems
│ ├── client.py # Central HTTP requester with tenacity retries
│ └── __init__.py
├── platforms/ # Individual platform scrapers
│ ├── github.py
│ ├── devto.py
│ ├── medium.py
│ ├── substack.py
│ ├── behance.py
│ ├── npm.py
│ ├── pypi.py
│ └── __init__.py
└── models/ # Platform-specific Pydantic validation schemas
├── github.py
├── devto.py
├── medium.py
├── substack.py
├── behance.py
├── npm.py
├── pypi.py
└── __init__.py
📊 Models & Capabilities
| Platform | Scraper Class | Response Model | Captured Data Features |
|---|---|---|---|
| GitHub | GitHubScraper |
GitHubRepositoryModel |
Stars, Forks, Main languages, Visibility, Watchers, Creation dates |
| Dev.to | DevToScraper |
DevToArticleModel |
Title, URL, Tags, Reading time, Publishing date |
| Medium | MediumScraper |
MediumEntryModel |
Title, RSS Summary, UTM-stripped link, Category tags |
| Substack | SubstackScraper |
SubstackEntryModel |
Title, RSS Summary, link, tags |
| Behance | BehanceScraper |
BehanceProjectModel |
Project title, gallery URL, appreciation count, publication dates (supports API client keys) |
| NPM | NpmScraper |
NpmSearchResultModel |
Maintainer packages, keywords, version history, publisher metadata |
| PyPI | PyPIScraper |
PyPiPackageModel |
Releases, download statistics, license, project metadata |
⚠️ Exception Handling
All scraper exceptions inherit from ScraperError to simplify integration errors:
from resumesh_scrapers.exceptions import ScraperError, GitHubScraperError
try:
repos = await github_scraper.fetch_data("some_username")
except GitHubScraperError as e:
print(f"GitHub API Error: {e.message} (HTTP {e.status_code})")
except ScraperError as e:
print(f"Generic Scraping Exception: {e}")
🤝 Contributing
We welcome contributions to add more platforms (such as LinkedIn, GitLab, or Dribbble) or optimize parsers. Please open a Pull Request or file an issue to discuss your ideas!
- Fork the Project.
- Create your Feature Branch (
git checkout -b feature/AmazingFeature). - Commit your Changes (
git commit -m 'Add some AmazingFeature'). - Push to the Branch (
git push origin feature/AmazingFeature). - Open a Pull Request.
📄 License
Distributed under the Apache 2.0 License. See LICENSE for more information.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file resumesh_scrapers-0.4.0.tar.gz.
File metadata
- Download URL: resumesh_scrapers-0.4.0.tar.gz
- Upload date:
- Size: 31.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d9ea7582dfacef82ee385d0ce96b03bc98e923c344128497b81d9301c1cbd9c3
|
|
| MD5 |
08d39f8111fdfc416e0f86a0f0fd66e5
|
|
| BLAKE2b-256 |
731a79329ef142aa6baf1a9cf0225d01b539da40394a638c68cb9e1466c99560
|
Provenance
The following attestation bundles were made for resumesh_scrapers-0.4.0.tar.gz:
Publisher:
cd.yml on AtaCanYmc/resumesh-scrapers
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
resumesh_scrapers-0.4.0.tar.gz -
Subject digest:
d9ea7582dfacef82ee385d0ce96b03bc98e923c344128497b81d9301c1cbd9c3 - Sigstore transparency entry: 2234789776
- Sigstore integration time:
-
Permalink:
AtaCanYmc/resumesh-scrapers@27f351a32c26a625fd832172afaf9cad29ffa5d8 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/AtaCanYmc
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
cd.yml@27f351a32c26a625fd832172afaf9cad29ffa5d8 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file resumesh_scrapers-0.4.0-py3-none-any.whl.
File metadata
- Download URL: resumesh_scrapers-0.4.0-py3-none-any.whl
- Upload date:
- Size: 29.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
225de0a5fe21e5fdc1720072e194d7b7825bd6241bed74bd7e0568b64b2ce1e3
|
|
| MD5 |
69669c99a2311129e6c1f6eb8c1adf77
|
|
| BLAKE2b-256 |
7f2bd7dfb410d470dbb7d8f5c2c31056b9a6f9dc2bf40c4a11ddf915e49a1746
|
Provenance
The following attestation bundles were made for resumesh_scrapers-0.4.0-py3-none-any.whl:
Publisher:
cd.yml on AtaCanYmc/resumesh-scrapers
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
resumesh_scrapers-0.4.0-py3-none-any.whl -
Subject digest:
225de0a5fe21e5fdc1720072e194d7b7825bd6241bed74bd7e0568b64b2ce1e3 - Sigstore transparency entry: 2234789914
- Sigstore integration time:
-
Permalink:
AtaCanYmc/resumesh-scrapers@27f351a32c26a625fd832172afaf9cad29ffa5d8 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/AtaCanYmc
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
cd.yml@27f351a32c26a625fd832172afaf9cad29ffa5d8 -
Trigger Event:
workflow_dispatch
-
Statement type: