PyPI Package Scraper — Downloads, Releases, Vulnerabilities avatar

PyPI Package Scraper — Downloads, Releases, Vulnerabilities

Pricing

from $1.40 / 1,000 result items

Go to Apify Store
PyPI Package Scraper — Downloads, Releases, Vulnerabilities

PyPI Package Scraper — Downloads, Releases, Vulnerabilities

Python package intelligence for AI agents and due diligence: downloads (day/week/month, by Python version and OS), release history and cadence, parsed requirements, license (PEP 639), development status, known vulnerabilities (OSV), owners, project URLs.

Pricing

from $1.40 / 1,000 result items

Rating

0.0

(0)

Developer

Samat Makatov

Samat Makatov

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

12 hours ago

Last modified

Categories

Share

PyPI Package Intel — downloads, versions, requirements, vulnerabilities

One clean JSON per Python package: downloads (day/week/month, by Python version and OS), release history and cadence, parsed requirements, normalized license, development status, known vulnerabilities, owners and project links. Built for AI agents, dependency due diligence and developer-tool market research. Plus two feed modes that watch PyPI for new releases and new projects in your niche. No API key, no proxy, no browser.

Use cases

  • Dependency due diligence — before adopting a library, get license (PEP 639 expression, field or classifier), maintenance cadence, wheel availability, Python support, owners and open vulnerabilities in one item.
  • Supply-chain / security review — pin name==version to see the OSV advisories (CVE/GHSA aliases, fixed-in) for exactly the version you ship; flag yanked releases.
  • Competitor & market tracking — compare monthly downloads, Python 3.x adoption and OS split of your SDK vs. alternatives; schedule weekly and diff.
  • Abandonment alertsdaysSinceLastRelease, releasesLast365d, developmentStatus (Inactive/Mature) feed a "stale dependency" monitor.
  • Lead generation for dev toolsnewPackages + keywords (e.g. mcp, agent, llm) surfaces projects launching in your category, with author e-mail when published.
  • Release monitoringrecentUpdates + keywords catches new versions of an ecosystem (e.g. langchain, openai) minutes after upload.

Input

FieldTypeDefaultNotes
modestringpackagespackages · recentUpdates · newPackages
packagesstring[]Project names; name==1.2.3 or name@1.2.3 pins a version. Names are PEP 503-normalized (case/-/_/. insensitive). Required in packages mode.
keywordsstring[][]Feed modes only: keep items whose name/summary contains any keyword (case-insensitive).
maxItemsinteger100Feed modes only (1–200). The PyPI feeds carry the latest ~40 entries.
includeDownloadsbooleantrueDay/week/month downloads from pypistats.org (mirrors excluded).
downloadsBreakdownbooleanfalseAdds downloadsByPythonMinor30d and downloadsBySystem30d (last 30 days). +2 pypistats requests per package.
downloadsHistoryDaysinteger00–180. Adds downloadsHistory daily series + total. +1 request.
includeMirrorsbooleanfalseCount mirror traffic in breakdown/history.
includeVulnerabilitiesbooleantruevulnerabilities[] from PyPI (OSV). vulnerabilityCount always present.
includeReleasesbooleantruerecentVersions[] (newest first).
versionsLimitinteger100–200 entries in recentVersions.
includeClassifiersbooleantrueRaw Trove classifiers[].
descriptionCharsinteger00 = omit; N = first N chars of the long description (README).
fieldsstring[][]Whitelist of top-level output fields; id and name are always kept.

Existing inputs (packages, versionsLimit) keep their old meaning.

Reference

Sources and what they provide

SourceEndpointUsed for
PyPI JSON APIhttps://pypi.org/pypi/{name}/json, /pypi/{name}/{version}/jsonmetadata, releases, files, vulnerabilities, ownership
PyPI RSShttps://pypi.org/rss/updates.xml, /rss/packages.xmlrecentUpdates, newPackages modes
pypistats.org/api/packages/{name}/recent, /python_minor, /system, /overalldownloads (updated once a day, 180-day depth)

PyPI has no search API (XML-RPC search was disabled in 2021); use the feed modes with keywords, or a search engine, to discover names.

Development Status classifiers → developmentStatus

CodeLabel
1Planning
2Pre-Alpha
3Alpha
4Beta
5Production/Stable
6Mature
7Inactive

Trove classifier groups (894 classifiers as of Sep 2026 — full list: https://pypi.org/classifiers/)

GroupCountExample
Development Status7Development Status :: 5 - Production/Stable
Environment74Environment :: Web Environment
Framework185Framework :: Django :: 5.1
Intended Audience14Intended Audience :: Developers
License84License :: OSI Approved :: MIT License
Natural Language64Natural Language :: English
Operating System43Operating System :: OS Independent
Programming Language102Programming Language :: Python :: 3.12
Topic320Topic :: Software Development :: Libraries
Typing2Typing :: Typed

pythonVersions is extracted from Programming Language :: Python :: 3.N classifiers (3.0 … 3.16 exist today); requiresPython is the authoritative constraint.

pypistats categories

  • downloadsBySystem30d keys: Linux, Windows, Darwin, null (unknown installer/CI), occasionally other.
  • downloadsByPythonMinor30d keys: 2.7, 3.63.14, null.
  • downloadsHistory categories: without_mirrors (default) or with_mirrors (includeMirrors: true).

License normalization (licenseSource)

expression (PEP 639 license_expression, SPDX) → field (short license string ≤ 60 chars) → classifier (License :: … leaf) → null. Projects that paste the whole license text into the field fall back to the classifier; the raw leaves are in licenseClassifiers.

Examples

Dependency due diligence with security and adoption data

{ "packages": ["requests", "fastapi", "langchain"], "downloadsBreakdown": true, "downloadsHistoryDays": 30 }

Audit the exact versions in your lockfile

{ "packages": ["pillow==9.0.0", "urllib3==1.26.5", "cryptography==41.0.0"], "includeDownloads": false, "includeReleases": false }

Lean weekly competitor tracker (small items, cheap to diff)

{ "packages": ["openai", "anthropic", "google-genai", "mistralai"], "fields": ["version", "downloadsWeek", "downloadsMonth", "lastRelease", "releasesLast90d", "vulnerabilityCount"] }

Watch for new MCP / agent projects launching on PyPI (run every 15 min)

{ "mode": "newPackages", "keywords": ["mcp", "agent", "llm"] }

Catch new releases in the LangChain ecosystem

{ "mode": "recentUpdates", "keywords": ["langchain", "langgraph"], "maxItems": 50 }

Output

One item per package (trimmed):

{
"id": "fastapi",
"name": "fastapi",
"version": "0.141.1",
"requestedVersion": null,
"isLatest": true,
"latestVersion": "0.141.1",
"summary": "FastAPI framework, high performance, easy to learn, fast to code, ready for production",
"license": "MIT",
"licenseSource": "expression",
"licenseExpression": "MIT",
"licenseClassifiers": [],
"developmentStatus": "Beta",
"developmentStatusCode": 4,
"requiresPython": ">=3.10",
"pythonVersions": ["3.10", "3.11", "3.12", "3.13", "3.14"],
"requires": [{ "name": "starlette", "normalized": "starlette", "specifier": ">=0.46.0", "extras": [], "marker": null, "extra": null, "url": null }],
"requiresCount": 5,
"requiresOptionalCount": 27,
"extras": ["standard", "standard-no-fastapi-cloud-cli", "all"],
"author": "Sebastián Ramírez",
"authorEmail": "tiangolo@gmail.com",
"owners": [{ "user": "tiangolo", "role": "Owner" }],
"organization": null,
"homepage": "https://github.com/fastapi/fastapi",
"repository": "https://github.com/fastapi/fastapi",
"documentation": "https://fastapi.tiangolo.com/",
"changelog": "https://fastapi.tiangolo.com/release-notes/",
"issues": "https://github.com/fastapi/fastapi/issues",
"downloadsDay": null, "downloadsWeek": null, "downloadsMonth": null,
"downloadsByPythonMinor30d": null,
"downloadsBySystem30d": null,
"downloadsError": "pypistats unavailable: 429 Too Many Requests after 4 attempts: https://pypistats.org/api/packages/fastapi/recent",
"vulnerabilities": [],
"vulnerabilityCount": 0,
"versionsCount": 317, "firstRelease": "2018-12-08T08:14:13.103167Z", "lastRelease": "2026-07-29T17:18:04.364385Z",
"daysSinceLastRelease": 45, "releasesLast90d": 24, "releasesLast365d": 92, "yankedVersionsCount": 0,
"latestFiles": { "count": 2, "wheels": 1, "sdist": true, "totalSize": 557753, "publishedAt": "2026-07-29T17:18:04.364385Z" },
"hasWheel": true, "yanked": false, "yankedReason": null,
"recentVersions": [{ "version": "0.141.1", "publishedAt": "2026-07-29T17:18:04.364385Z", "files": 2, "hasWheel": true, "hasSdist": true, "yanked": false, "requiresPython": ">=3.10", "totalSize": 557753 }],
"pypiUrl": "https://pypi.org/project/fastapi/",
"sourceUrl": "https://pypi.org/pypi/fastapi/json",
"fetchedAt": "2026-09-12T23:29:53.340Z"
}

This sample was captured while pypistats was rate-limiting our IP, so it shows the degraded shape. With pypistats available the download fields are integers and {category: count} maps, e.g. for requests (captured 2026-09-12): downloadsHistory.series entries like { "date": "2026-09-11", "downloads": 42125636 }, downloadsBySystem30d like { "Linux": …, "Darwin": …, "Windows": …, "null": … }, downloadsByPythonMinor30d like { "3.12": …, "3.11": …, "2.7": … }.

FieldMeaning
idPEP 503 normalized name — stable key for joins/dedupe
version, requestedVersion, latestVersion, isLatestReturned version; pinned version if any; newest release on PyPI; whether they match
license, licenseSource, licenseExpression, licenseClassifiersSee License normalization
developmentStatus, developmentStatusCodeFrom the Development Status classifier (null if not declared)
requiresPython, pythonVersionsDeclared constraint; minor versions advertised via classifiers
requires[], requiresCount, requiresOptionalCount, extrasParsed PEP 508 requirements; count of mandatory vs. extra-only deps
author, authorEmail, maintainer, maintainerEmail, owners[], organizationMetadata contacts (Name <email> lists are split into names / e-mails) and PyPI account owners/maintainers
homepage, repository, documentation, changelog, issues, funding, projectUrlsNormalized links (synonyms mapped, GitHub inferred) + raw map
downloadsDay/Week/Month, downloadsByPythonMinor30d, downloadsBySystem30d, downloadsHistory, downloadsErrorpypistats data; downloadsError explains a null (new package, rate limit)
vulnerabilities[], vulnerabilityCountOSV advisories for the returned version: id, aliases, summary, details, fixedIn, link, withdrawn
versionsCount, firstRelease, lastRelease, daysSinceLastRelease, releasesLast90d, releasesLast365d, yankedVersionsCountRelease cadence
latestFiles, hasWheel, yanked, yankedReasonArtifacts of the returned version
recentVersions[]Release history entries
description, descriptionContentTypeOnly when descriptionChars > 0
pypiUrl, sourceUrl, fetchedAtProvenance

Feed items (recentUpdates / newPackages): id (name@version or name), feed, name, version, summary, author, publishedAt, pypiUrl, sourceUrl, fetchedAt.

Use it from code / agents

curl -X POST "https://api.apify.com/v2/acts/yadroo~pypi-package-intel/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"packages":["requests","fastapi"],"fields":["version","license","downloadsMonth","vulnerabilityCount"]}'
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('yadroo/pypi-package-intel').call({ packages: ['langchain', 'llama-index'], downloadsBreakdown: true });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("yadroo/pypi-package-intel").call(run_input={"packages": ["pillow==9.0.0"], "includeDownloads": False})
items = client.dataset(run["defaultDatasetId"]).list_items().items

MCP: add https://mcp.apify.com to your agent (Claude, Cursor, etc.) and call the yadroo/pypi-package-intel tool with the same JSON input.

Pricing

Pay-per-event: $0.001 per run start + $0.002 per item (package or feed item). A due-diligence run on 10 packages costs about $0.021; a newPackages poll returning 40 items about $0.081. Packages/versions that do not exist or could not be fetched are not items and are not charged; batch names into one run to amortize the start fee.

Limits & FAQ

  • Rate limits. PyPI's JSON API is CDN-backed and generous. pypistats.org is IP rate-limited; the actor paces calls (~1.2 s apart) and backs off on 429 (up to ~1 min). If pypistats is rate-limited despite retries, the actor stops calling it for the rest of the run and every item carries downloadsError explaining why — metadata never depends on it. Counts are the same for 24 h, so re-run later for the numbers. Keep downloadsBreakdown/downloadsHistoryDays off for large batches.
  • Freshness. Metadata is live. Downloads are computed once a day by pypistats (BigQuery) with ~1–2 days lag; do not poll download numbers more than once a day. Feeds are near-real-time but only expose the latest ~40 events — poll every 5–15 min to avoid gaps in busy niches.
  • Vulnerabilities are what PyPI reports (OSV / PyPA advisory database) for the returned version; pin versions to audit older releases. An empty array means "none known", not "audited safe".
  • Unknown package or version → no item (not charged); it is listed in the SUMMARY record of the default key-value store (notFound[], and errors[{input, error}] for failed lookups, with counts) and in the run's status message. The run continues with the remaining names and fails only when no package could be fetched.
  • Not supported: search by keyword across PyPI (no public API), per-version download counts (pypistats provides them but only for the last 180 days and per request — on the roadmap), reverse dependencies (needs libraries.io key or deps.dev — roadmap), downloading/inspecting wheels.
  • Roadmap: per-version downloads, deps.dev dependents count, requirements.txt / pyproject upload as input.

Made by Yadroo. Sibling actors: npm-package-intel · github-repo-intel · hackernews-search · stackexchange-search