funbrowser 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- funbrowser-0.1.0/.gitignore +44 -0
- funbrowser-0.1.0/LICENSE +21 -0
- funbrowser-0.1.0/PKG-INFO +316 -0
- funbrowser-0.1.0/README.md +275 -0
- funbrowser-0.1.0/funbrowser/__init__.py +120 -0
- funbrowser-0.1.0/funbrowser/_cdp.py +181 -0
- funbrowser-0.1.0/funbrowser/_errors.py +32 -0
- funbrowser-0.1.0/funbrowser/_flags.py +89 -0
- funbrowser-0.1.0/funbrowser/_launcher.py +153 -0
- funbrowser-0.1.0/funbrowser/browser.py +281 -0
- funbrowser-0.1.0/funbrowser/context.py +163 -0
- funbrowser-0.1.0/funbrowser/context_pool.py +162 -0
- funbrowser-0.1.0/funbrowser/element.py +258 -0
- funbrowser-0.1.0/funbrowser/fingerprint/__init__.py +14 -0
- funbrowser-0.1.0/funbrowser/fingerprint/data.py +74 -0
- funbrowser-0.1.0/funbrowser/fingerprint/presets.py +588 -0
- funbrowser-0.1.0/funbrowser/geo.py +139 -0
- funbrowser-0.1.0/funbrowser/humanly.py +188 -0
- funbrowser-0.1.0/funbrowser/panel.py +1181 -0
- funbrowser-0.1.0/funbrowser/pool.py +152 -0
- funbrowser-0.1.0/funbrowser/profile.py +73 -0
- funbrowser-0.1.0/funbrowser/proxy.py +236 -0
- funbrowser-0.1.0/funbrowser/py.typed +0 -0
- funbrowser-0.1.0/funbrowser/solver/__init__.py +12 -0
- funbrowser-0.1.0/funbrowser/solver/bridge.py +167 -0
- funbrowser-0.1.0/funbrowser/solver/client.py +244 -0
- funbrowser-0.1.0/funbrowser/solver/scripts/__init__.py +0 -0
- funbrowser-0.1.0/funbrowser/solver/scripts/_bootstrap.js +30 -0
- funbrowser-0.1.0/funbrowser/solver/scripts/funcaptcha.js +74 -0
- funbrowser-0.1.0/funbrowser/solver/scripts/geetest.js +76 -0
- funbrowser-0.1.0/funbrowser/solver/scripts/hcaptcha.js +76 -0
- funbrowser-0.1.0/funbrowser/solver/scripts/recaptcha_v2.js +79 -0
- funbrowser-0.1.0/funbrowser/solver/scripts/recaptcha_v3.js +45 -0
- funbrowser-0.1.0/funbrowser/solver/scripts/turnstile.js +60 -0
- funbrowser-0.1.0/funbrowser/stealth/__init__.py +13 -0
- funbrowser-0.1.0/funbrowser/stealth/flags.py +54 -0
- funbrowser-0.1.0/funbrowser/stealth/patches.py +214 -0
- funbrowser-0.1.0/funbrowser/stealth/scripts/__init__.py +0 -0
- funbrowser-0.1.0/funbrowser/stealth/scripts/_camouflage.js +32 -0
- funbrowser-0.1.0/funbrowser/stealth/scripts/_cleanup.js +8 -0
- funbrowser-0.1.0/funbrowser/stealth/scripts/audio_noise.js +32 -0
- funbrowser-0.1.0/funbrowser/stealth/scripts/canvas_noise.js +43 -0
- funbrowser-0.1.0/funbrowser/stealth/scripts/chrome_runtime.js +53 -0
- funbrowser-0.1.0/funbrowser/stealth/scripts/hardware.js +15 -0
- funbrowser-0.1.0/funbrowser/stealth/scripts/languages.js +13 -0
- funbrowser-0.1.0/funbrowser/stealth/scripts/permissions.js +15 -0
- funbrowser-0.1.0/funbrowser/stealth/scripts/platform.js +18 -0
- funbrowser-0.1.0/funbrowser/stealth/scripts/plugins.js +37 -0
- funbrowser-0.1.0/funbrowser/stealth/scripts/screen_props.js +18 -0
- funbrowser-0.1.0/funbrowser/stealth/scripts/webdriver.js +14 -0
- funbrowser-0.1.0/funbrowser/stealth/scripts/webgl.js +27 -0
- funbrowser-0.1.0/funbrowser/stealth/scripts/webrtc.js +45 -0
- funbrowser-0.1.0/funbrowser/tab.py +345 -0
- funbrowser-0.1.0/funbrowser/tls/__init__.py +25 -0
- funbrowser-0.1.0/funbrowser/tls/ca.py +181 -0
- funbrowser-0.1.0/funbrowser/tls/http.py +145 -0
- funbrowser-0.1.0/funbrowser/tls/mitm.py +326 -0
- funbrowser-0.1.0/pyproject.toml +159 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.egg-info/
|
|
6
|
+
.eggs/
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
pip-wheel-metadata/
|
|
10
|
+
|
|
11
|
+
# Virtual environments
|
|
12
|
+
.venv/
|
|
13
|
+
venv/
|
|
14
|
+
env/
|
|
15
|
+
|
|
16
|
+
# Tooling caches
|
|
17
|
+
.mypy_cache/
|
|
18
|
+
.ruff_cache/
|
|
19
|
+
.pytest_cache/
|
|
20
|
+
.tox/
|
|
21
|
+
.coverage
|
|
22
|
+
.coverage.*
|
|
23
|
+
htmlcov/
|
|
24
|
+
|
|
25
|
+
# Editors
|
|
26
|
+
.idea/
|
|
27
|
+
.vscode/
|
|
28
|
+
*.swp
|
|
29
|
+
*.swo
|
|
30
|
+
|
|
31
|
+
# OS
|
|
32
|
+
.DS_Store
|
|
33
|
+
Thumbs.db
|
|
34
|
+
|
|
35
|
+
# FunBrowser-specific
|
|
36
|
+
# Profiles created by browser launches during local development
|
|
37
|
+
profiles/
|
|
38
|
+
*.profile/
|
|
39
|
+
# Example artifacts
|
|
40
|
+
example.png
|
|
41
|
+
examples/*.png
|
|
42
|
+
# Secrets: never commit API keys
|
|
43
|
+
.env
|
|
44
|
+
.env.local
|
funbrowser-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 FunBrowser contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: funbrowser
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Undetect browser SDK for Python with built-in captcha solving via funsolver.com
|
|
5
|
+
Project-URL: Homepage, https://github.com/WhyY0u/funBrowser
|
|
6
|
+
Project-URL: Documentation, https://github.com/WhyY0u/funBrowser#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/WhyY0u/funBrowser
|
|
8
|
+
Project-URL: Issues, https://github.com/WhyY0u/funBrowser/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/WhyY0u/funBrowser/blob/main/CHANGELOG.md
|
|
10
|
+
Project-URL: FunSolver API, https://funsolver.com
|
|
11
|
+
Author: FunBrowser contributors
|
|
12
|
+
License-Expression: MIT
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Keywords: anti-bot,anti-detect,antibot,antidetect,async,asyncio,automation,bot-detection,browser,browser-automation,captcha,captcha-bypass,captcha-solver,cdp,chrome,chrome-devtools-protocol,cloudflare,cloudflare-bypass,fingerprint,fingerprint-spoofing,funcaptcha,funsolver,geetest,hcaptcha,headless,headless-chrome,proxy,python,recaptcha,scraping,stealth,stealth-browser,turnstile,undetect,undetected,web-scraping
|
|
15
|
+
Classifier: Development Status :: 4 - Beta
|
|
16
|
+
Classifier: Framework :: AsyncIO
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Operating System :: MacOS
|
|
20
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
21
|
+
Classifier: Operating System :: OS Independent
|
|
22
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
23
|
+
Classifier: Programming Language :: Python :: 3
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
27
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
|
|
28
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
|
|
29
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
30
|
+
Classifier: Topic :: Software Development :: Testing
|
|
31
|
+
Classifier: Typing :: Typed
|
|
32
|
+
Requires-Python: >=3.11
|
|
33
|
+
Requires-Dist: httpx>=0.27
|
|
34
|
+
Requires-Dist: websockets>=12.0
|
|
35
|
+
Provides-Extra: panel
|
|
36
|
+
Requires-Dist: aiohttp>=3.9; extra == 'panel'
|
|
37
|
+
Provides-Extra: tls
|
|
38
|
+
Requires-Dist: cryptography>=42; extra == 'tls'
|
|
39
|
+
Requires-Dist: curl-cffi>=0.7; extra == 'tls'
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
|
|
42
|
+
# FunBrowser
|
|
43
|
+
|
|
44
|
+
[](https://pypi.org/project/funbrowser/)
|
|
45
|
+
[](https://pypi.org/project/funbrowser/)
|
|
46
|
+
[](https://github.com/WhyY0u/funBrowser/blob/main/LICENSE)
|
|
47
|
+
|
|
48
|
+
**Undetect / anti-detect browser SDK for Python.** Drives real Chrome through
|
|
49
|
+
the DevTools Protocol with built-in stealth patches, customisable browser
|
|
50
|
+
fingerprints (UA, GPU, screen, timezone, CPU cores, …), full proxy support,
|
|
51
|
+
human-like input timing, browser-pool / context-pool farming, an optional
|
|
52
|
+
local web panel, and automatic captcha solving for **Cloudflare Turnstile**,
|
|
53
|
+
**reCAPTCHA v2 / v3**, **hCaptcha**, **FunCaptcha**, and **GeeTest** through
|
|
54
|
+
[funsolver.com](https://funsolver.com).
|
|
55
|
+
|
|
56
|
+
Built for web scraping, browser automation, and bypassing antibot services
|
|
57
|
+
(Cloudflare, DataDome, PerimeterX, Akamai) without the Selenium / Playwright
|
|
58
|
+
leaks that get scripts flagged.
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install funbrowser # core: stealth + automation + solver
|
|
62
|
+
pip install funbrowser[panel] # + local web panel for the pool
|
|
63
|
+
pip install funbrowser[tls] # + browser-grade TLS impersonation
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Quick start
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
import asyncio
|
|
70
|
+
import funbrowser
|
|
71
|
+
|
|
72
|
+
async def main():
|
|
73
|
+
async with await funbrowser.start(headless=True) as browser:
|
|
74
|
+
tab = await browser.get("https://example.com")
|
|
75
|
+
print(await tab.evaluate("document.title"))
|
|
76
|
+
# → Example Domain
|
|
77
|
+
print(await tab.evaluate("navigator.userAgent"))
|
|
78
|
+
# → Mozilla/5.0 ... Chrome/... — no "HeadlessChrome"
|
|
79
|
+
|
|
80
|
+
asyncio.run(main())
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
# Full automation: stealth + proxy + auto-solve captchas + humanly input
|
|
85
|
+
async with await funbrowser.start(
|
|
86
|
+
headless=True,
|
|
87
|
+
proxy="user:pass@us-1.proxy.io:8080", # any common format works
|
|
88
|
+
api_key="fs_xxx", # funsolver.com key
|
|
89
|
+
humanly=True, # Bezier mouse + typing rhythm
|
|
90
|
+
fingerprint=funbrowser.presets.windows_11_nvidia_rtx_4070(),
|
|
91
|
+
) as browser:
|
|
92
|
+
tab = await browser.get("https://target-with-captcha.com")
|
|
93
|
+
# captchas auto-solve in the background
|
|
94
|
+
await tab.fill("#email", "alice@example.com")
|
|
95
|
+
await tab.click("button[type=submit]")
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Features
|
|
99
|
+
|
|
100
|
+
### Stealth (passes 25/25 standard antidetect probes)
|
|
101
|
+
|
|
102
|
+
- `navigator.webdriver` → undefined, **with native `toString` camouflage**
|
|
103
|
+
- UA + Client Hints with `HeadlessChrome` stripped
|
|
104
|
+
- `chrome.runtime`, `plugins`, `languages`, permissions consistency
|
|
105
|
+
- **Real GPU** for WebGL (`--use-gl=angle`, not SwiftShader)
|
|
106
|
+
- Canvas + audio readout noise to break fingerprint tracking
|
|
107
|
+
- WebRTC IP leak blocked (flag-level + SDP filter)
|
|
108
|
+
- iframe stealth propagation
|
|
109
|
+
- Geo auto-couples timezone + locale to proxy exit IP
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
uv run python examples/detect_check.py # self-audit
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Fingerprint customisation
|
|
116
|
+
|
|
117
|
+
17 ready presets (Windows × NVIDIA / Intel / AMD, macOS Apple Silicon /
|
|
118
|
+
Intel, Linux, plus 4 Android mobile) + arbitrary custom `Fingerprint(...)`.
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from funbrowser import Fingerprint, presets
|
|
122
|
+
|
|
123
|
+
fp = presets.macos_apple_silicon_m3_pro().merge(
|
|
124
|
+
Fingerprint(timezone="Asia/Tokyo", languages=("ja-JP", "ja", "en"))
|
|
125
|
+
)
|
|
126
|
+
async with await funbrowser.start(fingerprint=fp) as browser:
|
|
127
|
+
...
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Humanly mode (Bezier-curve mouse + typing rhythm)
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
async with await funbrowser.start(humanly=True) as browser:
|
|
134
|
+
await tab.click("button") # cursor curves toward target
|
|
135
|
+
await tab.type("#email", "ada") # per-keystroke random delay
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Presets: `humanly.FAST`, `humanly.DEFAULT`, `humanly.CAREFUL`, plus arbitrary
|
|
139
|
+
custom `HumanBehavior(...)`.
|
|
140
|
+
|
|
141
|
+
### Captcha auto-solve
|
|
142
|
+
|
|
143
|
+
Paste a [funsolver.com](https://funsolver.com) API key. Five captcha
|
|
144
|
+
families detected on-page and solved automatically:
|
|
145
|
+
|
|
146
|
+
| | API method | Page integration |
|
|
147
|
+
|---|---|---|
|
|
148
|
+
| Cloudflare Turnstile | `solve_turnstile` | `.cf-turnstile` widgets |
|
|
149
|
+
| reCAPTCHA v2 (+ Enterprise) | `solve_recaptcha_v2` | `.g-recaptcha` widgets |
|
|
150
|
+
| reCAPTCHA v3 (+ Enterprise) | `solve_recaptcha_v3` | hooks `grecaptcha.execute()` |
|
|
151
|
+
| hCaptcha | `solve_hcaptcha` | `.h-captcha` widgets |
|
|
152
|
+
| FunCaptcha / Arkose | `solve_funcaptcha` | `[data-pkey]` elements |
|
|
153
|
+
| GeeTest v3 + v4 | `solve_geetest` | hooks `initGeetest` / `initGeetest4` |
|
|
154
|
+
|
|
155
|
+
### Proxies (every format)
|
|
156
|
+
|
|
157
|
+
`host:port`, `host:port:user:pass`, `user:pass@host:port`, `host:port@user:pass`,
|
|
158
|
+
`socks5://...`, `chrome` URL form — all auto-parsed. HTTP/HTTPS auth flows
|
|
159
|
+
through CDP automatically.
|
|
160
|
+
|
|
161
|
+
### Persistent profiles
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
from funbrowser import Profile
|
|
165
|
+
|
|
166
|
+
alice = Profile.ensure("alice") # ./funbrowser_profiles/alice
|
|
167
|
+
async with await funbrowser.start(user_data_dir=alice) as browser:
|
|
168
|
+
# cookies + localStorage + login state persist between runs
|
|
169
|
+
...
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Browser farming — `BrowserPool` and `ContextPool`
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
from funbrowser import BrowserPool, ContextPool
|
|
176
|
+
|
|
177
|
+
# Process pool — full Chrome per slot (max isolation)
|
|
178
|
+
async with BrowserPool(
|
|
179
|
+
size=5,
|
|
180
|
+
proxies=["proxy1:8080", "proxy2:8080", "proxy3:8080"],
|
|
181
|
+
headless=True,
|
|
182
|
+
mini=True,
|
|
183
|
+
) as pool:
|
|
184
|
+
async def scrape(browser):
|
|
185
|
+
tab = await browser.get("https://example.com")
|
|
186
|
+
return await tab.evaluate("document.title")
|
|
187
|
+
|
|
188
|
+
results = await pool.run_all([scrape] * 100)
|
|
189
|
+
|
|
190
|
+
# Context pool — 1 Chrome + N isolated contexts (~7-10x less RAM)
|
|
191
|
+
async with ContextPool(size=10, headless=True, mini=True) as pool:
|
|
192
|
+
async def scrape(ctx):
|
|
193
|
+
tab = await ctx.get("https://example.com")
|
|
194
|
+
return await tab.evaluate("document.title")
|
|
195
|
+
|
|
196
|
+
results = await pool.run_all([scrape] * 100)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Memory comparison on the same 10-slot workload:
|
|
200
|
+
- `BrowserPool(size=10)` → ~1.0 GB
|
|
201
|
+
- `ContextPool(size=10)` → ~260 MB (one Chrome + 10 contexts)
|
|
202
|
+
|
|
203
|
+
### `mini=True` mode
|
|
204
|
+
|
|
205
|
+
Curated set of Chrome flags that cut RAM / CPU / disk per browser
|
|
206
|
+
(~50% lower RSS): site isolation off, background throttling, audio
|
|
207
|
+
muted, extensions / sync / translate disabled, small disk caches,
|
|
208
|
+
V8 heap cap. Combines with stealth — does **not** turn off the real
|
|
209
|
+
GPU. Works on `Browser`, `BrowserPool`, and `ContextPool` alike.
|
|
210
|
+
|
|
211
|
+
### TLS fingerprint impersonation (`pip install funbrowser[tls]`)
|
|
212
|
+
|
|
213
|
+
Script-level HTTP that picks JA3/JA4 from real-browser profiles:
|
|
214
|
+
|
|
215
|
+
```python
|
|
216
|
+
from funbrowser.tls import ImpersonatedHTTPClient
|
|
217
|
+
|
|
218
|
+
async with ImpersonatedHTTPClient(profile="chrome131") as http:
|
|
219
|
+
r = await http.get("https://protected-api.com/endpoint")
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
23 supported profiles: `chrome99..chrome133a`, `safari15..safari18`,
|
|
223
|
+
`firefox133/135`, Android variants. See
|
|
224
|
+
[docs/M10_M11_DESIGN.md](docs/M10_M11_DESIGN.md) for the deeper
|
|
225
|
+
browser-traffic mitm proxy roadmap.
|
|
226
|
+
|
|
227
|
+
### Local web panel (`pip install funbrowser[panel]`)
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
from funbrowser import BrowserPool, Panel
|
|
231
|
+
|
|
232
|
+
async with BrowserPool(size=5) as pool:
|
|
233
|
+
async with Panel(pool) as panel:
|
|
234
|
+
print(panel.url) # http://127.0.0.1:8765
|
|
235
|
+
await long_running_task()
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Black-and-white dashboard with: pool stats, FunSolver balance, browser
|
|
239
|
+
fleet table (proxy / geo / fingerprint / open tabs / per-row goto +
|
|
240
|
+
screenshot), activity log (panel actions + per-browser captcha solves),
|
|
241
|
+
quick actions, and a **script runner** — upload an `async def
|
|
242
|
+
main(browser)` script and run it on one browser or fan it out across
|
|
243
|
+
the whole pool, with per-run stdout / return / traceback captured.
|
|
244
|
+
|
|
245
|
+
## Documentation
|
|
246
|
+
|
|
247
|
+
- [docs/stealth.md](docs/stealth.md) — anti-detect coverage in depth
|
|
248
|
+
- [docs/captchas.md](docs/captchas.md) — solver integration guide
|
|
249
|
+
- [docs/farming.md](docs/farming.md) — `BrowserPool` vs `ContextPool`
|
|
250
|
+
- [docs/panel.md](docs/panel.md) — the local web dashboard
|
|
251
|
+
- [docs/M10_M11_DESIGN.md](docs/M10_M11_DESIGN.md) — TLS + engine-layer roadmap
|
|
252
|
+
- [examples/](examples/) — runnable demos for every feature
|
|
253
|
+
|
|
254
|
+
## Self-audit
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
uv run python examples/detect_check.py
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
```
|
|
261
|
+
[navigator.* basics] 9/9 PASS
|
|
262
|
+
[chrome runtime + iframe] 6/6 PASS
|
|
263
|
+
[stealth-detection probes] 5/5 PASS
|
|
264
|
+
[WebGL / canvas / audio] 4/4 PASS
|
|
265
|
+
[WebRTC IP leak] 1/1 PASS
|
|
266
|
+
|
|
267
|
+
score: 25/25 (100%)
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Roadmap
|
|
271
|
+
|
|
272
|
+
| | Milestone | Status |
|
|
273
|
+
|---|---|---|
|
|
274
|
+
| M0 | Bootstrap | done |
|
|
275
|
+
| M1 | CDP core + Tab API | done |
|
|
276
|
+
| M2 | Stealth Tier 1 + 2 | done |
|
|
277
|
+
| M2.5 | Fingerprint customisation | done |
|
|
278
|
+
| M3 | Solver bridge + Turnstile | done |
|
|
279
|
+
| M4 | reCAPTCHA / hCaptcha / FunCaptcha / GeeTest | done |
|
|
280
|
+
| M5 | Production hardening (proxies, profiles, retries, multi-tab) | done |
|
|
281
|
+
| M5.5 | DX Tier S (auto-wait + ElementHandle + cookies + block_urls) | done |
|
|
282
|
+
| M5.5+ | Humanly mode | done |
|
|
283
|
+
| M5.5++ | WebRTC + toString camouflage + geo auto-couple | done |
|
|
284
|
+
| M5.5+++ | Mobile presets + expanded catalog | done |
|
|
285
|
+
| M5.6 | BrowserPool | done |
|
|
286
|
+
| M5.7 | Web Panel (+ FunSolver balance + per-browser logs + scripts) | done |
|
|
287
|
+
| M5.8 | Mini mode | done |
|
|
288
|
+
| M6 | **v0.1 release** | **in progress** |
|
|
289
|
+
| M10a | TLS HTTP client (curl_cffi) | done |
|
|
290
|
+
| M11-alt | ContextPool (lightweight pool) | done |
|
|
291
|
+
| M7 | Fingerprint consistency (Tier 3) | post-v0.1 |
|
|
292
|
+
| M8 | Real fingerprint pool (Tier 4) | post-v0.1 |
|
|
293
|
+
| M9 | Deep WebGL / canvas / shader spoofing | post-v0.1 |
|
|
294
|
+
| M10b | mitm proxy for Chrome traffic (production-grade) | post-v0.1 |
|
|
295
|
+
| M11 | Browser fork (Camoufox / Chromium) | post-v0.1 |
|
|
296
|
+
| M12 | Tauri UI for manual mode | post-v0.1 |
|
|
297
|
+
|
|
298
|
+
## Development
|
|
299
|
+
|
|
300
|
+
Uses [uv](https://docs.astral.sh/uv/) for env + deps.
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
uv sync # install
|
|
304
|
+
uv run pytest -q # full test suite (173 tests)
|
|
305
|
+
uv run ruff check . && uv run ruff format --check .
|
|
306
|
+
uv run mypy funbrowser
|
|
307
|
+
uv run python examples/detect_check.py
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## Contributing
|
|
311
|
+
|
|
312
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). Issues + PRs welcome.
|
|
313
|
+
|
|
314
|
+
## License
|
|
315
|
+
|
|
316
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# FunBrowser
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/funbrowser/)
|
|
4
|
+
[](https://pypi.org/project/funbrowser/)
|
|
5
|
+
[](https://github.com/WhyY0u/funBrowser/blob/main/LICENSE)
|
|
6
|
+
|
|
7
|
+
**Undetect / anti-detect browser SDK for Python.** Drives real Chrome through
|
|
8
|
+
the DevTools Protocol with built-in stealth patches, customisable browser
|
|
9
|
+
fingerprints (UA, GPU, screen, timezone, CPU cores, …), full proxy support,
|
|
10
|
+
human-like input timing, browser-pool / context-pool farming, an optional
|
|
11
|
+
local web panel, and automatic captcha solving for **Cloudflare Turnstile**,
|
|
12
|
+
**reCAPTCHA v2 / v3**, **hCaptcha**, **FunCaptcha**, and **GeeTest** through
|
|
13
|
+
[funsolver.com](https://funsolver.com).
|
|
14
|
+
|
|
15
|
+
Built for web scraping, browser automation, and bypassing antibot services
|
|
16
|
+
(Cloudflare, DataDome, PerimeterX, Akamai) without the Selenium / Playwright
|
|
17
|
+
leaks that get scripts flagged.
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install funbrowser # core: stealth + automation + solver
|
|
21
|
+
pip install funbrowser[panel] # + local web panel for the pool
|
|
22
|
+
pip install funbrowser[tls] # + browser-grade TLS impersonation
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick start
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
import asyncio
|
|
29
|
+
import funbrowser
|
|
30
|
+
|
|
31
|
+
async def main():
|
|
32
|
+
async with await funbrowser.start(headless=True) as browser:
|
|
33
|
+
tab = await browser.get("https://example.com")
|
|
34
|
+
print(await tab.evaluate("document.title"))
|
|
35
|
+
# → Example Domain
|
|
36
|
+
print(await tab.evaluate("navigator.userAgent"))
|
|
37
|
+
# → Mozilla/5.0 ... Chrome/... — no "HeadlessChrome"
|
|
38
|
+
|
|
39
|
+
asyncio.run(main())
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
# Full automation: stealth + proxy + auto-solve captchas + humanly input
|
|
44
|
+
async with await funbrowser.start(
|
|
45
|
+
headless=True,
|
|
46
|
+
proxy="user:pass@us-1.proxy.io:8080", # any common format works
|
|
47
|
+
api_key="fs_xxx", # funsolver.com key
|
|
48
|
+
humanly=True, # Bezier mouse + typing rhythm
|
|
49
|
+
fingerprint=funbrowser.presets.windows_11_nvidia_rtx_4070(),
|
|
50
|
+
) as browser:
|
|
51
|
+
tab = await browser.get("https://target-with-captcha.com")
|
|
52
|
+
# captchas auto-solve in the background
|
|
53
|
+
await tab.fill("#email", "alice@example.com")
|
|
54
|
+
await tab.click("button[type=submit]")
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Features
|
|
58
|
+
|
|
59
|
+
### Stealth (passes 25/25 standard antidetect probes)
|
|
60
|
+
|
|
61
|
+
- `navigator.webdriver` → undefined, **with native `toString` camouflage**
|
|
62
|
+
- UA + Client Hints with `HeadlessChrome` stripped
|
|
63
|
+
- `chrome.runtime`, `plugins`, `languages`, permissions consistency
|
|
64
|
+
- **Real GPU** for WebGL (`--use-gl=angle`, not SwiftShader)
|
|
65
|
+
- Canvas + audio readout noise to break fingerprint tracking
|
|
66
|
+
- WebRTC IP leak blocked (flag-level + SDP filter)
|
|
67
|
+
- iframe stealth propagation
|
|
68
|
+
- Geo auto-couples timezone + locale to proxy exit IP
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
uv run python examples/detect_check.py # self-audit
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Fingerprint customisation
|
|
75
|
+
|
|
76
|
+
17 ready presets (Windows × NVIDIA / Intel / AMD, macOS Apple Silicon /
|
|
77
|
+
Intel, Linux, plus 4 Android mobile) + arbitrary custom `Fingerprint(...)`.
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from funbrowser import Fingerprint, presets
|
|
81
|
+
|
|
82
|
+
fp = presets.macos_apple_silicon_m3_pro().merge(
|
|
83
|
+
Fingerprint(timezone="Asia/Tokyo", languages=("ja-JP", "ja", "en"))
|
|
84
|
+
)
|
|
85
|
+
async with await funbrowser.start(fingerprint=fp) as browser:
|
|
86
|
+
...
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Humanly mode (Bezier-curve mouse + typing rhythm)
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
async with await funbrowser.start(humanly=True) as browser:
|
|
93
|
+
await tab.click("button") # cursor curves toward target
|
|
94
|
+
await tab.type("#email", "ada") # per-keystroke random delay
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Presets: `humanly.FAST`, `humanly.DEFAULT`, `humanly.CAREFUL`, plus arbitrary
|
|
98
|
+
custom `HumanBehavior(...)`.
|
|
99
|
+
|
|
100
|
+
### Captcha auto-solve
|
|
101
|
+
|
|
102
|
+
Paste a [funsolver.com](https://funsolver.com) API key. Five captcha
|
|
103
|
+
families detected on-page and solved automatically:
|
|
104
|
+
|
|
105
|
+
| | API method | Page integration |
|
|
106
|
+
|---|---|---|
|
|
107
|
+
| Cloudflare Turnstile | `solve_turnstile` | `.cf-turnstile` widgets |
|
|
108
|
+
| reCAPTCHA v2 (+ Enterprise) | `solve_recaptcha_v2` | `.g-recaptcha` widgets |
|
|
109
|
+
| reCAPTCHA v3 (+ Enterprise) | `solve_recaptcha_v3` | hooks `grecaptcha.execute()` |
|
|
110
|
+
| hCaptcha | `solve_hcaptcha` | `.h-captcha` widgets |
|
|
111
|
+
| FunCaptcha / Arkose | `solve_funcaptcha` | `[data-pkey]` elements |
|
|
112
|
+
| GeeTest v3 + v4 | `solve_geetest` | hooks `initGeetest` / `initGeetest4` |
|
|
113
|
+
|
|
114
|
+
### Proxies (every format)
|
|
115
|
+
|
|
116
|
+
`host:port`, `host:port:user:pass`, `user:pass@host:port`, `host:port@user:pass`,
|
|
117
|
+
`socks5://...`, `chrome` URL form — all auto-parsed. HTTP/HTTPS auth flows
|
|
118
|
+
through CDP automatically.
|
|
119
|
+
|
|
120
|
+
### Persistent profiles
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
from funbrowser import Profile
|
|
124
|
+
|
|
125
|
+
alice = Profile.ensure("alice") # ./funbrowser_profiles/alice
|
|
126
|
+
async with await funbrowser.start(user_data_dir=alice) as browser:
|
|
127
|
+
# cookies + localStorage + login state persist between runs
|
|
128
|
+
...
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Browser farming — `BrowserPool` and `ContextPool`
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from funbrowser import BrowserPool, ContextPool
|
|
135
|
+
|
|
136
|
+
# Process pool — full Chrome per slot (max isolation)
|
|
137
|
+
async with BrowserPool(
|
|
138
|
+
size=5,
|
|
139
|
+
proxies=["proxy1:8080", "proxy2:8080", "proxy3:8080"],
|
|
140
|
+
headless=True,
|
|
141
|
+
mini=True,
|
|
142
|
+
) as pool:
|
|
143
|
+
async def scrape(browser):
|
|
144
|
+
tab = await browser.get("https://example.com")
|
|
145
|
+
return await tab.evaluate("document.title")
|
|
146
|
+
|
|
147
|
+
results = await pool.run_all([scrape] * 100)
|
|
148
|
+
|
|
149
|
+
# Context pool — 1 Chrome + N isolated contexts (~7-10x less RAM)
|
|
150
|
+
async with ContextPool(size=10, headless=True, mini=True) as pool:
|
|
151
|
+
async def scrape(ctx):
|
|
152
|
+
tab = await ctx.get("https://example.com")
|
|
153
|
+
return await tab.evaluate("document.title")
|
|
154
|
+
|
|
155
|
+
results = await pool.run_all([scrape] * 100)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Memory comparison on the same 10-slot workload:
|
|
159
|
+
- `BrowserPool(size=10)` → ~1.0 GB
|
|
160
|
+
- `ContextPool(size=10)` → ~260 MB (one Chrome + 10 contexts)
|
|
161
|
+
|
|
162
|
+
### `mini=True` mode
|
|
163
|
+
|
|
164
|
+
Curated set of Chrome flags that cut RAM / CPU / disk per browser
|
|
165
|
+
(~50% lower RSS): site isolation off, background throttling, audio
|
|
166
|
+
muted, extensions / sync / translate disabled, small disk caches,
|
|
167
|
+
V8 heap cap. Combines with stealth — does **not** turn off the real
|
|
168
|
+
GPU. Works on `Browser`, `BrowserPool`, and `ContextPool` alike.
|
|
169
|
+
|
|
170
|
+
### TLS fingerprint impersonation (`pip install funbrowser[tls]`)
|
|
171
|
+
|
|
172
|
+
Script-level HTTP that picks JA3/JA4 from real-browser profiles:
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
from funbrowser.tls import ImpersonatedHTTPClient
|
|
176
|
+
|
|
177
|
+
async with ImpersonatedHTTPClient(profile="chrome131") as http:
|
|
178
|
+
r = await http.get("https://protected-api.com/endpoint")
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
23 supported profiles: `chrome99..chrome133a`, `safari15..safari18`,
|
|
182
|
+
`firefox133/135`, Android variants. See
|
|
183
|
+
[docs/M10_M11_DESIGN.md](docs/M10_M11_DESIGN.md) for the deeper
|
|
184
|
+
browser-traffic mitm proxy roadmap.
|
|
185
|
+
|
|
186
|
+
### Local web panel (`pip install funbrowser[panel]`)
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
from funbrowser import BrowserPool, Panel
|
|
190
|
+
|
|
191
|
+
async with BrowserPool(size=5) as pool:
|
|
192
|
+
async with Panel(pool) as panel:
|
|
193
|
+
print(panel.url) # http://127.0.0.1:8765
|
|
194
|
+
await long_running_task()
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Black-and-white dashboard with: pool stats, FunSolver balance, browser
|
|
198
|
+
fleet table (proxy / geo / fingerprint / open tabs / per-row goto +
|
|
199
|
+
screenshot), activity log (panel actions + per-browser captcha solves),
|
|
200
|
+
quick actions, and a **script runner** — upload an `async def
|
|
201
|
+
main(browser)` script and run it on one browser or fan it out across
|
|
202
|
+
the whole pool, with per-run stdout / return / traceback captured.
|
|
203
|
+
|
|
204
|
+
## Documentation
|
|
205
|
+
|
|
206
|
+
- [docs/stealth.md](docs/stealth.md) — anti-detect coverage in depth
|
|
207
|
+
- [docs/captchas.md](docs/captchas.md) — solver integration guide
|
|
208
|
+
- [docs/farming.md](docs/farming.md) — `BrowserPool` vs `ContextPool`
|
|
209
|
+
- [docs/panel.md](docs/panel.md) — the local web dashboard
|
|
210
|
+
- [docs/M10_M11_DESIGN.md](docs/M10_M11_DESIGN.md) — TLS + engine-layer roadmap
|
|
211
|
+
- [examples/](examples/) — runnable demos for every feature
|
|
212
|
+
|
|
213
|
+
## Self-audit
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
uv run python examples/detect_check.py
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
[navigator.* basics] 9/9 PASS
|
|
221
|
+
[chrome runtime + iframe] 6/6 PASS
|
|
222
|
+
[stealth-detection probes] 5/5 PASS
|
|
223
|
+
[WebGL / canvas / audio] 4/4 PASS
|
|
224
|
+
[WebRTC IP leak] 1/1 PASS
|
|
225
|
+
|
|
226
|
+
score: 25/25 (100%)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Roadmap
|
|
230
|
+
|
|
231
|
+
| | Milestone | Status |
|
|
232
|
+
|---|---|---|
|
|
233
|
+
| M0 | Bootstrap | done |
|
|
234
|
+
| M1 | CDP core + Tab API | done |
|
|
235
|
+
| M2 | Stealth Tier 1 + 2 | done |
|
|
236
|
+
| M2.5 | Fingerprint customisation | done |
|
|
237
|
+
| M3 | Solver bridge + Turnstile | done |
|
|
238
|
+
| M4 | reCAPTCHA / hCaptcha / FunCaptcha / GeeTest | done |
|
|
239
|
+
| M5 | Production hardening (proxies, profiles, retries, multi-tab) | done |
|
|
240
|
+
| M5.5 | DX Tier S (auto-wait + ElementHandle + cookies + block_urls) | done |
|
|
241
|
+
| M5.5+ | Humanly mode | done |
|
|
242
|
+
| M5.5++ | WebRTC + toString camouflage + geo auto-couple | done |
|
|
243
|
+
| M5.5+++ | Mobile presets + expanded catalog | done |
|
|
244
|
+
| M5.6 | BrowserPool | done |
|
|
245
|
+
| M5.7 | Web Panel (+ FunSolver balance + per-browser logs + scripts) | done |
|
|
246
|
+
| M5.8 | Mini mode | done |
|
|
247
|
+
| M6 | **v0.1 release** | **in progress** |
|
|
248
|
+
| M10a | TLS HTTP client (curl_cffi) | done |
|
|
249
|
+
| M11-alt | ContextPool (lightweight pool) | done |
|
|
250
|
+
| M7 | Fingerprint consistency (Tier 3) | post-v0.1 |
|
|
251
|
+
| M8 | Real fingerprint pool (Tier 4) | post-v0.1 |
|
|
252
|
+
| M9 | Deep WebGL / canvas / shader spoofing | post-v0.1 |
|
|
253
|
+
| M10b | mitm proxy for Chrome traffic (production-grade) | post-v0.1 |
|
|
254
|
+
| M11 | Browser fork (Camoufox / Chromium) | post-v0.1 |
|
|
255
|
+
| M12 | Tauri UI for manual mode | post-v0.1 |
|
|
256
|
+
|
|
257
|
+
## Development
|
|
258
|
+
|
|
259
|
+
Uses [uv](https://docs.astral.sh/uv/) for env + deps.
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
uv sync # install
|
|
263
|
+
uv run pytest -q # full test suite (173 tests)
|
|
264
|
+
uv run ruff check . && uv run ruff format --check .
|
|
265
|
+
uv run mypy funbrowser
|
|
266
|
+
uv run python examples/detect_check.py
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Contributing
|
|
270
|
+
|
|
271
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). Issues + PRs welcome.
|
|
272
|
+
|
|
273
|
+
## License
|
|
274
|
+
|
|
275
|
+
MIT. See [LICENSE](LICENSE).
|