Skip to main content

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, PyPI, and YouTube 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, blog statistics, and YouTube videos:

import asyncio
from resumesh_scrapers import (
    GitHubScraper,
    DevToScraper,
    MediumScraper,
    SubstackScraper,
    BehanceScraper,
    YouTubeScraper,
    GitHubRepositoryModel,
    GitHubCommitModel,
    GitHubUserModel,
    DevToArticleModel,
    MediumEntryModel,
    SubstackEntryModel,
    BehanceProjectModel,
    YouTubeVideoModel,
)

async def main():
    # 1. Scraping GitHub Repositories, README Repos, Commits, and User Lists
    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.")

    # Fetch profile README repository details
    readme_repo = await github.fetch_readme_repo("octocat")
    if readme_repo:
        print(f"Profile README Repository: {readme_repo.html_url}")

    # Fetch recent commits (default since: last 7 days)
    commits: list[GitHubCommitModel] = await github.fetch_commits("octocat")
    print(f"Fetched {len(commits)} commits.")

    # Fetch followers and following list
    followers: list[GitHubUserModel] = await github.fetch_followers("octocat", per_page=10)
    print(f"Fetched {len(followers)} followers.")


    # 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.")

    # 5. Scraping YouTube Video Metadata
    youtube = YouTubeScraper()
    video_data: YouTubeVideoModel = await youtube.fetch_video("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    print(f"Fetched YouTube video: {video_data.title} ({video_data.view_count:,} views)")

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
│   ├── youtube.py
│   └── __init__.py
└── models/                     # Platform-specific Pydantic validation schemas
    ├── github.py
    ├── devto.py
    ├── medium.py
    ├── substack.py
    ├── behance.py
    ├── npm.py
    ├── pypi.py
    ├── youtube.py
    └── __init__.py

📊 Models & Capabilities

Platform Scraper Class Response Model Captured Data Features
GitHub GitHubScraper GitHubRepositoryModel
GitHubCommitModel
GitHubUserModel
Repos: Stars, Forks, languages, watchers.
Commits: author, message, sha, repo, date, HTML link.
Users: login, avatar URL, HTML link (followers/following).
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
YouTube YouTubeScraper YouTubeVideoModel Video title, duration, view count, like count, comment count, channel info, thumbnail, tags, categories (via yt-dlp)

⚠️ 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.

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.9.0.tar.gz (37.9 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.9.0-py3-none-any.whl (33.4 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for resumesh_scrapers-0.9.0.tar.gz
Algorithm Hash digest
SHA256 ba4df0809cd9249a078f1f54b097a622201c9de2d25ab17010c4896e7f6cefa1
MD5 38758f44f6106fb17b4c713c10719c91
BLAKE2b-256 af1d97309994e6e441fb79440df46679c93f8a9ad3dc0d959e896b84bd8447f2

See more details on using hashes here.

Provenance

The following attestation bundles were made for resumesh_scrapers-0.9.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.9.0-py3-none-any.whl.

File metadata

File hashes

Hashes for resumesh_scrapers-0.9.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2cff284c87ecc46b89170d6d9302d5c3cc9c7346ea11b50abd8721eb0a88c5a5
MD5 4dfab8f08e3a72f4aa4199b12cdd5f24
BLAKE2b-256 264af463f55812f4180798475c7c7a24b70ea096111bda44172c4f6e3b860e8c

See more details on using hashes here.

Provenance

The following attestation bundles were made for resumesh_scrapers-0.9.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.

Release history Release notifications | RSS feed

This release

0.9.0 This release

2 files

0.8.0

2 files

0.6.0

2 files

0.4.0

2 files

0.3.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page