feat: add Pornhub username scan module - #433
Merged
kaifcodec merged 3 commits intoJul 23, 2026
Merged
Conversation
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().
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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}:"<name>'s Profile - Pornhub.com"title/users/<id>,/model/,/pornstar/,/channels/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 throughcurl_cffiwithimpersonate="chrome"replicates a real Chrome handshake and clears it. No session warm-up is needed (passive fingerprinting, unlike a DataDome cookie wall):httpx(default, or real Chrome UA + full headers)curl_cffiimpersonate="chrome"This lives in a reusable core helper —
user_scanner/core/impersonate.py(impersonate_validate/impersonate_request) — that mirrorsgeneric_validatebut routes through a browser-impersonating session.curl_cffi>=0.7,<1is added topyproject.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
infoPieceblock, then labels the accounttypefrom the resolved namespace:name,user_idname,gender,profile_views,videos_watchedgender,relationship_status,birth_place,measurements,height,weight,ethnicity,star_sign,career_status,career_start_and_end, …)The
typefield follows the existingdev/dockerhub.pyconvention (extra["type"]= User/Organization) and makes the widely-varyingextraself-describing — a consumer can tell a viewer from a verified pornstar directly instead of inferring it from which fields are present. TheinfoPieceextractor is generic, so whatever bio fields a profile fills in are captured automatically.Notes
impersonate.pyhelper is shared with the TripAdvisor (feat: add TripAdvisor username scan module #428) and SpankBang (feat: add SpankBang username scan module #422) PRs — the file is identical in all three, so whichever merges first, the later PRs' copies can be dropped from their diff.Testing
brunolm), models (alex), pornstars (rileyreid→/pornstar/riley-reid, 18-field bio), renamed handles (mike→/users/9db2661), and random → Not Found.pytestpasses except the 2 pre-existing Windowschmod(0)no-op tests, unrelated to this change.