Skip to content

feat: bypass Cloudflare bot protection with curl_cffi - #2

Merged
nille merged 1 commit into
mainfrom
feat/cloudflare-bypass
Apr 18, 2026
Merged

feat: bypass Cloudflare bot protection with curl_cffi#2
nille merged 1 commit into
mainfrom
feat/cloudflare-bypass

Conversation

@nille

@nille nille commented Apr 18, 2026

Copy link
Copy Markdown
Owner

Summary

  • When curl_cffi is installed (pip install curl_cffi), API requests use Chrome TLS fingerprint impersonation to bypass Cloudflare JavaScript challenges that block standard HTTP clients with HTTP 403
  • Falls back to stdlib urllib when curl_cffi is not installed — zero required dependencies preserved
  • HTTP 403 errors are now retried with exponential backoff (previously only 429 and 5xx triggered retries)

Background

Boligportal.dk recently enabled Cloudflare bot management, which detects non-browser TLS fingerprints and issues JavaScript challenges. Standard urllib requests get a 403 with cf-mitigated: challenge header. curl_cffi impersonates Chrome's TLS handshake, which Cloudflare accepts.

Changes

  • boligwatch.py: Split _api_request into _api_request_cffi and _api_request_urllib backends, with auto-detection dispatch. Extracted _backoff_delay helper. Added Origin/Referer headers for cffi backend.
  • test_boligwatch.py: Added tests for dispatch logic, backoff helper, and 403 retry behavior (60 total, up from 55)
  • CHANGELOG.md: Documented new feature and 403 retry fix
  • README.md: Added Cloudflare bypass section, updated requirements and installation

Test plan

  • All 60 tests pass
  • Manual test with curl_cffi installed — verify API returns 200
  • Manual test without curl_cffi — verify fallback to urllib
  • Verify --peek mode works end-to-end with Cloudflare active

@nille
nille force-pushed the feat/cloudflare-bypass branch 2 times, most recently from d2eca2c to 338e063 Compare April 18, 2026 09:06
- curl_cffi Chrome TLS impersonation bypasses Cloudflare bot challenges
- Falls back to stdlib urllib when curl_cffi is not installed
- HTTP 403 retried with exponential backoff
- Z suffix date parsing fixed for Python 3.10
- CI: ruff lint + format, mypy type checking, tests on 3.10/3.12/3.14
- README badges: CI, Python version, Ruff, MIT license
- pyproject.toml with ruff and mypy configuration
- Ruff-formatted codebase, all lint issues fixed
@nille
nille force-pushed the feat/cloudflare-bypass branch from 338e063 to 5f6cbe3 Compare April 18, 2026 09:10
@nille
nille merged commit d6c259e into main Apr 18, 2026
5 checks passed
@nille
nille deleted the feat/cloudflare-bypass branch April 18, 2026 09:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant