Skip to main content

Standalone, reusable web scraping services for GitHub, Dev.to, and Medium — extracted from the ResuMesh project.

Project description

ResuMesh Scrapers Banner

resumesh-scrapers

Enterprise-Grade, Standalone, and Decoupled Web Scraping Engines for Portfolio Building

PyPI version Python versions License CI Status


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 tenacity and structured logging.
  • Fully Decoupled Models: Independent, clean data validation using pydantic v2, 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 ScraperError with 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,
    ScrapedArticle,
    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[ScrapedArticle] = await devto.fetch_data("atacanymc")
    print(f"Fetched {len(devto_posts)} Dev.to articles.")

    # 3. Scraping Substack Publications
    substack = SubstackScraper()
    substack_posts: list[ScrapedArticle] = 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("atacanymc")
    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
    ├── article.py              # Dev.to, Medium, Substack shared schemas
    ├── 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 ScrapedArticle Title, URL, Tags, Reading time, Publishing date
Medium MediumScraper ScrapedArticle Title, RSS Summary, UTM-stripped URL, Category tags
Substack SubstackScraper ScrapedArticle Title, RSS Summary, URL, Reading time estimation
Behance BehanceScraper BehanceProjectModel Project title, gallery URL, appreciation count, publication dates
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!

  1. Fork the Project.
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature).
  3. Commit your Changes (git commit -m 'Add some AmazingFeature').
  4. Push to the Branch (git push origin feature/AmazingFeature).
  5. Open a Pull Request.

📄 License

Distributed under the Apache 2.0 License. See LICENSE for more information.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

resumesh_scrapers-0.3.0.tar.gz (30.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

resumesh_scrapers-0.3.0-py3-none-any.whl (28.6 kB view details)

Uploaded Python 3

File details

Details for the file resumesh_scrapers-0.3.0.tar.gz.

File metadata

  • Download URL: resumesh_scrapers-0.3.0.tar.gz
  • Upload date:
  • Size: 30.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for resumesh_scrapers-0.3.0.tar.gz
Algorithm Hash digest
SHA256 219ed7928f5985904c0e8026c0e4685243a0cb8c69bc67281d25912dde96b879
MD5 f3f222d279a9db67a9451d6d3a40bfdb
BLAKE2b-256 93143ccbf821efb3ea0abe05aea0ac26116e6b58cb9235bc1990b0c05ba41bc2

See more details on using hashes here.

Provenance

The following attestation bundles were made for resumesh_scrapers-0.3.0.tar.gz:

Publisher: cd.yml on AtaCanYmc/resumesh-scrapers

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file resumesh_scrapers-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for resumesh_scrapers-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 383654527d0771ed415c73d859aeeb32be4bf5c71c3a332affdb9ba14ffeb476
MD5 80eb6cd12e24f5c6e5f04e9614b11c37
BLAKE2b-256 e453d76583b67423fa4f8ed8746515d8711b5b533827b8cc93888d0cce0e78ac

See more details on using hashes here.

Provenance

The following attestation bundles were made for resumesh_scrapers-0.3.0-py3-none-any.whl:

Publisher: cd.yml on AtaCanYmc/resumesh-scrapers

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page