Skip to content

feat: add Pornhub username scan module - #433

Merged
kaifcodec merged 3 commits into
kaifcodec:mainfrom
brunolm:feat/add-pornhub-username-module
Jul 23, 2026
Merged

feat: add Pornhub username scan module#433
kaifcodec merged 3 commits into
kaifcodec:mainfrom
brunolm:feat/add-pornhub-username-module

Conversation

@brunolm

@brunolm brunolm commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

What

Adds a username-based Pornhub profile scan to user_scan/adult/, routed through a browser-impersonating request so it clears Pornhub's TLS-fingerprint bot block.

How it works

Requests https://www.pornhub.com/users/{user}:

Response Result
200 + "<name>'s Profile - Pornhub.com" title Found (viewer)
301/302 → /users/<id>, /model/, /pornstar/, /channels/ Found (renamed handle or promoted creator)
404 Not Found
other status Error

A direct 200 on /users/<name> is always a viewer account; models and pornstars 301-redirect to their own namespace, and a genuinely missing handle just 404s.

Why the new dependency (curl_cffi)

Pornhub returns 410 Gone to Python's default TLS stack (httpx) regardless of headers — it fingerprints the TLS handshake (JA3/JA4), not the User-Agent. Routing through curl_cffi with impersonate="chrome" replicates a real Chrome handshake and clears it. No session warm-up is needed (passive fingerprinting, unlike a DataDome cookie wall):

Approach Result
httpx (default, or real Chrome UA + full headers) 410
curl_cffi impersonate="chrome" 200

This lives in a reusable core helper — user_scanner/core/impersonate.py (impersonate_validate / impersonate_request) — that mirrors generic_validate but routes through a browser-impersonating session. curl_cffi>=0.7,<1 is added to pyproject.toml/requirements.txt, and to the lint job's install step so mypy type-checks against it.

Metadata & account type

On a hit, the module follows the redirect (for models/pornstars) and scrapes the profile's About Me infoPiece block, then labels the account type from the resolved namespace:

  • viewername, user_id
  • modelname, gender, profile_views, videos_watched
  • pornstar → full bio (gender, relationship_status, birth_place, measurements, height, weight, ethnicity, star_sign, career_status, career_start_and_end, …)

The type field follows the existing dev/dockerhub.py convention (extra["type"] = User/Organization) and makes the widely-varying extra self-describing — a consumer can tell a viewer from a verified pornstar directly instead of inferring it from which fields are present. The infoPiece extractor is generic, so whatever bio fields a profile fills in are captured automatically.

Notes

Testing

  • Verified live: viewers (brunolm), models (alex), pornstars (rileyreid/pornstar/riley-reid, 18-field bio), renamed handles (mike/users/9db2661), and random → Not Found.
  • ruff + mypy clean; pytest passes except the 2 pre-existing Windows chmod(0) no-op tests, unrelated to this change.
brunolm added 3 commits July 22, 2026 13:11
Pornhub returns 410 to Python's default TLS fingerprint, so route the /users/
profile check through the browser-impersonating curl_cffi session (no warm-up
needed — passive fingerprinting, like SpankBang). Add the reusable impersonate
helper, the curl_cffi dependency, and install it in the lint job.

Detection: 200 = found, 404 = not found, and a 301 to /users/<id>, /model/,
/pornstar/, or /channels/ (a renamed handle or promoted creator) = found.

Enrich each hit by following the redirect and scraping the profile's About Me
infoPiece block, and label the account type (viewer/model/pornstar/channel)
from the resolved namespace — viewers yield name + id, pornstars a full bio.
impersonate_request() and the session warm-up used a hardcoded DEFAULT_TIMEOUT,
so they ignored the CLI -t flag. Route both through a _timeout() helper that
reads get_global_timeout() and falls back to DEFAULT_TIMEOUT, matching
make_request() / generic_validate().

@kaifcodec kaifcodec left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brunolm Perfect!
Merging it!

@kaifcodec
kaifcodec merged commit b070d9f into kaifcodec:main Jul 23, 2026
2 checks passed
@kaifcodec kaifcodec added the user module addition PRs or issues related to new user_scan module additions label Jul 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

user module addition PRs or issues related to new user_scan module additions

2 participants