Python · Async · v1.8

Porntrex API

A fully asynchronous Python API wrapper and scraper for Porntrex. Fetch video metadata, channel information, and model profiles, run search queries, and download media via direct CDN links. Powered by the eaf_base_api networking engine.

$ pip install unofficial-api-for-porntrex 📋
GitHub →
⚠️ Legal Disclaimer
This tool is an unofficial, independent project and is not affiliated with, endorsed by, or sponsored by the target website. This software is provided "as is" for educational and personal purposes only. The developer assumes no responsibility for any consequences arising from the use of this tool, including but not limited to account suspension, IP blocking, or any violation of the target website's Terms of Service. Users are solely responsible for ensuring their use complies with all applicable laws and policies. Use at your own risk.
💚 Support & Commercial Licensing
If you find this project helpful, please consider donating to support its continued development!

Other Options:
PayPal
Ko-Fi

For extended features, enterprise integrations, or custom commercial licensing, please contact EchterAlsFakeBS@proton.me.

📦 Installation

Install from PyPI using pip:

bash
pip install unofficial-api-for-porntrex
Note
Requires Python ≥ 3.12 and eaf-base-api>=4.0.0. The compatible networking core is installed automatically.

🚀 Quick Start

All operations are asynchronous and should run within an async context:

python
import asyncio
from porntrex_api import Client
from base_api import DownloadConfigRAW

async def main():
    client = Client()

    # Fetch a video
    video = await client.get_video("https://www.porntrex.com/videos/12345/example-video/")

    # Access metadata
    print(video.title)
    print(video.video_qualities)  # list of available resolutions (e.g., ["360", "480", "720", "1080"])

    # Download video using RAW downloader (direct MP4)
    config = DownloadConfigRAW(quality="best", path="./downloads")
    await video.download(configuration=config)

asyncio.run(main())

⚙️ Configuration

Porntrex API uses eaf_base_api 4.x for networking. You can configure a proxy, timeouts, request attempts, limits, and headers via a custom BaseCore.

Please refer to the eaf_base_api Documentation for the complete reference on how to set up RuntimeConfig and BaseCore.

python
from base_api import BaseCore
from base_api.modules.config import RuntimeConfig
from porntrex_api import Client

my_config = RuntimeConfig()
my_config.proxy = "socks5://127.0.0.1:9050"
my_config.request_attempts = 4

core = BaseCore(configuration=my_config)
client = Client(core=core)

IteratorConfig, retry policy, and custom scrape errors

Iterator methods take one iterator_config object. Keep load_specific_sources=("html",) when replacing Porntrex's package defaults so full Video metadata is loaded.

python
from base_api import ErrorAction, ErrorMode, ResultOrder, RetryPolicy, ScrapeErrorContext
from base_api.modules.config import IteratorConfig

async def handle_scrape_error(context: ScrapeErrorContext) -> ErrorAction:
    print(context.stage, context.url, context.error, context.attempt)
    return ErrorAction.RETRY

retry = RetryPolicy(
    max_attempts=3, base_delay=0.5, multiplier=2, max_delay=8, jitter=0.25
)
iterator_config = IteratorConfig(
    max_page_concurrency=2,
    max_item_concurrency=5,
    order=ResultOrder.ORIGINAL,
    load_specific_sources=("html",),
    page_retry=retry,
    item_retry=retry,
    page_error_mode=ErrorMode.SKIP,
    item_error_mode=ErrorMode.YIELD,
    page_error_handler=handle_scrape_error,
    item_error_handler=handle_scrape_error,
)

async for result in client.search("college", iterator_config=iterator_config):
    print(result.unwrap().title if result.succeeded else result.error)

max_attempts includes the first attempt. page_error_handler and item_error_handler are routed independently. This example shares one callable because it intentionally applies the same retry decision to both stages; use separate callables when page and item policy differ.


🔌 Client

The main class to interact with the Porntrex scraper ecosystem.

python
from porntrex_api import Client
from base_api import BaseCore

client = Client()
client_custom = Client(core=BaseCore())

Constructor Parameters

  • core BaseCore — Networking core instance (default: BaseCore())

Methods

Fetch Video get_video()

async
Fetches metadata for a video URL and returns a populated Video object.
await client.get_video( url: str, load_html: bool = True ) -> Video

Parameters

  • url str — The Porntrex video page URL
  • load_html bool — If True (default), fetches and extracts metadata immediately

Returns

→ Video

Fetch Model get_model()

async
Fetches a model profile profile page and returns a populated Model object.
await client.get_model( url: str, load_html: bool = True ) -> Model

Parameters

  • url str — The Porntrex model profile page URL
  • load_html bool — If True (default), fetches and extracts metadata immediately

Returns

→ Model

Fetch Channel get_channel()

async
Fetches a publisher channel page and returns a populated Channel object.
await client.get_channel( url: str, load_html: bool = True ) -> Channel

Parameters

  • url str — The Porntrex channel page URL
  • load_html bool — If True (default), fetches and extracts metadata immediately

Returns

→ Channel

Search Videos search()

async
Queries Porntrex search and streams video results via an asynchronous generator.
async for result in client.search( query: str, pages: int = 2, iterator_config: IteratorConfig | None = None ) -> AsyncGenerator[ScrapeResult[Video], None]

Parameters

  • query str — Search query string
  • pages int — Number of search pages to parse (default: 2)
  • iterator_config IteratorConfig | None — Per-iterator concurrency, source loading, ordering, retry, error-mode, and custom-handler settings. The package default loads the html source.

Returns

→ AsyncGenerator[ScrapeResult[Video], None]

🎬 Video

dataclass Inherits from BaseMedia. Represents a single video with details extracted from Porntrex's script variables.

Attributes

AttributeTypeDescription
urlstrThe video page URL
titlestr | NoneVideo title
video_idstr | NoneUnique video key ID
categorieslist[str] | NoneList of category labels
tagslist[str] | NoneList of tags
license_codestr | NoneLicense code metadata
lrcstr | NoneLRC string identifier
rndstr | NoneRnd hash value used in player config
authorstr | NoneUsername of the uploader
publish_datestr | NoneUploader date description
viewsstr | NoneNumber of views
durationstr | NoneDuration string (e.g. 12:34)
descriptionstr | NoneDescription of the video
subscribers_countstr | NoneAuthor's subscriber count
thumbnailstr | NoneCover image thumbnail URL
direct_download_urlslist[str] | NoneRaw CDN download URLs ordered by resolution
video_qualitieslist[str] | NoneSorted list of available resolutions (e.g. ["360", "480", "720", "1080"])

Methods

Download Video download()

async
Downloads the video directly from CDN server using DownloadConfigRAW.
await video.download( configuration: DownloadConfigRAW ) -> bool

Parameters

Returns

→ bool

Model

dataclass Inherits from BaseMedia via ChannelModelHelper. Represents a model profile page.

Attributes

AttributeTypeDescription
urlstrModel profile page URL
namestr | NoneName of the model
informationdict | NoneKey-value parameters extracted from the sidebar info container (e.g. age, views)
thumbnailstr | NoneProfile picture URL

Methods

Get Model Videos videos()

async
Iterates over the videos uploaded/featuring this model.
async for result in model.videos( pages: int = 2, iterator_config: IteratorConfig | None = None ) -> AsyncGenerator[ScrapeResult[Video], None]

Parameters

  • pages int — Pages to parse (default: 2)
  • iterator_config IteratorConfig | None — Per-iterator concurrency, source loading, ordering, retry, error-mode, and custom-handler settings. The package default loads the html source.

Returns

→ AsyncGenerator[ScrapeResult[Video], None]

📺 Channel

dataclass Inherits from BaseMedia via ChannelModelHelper. Represents a publisher channel.

Attributes

AttributeTypeDescription
urlstrChannel page URL
namestr | NoneName of the channel
informationdict | NoneSidebar metadata key-value properties
thumbnailstr | NoneChannel cover profile picture URL

Methods

Get Channel Videos videos()

async
Iterates over the videos uploaded to this channel.
async for result in channel.videos( pages: int = 2, iterator_config: IteratorConfig | None = None ) -> AsyncGenerator[ScrapeResult[Video], None]

Parameters

  • pages int — Pages to parse (default: 2)
  • iterator_config IteratorConfig | None — Per-iterator concurrency, source loading, ordering, retry, error-mode, and custom-handler settings. The package default loads the html source.

Returns

→ AsyncGenerator[ScrapeResult[Video], None]

⬇️ Downloading Options

Porntrex media files are served directly as MP4 files. Configure downloads using DownloadConfigRAW:

python
from base_api import DownloadConfigRAW

config = DownloadConfigRAW(
    quality="best",            # "best", "half", "worst", or height int (e.g. 720)
    path="./downloads",        # Destination path
    no_title=False,            # If False, automatically appends title + ".mp4"
    allow_multipart=True,      # Enable multi-threaded range requests
    max_workers=5              # Concurrent download segment threads
)

success = await video.download(configuration=config)

For a detailed breakdown of all available settings inside DownloadConfigRAW, please read the eaf_base_api Documentation.

📊 Scraping Results

Iterators like client.search() and model.videos() return async generators that yield ScrapeResult containers:

python
async for result in client.search("college", pages=3):
    if result.succeeded:
        video = result.unwrap()     # The Video object
        print(video.title)
    else:
        print(f"{result.stage} failed: {result.error}")

ScrapeResult Attributes

AttributeTypeDescription
succeededboolWhether the scraping task succeeded.
unwrap()VideoReturns the parsed video, or raises the stored error.
itemVideo | NoneThe parsed video when successful.
errorScrapeOperationError | NoneThe typed page or item failure.
stageScrapeStageThe iterator stage: PAGE or ITEM.

⚠️ Error Handling

Source loaders translate request failures into exceptions from porntrex_api.modules.errors. Calls that load media expose ordinary loader failures through base_api.MediaLoadError (or MediaLoadErrors for several sources); inspect original_error/errors as shown. Operations outside media loading may still raise package or core exceptions directly.

ExceptionTrigger Cause
NotFoundServer returned HTTP 404 (e.g. video/model deleted)
NetworkErrorRequest failed due to HTTP connection problems
BotDetectionCloudflare challenge block detected
ProxyErrorProxy configuration failed or proxy is down
UnknownNetworkErrorUnexpected network errors
DownloadFailedRaw segmented download failed
python
from base_api import MediaLoadError
from porntrex_api.modules.errors import NotFound, BotDetection

try:
    video = await client.get_video(url)
except MediaLoadError as error:
    if isinstance(error.original_error, NotFound):
        print("This video does not exist!")
    elif isinstance(error.original_error, BotDetection):
        print("Scraper was blocked by anti-bot measures.")
    else:
        raise

📝 Changelog

1.8 — 2026-08-11 d86ccad

  • Added generic ScrapeResult[Video] return annotations and the py.typed marker.
  • Changed unset iterator retry policies to resolve from the live RuntimeConfig.
  • Updated the package version from 1.7 to 1.8.

IteratorConfig synchronization — 2026-08-08 aa51d6b

  • Replaced the legacy per-call iterator arguments with IteratorConfig.
  • Preserved the required html source loading for search, model, and channel results.

Core v4 migration — 2026-08-07 d731458

  • Migrated to eaf-base-api 4.x with explicit request methods and source-aware media loading.
  • Added bounded retries, structured errors, extractor validation, improved concurrency, and deterministic stream cleanup.
  • Removed obsolete compatibility code and adopted the current ScrapeResult model.

🖥️ Supported Platforms

PlatformArchitectureStatus
Windows 11x64✅ Tested
macOS Sequoiax86_64 / arm64✅ Tested
Linux (Arch)x86_64✅ Tested
Android 16aarch64✅ Tested