mirror of
https://forge.fsky.io/oneflux/omegafox.git
synced 2026-02-11 02:02:03 -08:00
pythonlib: Add persistent_context, humanize, etc. 0.2.5
- Added `persistent_context` parameter #21 - Added `humanize` parameter #22 - Added validation for custom fingerprints - Updated Browserforge integration documentation
This commit is contained in:
parent
2201d9fc0c
commit
2832673f83
6 changed files with 188 additions and 49 deletions
|
|
@ -92,7 +92,7 @@ Parameters:
|
||||||
Camoufox properties to use.
|
Camoufox properties to use.
|
||||||
os (Optional[ListOrString]):
|
os (Optional[ListOrString]):
|
||||||
Operating system to use for the fingerprint generation.
|
Operating system to use for the fingerprint generation.
|
||||||
Can be "windows", "macos", or "linux", or a list of these to choose from randomly.
|
Can be "windows", "macos", "linux", "android", "ios", or a list to randomly choose from.
|
||||||
Default: ["windows", "macos", "linux"]
|
Default: ["windows", "macos", "linux"]
|
||||||
block_images (Optional[bool]):
|
block_images (Optional[bool]):
|
||||||
Whether to block all images.
|
Whether to block all images.
|
||||||
|
|
@ -103,6 +103,10 @@ Parameters:
|
||||||
geoip (Optional[Union[str, bool]]):
|
geoip (Optional[Union[str, bool]]):
|
||||||
Calculate longitude, latitude, timezone, country, & locale based on the IP address.
|
Calculate longitude, latitude, timezone, country, & locale based on the IP address.
|
||||||
Pass the target IP address to use, or `True` to find the IP address automatically.
|
Pass the target IP address to use, or `True` to find the IP address automatically.
|
||||||
|
humanize (Optional[Union[bool, float]]):
|
||||||
|
Humanize the cursor movement.
|
||||||
|
Takes either `True`, or the MAX duration in seconds of the cursor movement.
|
||||||
|
The cursor typically takes up to 1.5 seconds to move across the window.
|
||||||
locale (Optional[str]):
|
locale (Optional[str]):
|
||||||
Locale to use in Camoufox.
|
Locale to use in Camoufox.
|
||||||
addons (Optional[List[str]]):
|
addons (Optional[List[str]]):
|
||||||
|
|
@ -112,12 +116,16 @@ Parameters:
|
||||||
Takes a list of font family names that are installed on the system.
|
Takes a list of font family names that are installed on the system.
|
||||||
exclude_addons (Optional[List[DefaultAddons]]):
|
exclude_addons (Optional[List[DefaultAddons]]):
|
||||||
Default addons to exclude. Passed as a list of camoufox.DefaultAddons enums.
|
Default addons to exclude. Passed as a list of camoufox.DefaultAddons enums.
|
||||||
fingerprint (Optional[Fingerprint]):
|
|
||||||
Use a custom BrowserForge fingerprint. Note: Not all values will be implemented.
|
|
||||||
If not provided, a random fingerprint will be generated based on the provided os & user_agent.
|
|
||||||
screen (Optional[Screen]):
|
screen (Optional[Screen]):
|
||||||
Constrains the screen dimensions of the generated fingerprint.
|
Constrains the screen dimensions of the generated fingerprint.
|
||||||
Takes a browserforge.fingerprints.Screen instance.
|
Takes a browserforge.fingerprints.Screen instance.
|
||||||
|
fingerprint (Optional[Fingerprint]):
|
||||||
|
Use a custom BrowserForge fingerprint. Note: Not all values will be implemented.
|
||||||
|
If not provided, a random fingerprint will be generated based on the provided
|
||||||
|
`os` & `screen` constraints.
|
||||||
|
ff_version (Optional[int]):
|
||||||
|
Firefox version to use. Defaults to the current Camoufox version.
|
||||||
|
To prevent leaks, only use this for special cases.
|
||||||
headless (Optional[bool]):
|
headless (Optional[bool]):
|
||||||
Whether to run the browser in headless mode. Defaults to True.
|
Whether to run the browser in headless mode. Defaults to True.
|
||||||
executable_path (Optional[str]):
|
executable_path (Optional[str]):
|
||||||
|
|
@ -127,13 +135,14 @@ Parameters:
|
||||||
proxy (Optional[Dict[str, str]]):
|
proxy (Optional[Dict[str, str]]):
|
||||||
Proxy to use for the browser.
|
Proxy to use for the browser.
|
||||||
Note: If geoip is True, a request will be sent through this proxy to find the target IP.
|
Note: If geoip is True, a request will be sent through this proxy to find the target IP.
|
||||||
ff_version (Optional[int]):
|
|
||||||
Firefox version to use. Defaults to the current Camoufox version.
|
|
||||||
To prevent leaks, only use this for special cases.
|
|
||||||
args (Optional[List[str]]):
|
args (Optional[List[str]]):
|
||||||
Arguments to pass to the browser.
|
Arguments to pass to the browser.
|
||||||
env (Optional[Dict[str, Union[str, float, bool]]]):
|
env (Optional[Dict[str, Union[str, float, bool]]]):
|
||||||
Environment variables to set.
|
Environment variables to set.
|
||||||
|
persistent_context (Optional[bool]):
|
||||||
|
Whether to use a persistent context.
|
||||||
|
debug (Optional[bool]):
|
||||||
|
Prints the config being sent to Camoufox.
|
||||||
**launch_options (Dict[str, Any]):
|
**launch_options (Dict[str, Any]):
|
||||||
Additional Firefox launch options.
|
Additional Firefox launch options.
|
||||||
```
|
```
|
||||||
|
|
@ -245,7 +254,35 @@ with sync_playwright() as p:
|
||||||
|
|
||||||
Camoufox is compatible with [BrowserForge](https://github.com/daijro/browserforge) fingerprints.
|
Camoufox is compatible with [BrowserForge](https://github.com/daijro/browserforge) fingerprints.
|
||||||
|
|
||||||
By default, Camoufox will use a random fingerprint. You can also inject your own Firefox Browserforge fingerprint into Camoufox with the following example:
|
By default, Camoufox will generate an use a random BrowserForge fingerprint based on the target `os` & `screen` constraints.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from camoufox.sync_api import Camoufox
|
||||||
|
from browserforge.fingerprints import Screen
|
||||||
|
|
||||||
|
with Camoufox(
|
||||||
|
os=('windows', 'macos', 'linux'),
|
||||||
|
screen=Screen(max_width=1920, max_height=1080),
|
||||||
|
) as browser:
|
||||||
|
page = browser.new_page()
|
||||||
|
page.goto("https://example.com/")
|
||||||
|
```
|
||||||
|
|
||||||
|
**Notes:**
|
||||||
|
|
||||||
|
- If Camoufox is being ran in headful mode, the max screen size will be generated based on your monitor's dimensions (+15%).
|
||||||
|
|
||||||
|
- To prevent UA-spoofing leaks, Camoufox only generates fingerprints with the same browser version as the current Camoufox version by default.
|
||||||
|
|
||||||
|
- If rotating the Firefox version is absolutely necessary, it would be more advisable to rotate between older versions of Camoufox instead.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Injecting custom Fingerprint objects...</summary>
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> It is recommended to pass `os` & `screen` constraints into Camoufox instead. Camoufox will handle fingerprint generation for you. This will be deprecated in the future.
|
||||||
|
|
||||||
|
You can also inject your own Firefox BrowserForge fingerprint into Camoufox.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from camoufox.sync_api import Camoufox
|
from camoufox.sync_api import Camoufox
|
||||||
|
|
@ -259,8 +296,8 @@ with Camoufox(fingerprint=fg.generate()) as browser:
|
||||||
page.goto("https://example.com/")
|
page.goto("https://example.com/")
|
||||||
```
|
```
|
||||||
|
|
||||||
<hr width=50>
|
|
||||||
|
|
||||||
**Note:** As of now, some properties from BrowserForge fingerprints will not be passed to Camoufox. This is due to the outdated fingerprint dataset from Apify's fingerprint-suite (see [here](https://github.com/apify/fingerprint-suite/discussions/308)). Properties will be re-enabled as soon as an updated dataset is available.
|
**Note:** As of now, some properties from BrowserForge fingerprints will not be passed to Camoufox. This is due to the outdated fingerprint dataset from Apify's fingerprint-suite (see [here](https://github.com/apify/fingerprint-suite/discussions/308)). Properties will be re-enabled as soon as an updated dataset is available.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,15 @@
|
||||||
from typing import Any, Dict, List, Optional, Union
|
from typing import Any, Dict, List, Optional, Union
|
||||||
|
|
||||||
from browserforge.fingerprints import Fingerprint, Screen
|
from browserforge.fingerprints import Fingerprint, Screen
|
||||||
from playwright.async_api import Browser, Playwright, PlaywrightContextManager
|
from playwright.async_api import (
|
||||||
|
Browser,
|
||||||
|
BrowserContext,
|
||||||
|
Playwright,
|
||||||
|
PlaywrightContextManager,
|
||||||
|
)
|
||||||
|
|
||||||
from .addons import DefaultAddons
|
from .addons import DefaultAddons
|
||||||
from .utils import ListOrString, get_launch_options
|
from .utils import ListOrString, _clean_locals, get_launch_options
|
||||||
|
|
||||||
|
|
||||||
class AsyncCamoufox(PlaywrightContextManager):
|
class AsyncCamoufox(PlaywrightContextManager):
|
||||||
|
|
@ -16,9 +21,9 @@ class AsyncCamoufox(PlaywrightContextManager):
|
||||||
def __init__(self, **launch_options):
|
def __init__(self, **launch_options):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.launch_options = launch_options
|
self.launch_options = launch_options
|
||||||
self.browser: Optional[Browser] = None
|
self.browser: Optional[Union[Browser, BrowserContext]] = None
|
||||||
|
|
||||||
async def __aenter__(self) -> Browser:
|
async def __aenter__(self) -> Union[Browser, BrowserContext]:
|
||||||
_playwright = await super().__aenter__()
|
_playwright = await super().__aenter__()
|
||||||
self.browser = await AsyncNewBrowser(_playwright, **self.launch_options)
|
self.browser = await AsyncNewBrowser(_playwright, **self.launch_options)
|
||||||
return self.browser
|
return self.browser
|
||||||
|
|
@ -38,21 +43,25 @@ async def AsyncNewBrowser(
|
||||||
block_webrtc: Optional[bool] = None,
|
block_webrtc: Optional[bool] = None,
|
||||||
allow_webgl: Optional[bool] = None,
|
allow_webgl: Optional[bool] = None,
|
||||||
geoip: Optional[Union[str, bool]] = None,
|
geoip: Optional[Union[str, bool]] = None,
|
||||||
|
humanize: Optional[Union[bool, float]] = None,
|
||||||
locale: Optional[str] = None,
|
locale: Optional[str] = None,
|
||||||
addons: Optional[List[str]] = None,
|
addons: Optional[List[str]] = None,
|
||||||
fonts: Optional[List[str]] = None,
|
fonts: Optional[List[str]] = None,
|
||||||
exclude_addons: Optional[List[DefaultAddons]] = None,
|
exclude_addons: Optional[List[DefaultAddons]] = None,
|
||||||
fingerprint: Optional[Fingerprint] = None,
|
|
||||||
screen: Optional[Screen] = None,
|
screen: Optional[Screen] = None,
|
||||||
|
fingerprint: Optional[Fingerprint] = None,
|
||||||
|
ff_version: Optional[int] = None,
|
||||||
headless: Optional[bool] = None,
|
headless: Optional[bool] = None,
|
||||||
executable_path: Optional[str] = None,
|
executable_path: Optional[str] = None,
|
||||||
firefox_user_prefs: Optional[Dict[str, Any]] = None,
|
firefox_user_prefs: Optional[Dict[str, Any]] = None,
|
||||||
proxy: Optional[Dict[str, str]] = None,
|
proxy: Optional[Dict[str, str]] = None,
|
||||||
ff_version: Optional[int] = None,
|
|
||||||
args: Optional[List[str]] = None,
|
args: Optional[List[str]] = None,
|
||||||
env: Optional[Dict[str, Union[str, float, bool]]] = None,
|
env: Optional[Dict[str, Union[str, float, bool]]] = None,
|
||||||
|
persistent_context: Optional[bool] = None,
|
||||||
|
i_know_what_im_doing: Optional[bool] = None,
|
||||||
|
debug: Optional[bool] = None,
|
||||||
**launch_options: Dict[str, Any]
|
**launch_options: Dict[str, Any]
|
||||||
) -> Browser:
|
) -> Union[Browser, BrowserContext]:
|
||||||
"""
|
"""
|
||||||
Launches a new browser instance for Camoufox.
|
Launches a new browser instance for Camoufox.
|
||||||
Accepts all Playwright Firefox launch options, along with the following:
|
Accepts all Playwright Firefox launch options, along with the following:
|
||||||
|
|
@ -62,7 +71,7 @@ async def AsyncNewBrowser(
|
||||||
Camoufox properties to use. (read https://github.com/daijro/camoufox/blob/main/README.md)
|
Camoufox properties to use. (read https://github.com/daijro/camoufox/blob/main/README.md)
|
||||||
os (Optional[ListOrString]):
|
os (Optional[ListOrString]):
|
||||||
Operating system to use for the fingerprint generation.
|
Operating system to use for the fingerprint generation.
|
||||||
Can be "windows", "macos", or "linux", or a list of these to choose from randomly.
|
Can be "windows", "macos", "linux", "android", "ios", or a list to randomly choose from.
|
||||||
Default: ["windows", "macos", "linux"]
|
Default: ["windows", "macos", "linux"]
|
||||||
block_images (Optional[bool]):
|
block_images (Optional[bool]):
|
||||||
Whether to block all images.
|
Whether to block all images.
|
||||||
|
|
@ -73,6 +82,10 @@ async def AsyncNewBrowser(
|
||||||
geoip (Optional[Union[str, bool]]):
|
geoip (Optional[Union[str, bool]]):
|
||||||
Calculate longitude, latitude, timezone, country, & locale based on the IP address.
|
Calculate longitude, latitude, timezone, country, & locale based on the IP address.
|
||||||
Pass the target IP address to use, or `True` to find the IP address automatically.
|
Pass the target IP address to use, or `True` to find the IP address automatically.
|
||||||
|
humanize (Optional[Union[bool, float]]):
|
||||||
|
Humanize the cursor movement.
|
||||||
|
Takes either `True`, or the MAX duration in seconds of the cursor movement.
|
||||||
|
The cursor typically takes up to 1.5 seconds to move across the window.
|
||||||
locale (Optional[str]):
|
locale (Optional[str]):
|
||||||
Locale to use in Camoufox.
|
Locale to use in Camoufox.
|
||||||
addons (Optional[List[str]]):
|
addons (Optional[List[str]]):
|
||||||
|
|
@ -82,12 +95,16 @@ async def AsyncNewBrowser(
|
||||||
Takes a list of font family names that are installed on the system.
|
Takes a list of font family names that are installed on the system.
|
||||||
exclude_addons (Optional[List[DefaultAddons]]):
|
exclude_addons (Optional[List[DefaultAddons]]):
|
||||||
Default addons to exclude. Passed as a list of camoufox.DefaultAddons enums.
|
Default addons to exclude. Passed as a list of camoufox.DefaultAddons enums.
|
||||||
fingerprint (Optional[Fingerprint]):
|
|
||||||
Use a custom BrowserForge fingerprint. Note: Not all values will be implemented.
|
|
||||||
If not provided, a random fingerprint will be generated based on the provided os & user_agent.
|
|
||||||
screen (Optional[Screen]):
|
screen (Optional[Screen]):
|
||||||
Constrains the screen dimensions of the generated fingerprint.
|
Constrains the screen dimensions of the generated fingerprint.
|
||||||
Takes a browserforge.fingerprints.Screen instance.
|
Takes a browserforge.fingerprints.Screen instance.
|
||||||
|
fingerprint (Optional[Fingerprint]):
|
||||||
|
Use a custom BrowserForge fingerprint. Note: Not all values will be implemented.
|
||||||
|
If not provided, a random fingerprint will be generated based on the provided
|
||||||
|
`os` & `screen` constraints.
|
||||||
|
ff_version (Optional[int]):
|
||||||
|
Firefox version to use. Defaults to the current Camoufox version.
|
||||||
|
To prevent leaks, only use this for special cases.
|
||||||
headless (Optional[bool]):
|
headless (Optional[bool]):
|
||||||
Whether to run the browser in headless mode. Defaults to True.
|
Whether to run the browser in headless mode. Defaults to True.
|
||||||
executable_path (Optional[str]):
|
executable_path (Optional[str]):
|
||||||
|
|
@ -97,18 +114,20 @@ async def AsyncNewBrowser(
|
||||||
proxy (Optional[Dict[str, str]]):
|
proxy (Optional[Dict[str, str]]):
|
||||||
Proxy to use for the browser.
|
Proxy to use for the browser.
|
||||||
Note: If geoip is True, a request will be sent through this proxy to find the target IP.
|
Note: If geoip is True, a request will be sent through this proxy to find the target IP.
|
||||||
ff_version (Optional[int]):
|
|
||||||
Firefox version to use. Defaults to the current Camoufox version.
|
|
||||||
To prevent leaks, only use this for special cases.
|
|
||||||
args (Optional[List[str]]):
|
args (Optional[List[str]]):
|
||||||
Arguments to pass to the browser.
|
Arguments to pass to the browser.
|
||||||
env (Optional[Dict[str, Union[str, float, bool]]]):
|
env (Optional[Dict[str, Union[str, float, bool]]]):
|
||||||
Environment variables to set.
|
Environment variables to set.
|
||||||
|
persistent_context (Optional[bool]):
|
||||||
|
Whether to use a persistent context.
|
||||||
|
debug (Optional[bool]):
|
||||||
|
Prints the config being sent to Camoufox.
|
||||||
**launch_options (Dict[str, Any]):
|
**launch_options (Dict[str, Any]):
|
||||||
Additional Firefox launch options.
|
Additional Firefox launch options.
|
||||||
"""
|
"""
|
||||||
data = locals()
|
opt = get_launch_options(**_clean_locals(locals()))
|
||||||
data.pop('playwright')
|
|
||||||
|
if persistent_context:
|
||||||
|
return await playwright.firefox.launch_persistent_context(**opt)
|
||||||
|
|
||||||
opt = get_launch_options(**data)
|
|
||||||
return await playwright.firefox.launch(**opt)
|
return await playwright.firefox.launch(**opt)
|
||||||
|
|
|
||||||
|
|
@ -100,3 +100,11 @@ class NotInstalledGeoIPExtra(ImportError):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class NonFirefoxFingerprint(Exception):
|
||||||
|
"""
|
||||||
|
Raised when a passed Browserforge fingerprint is invalid.
|
||||||
|
"""
|
||||||
|
|
||||||
|
...
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,15 @@
|
||||||
from typing import Any, Dict, List, Optional, Union
|
from typing import Any, Dict, List, Optional, Union
|
||||||
|
|
||||||
from browserforge.fingerprints import Fingerprint, Screen
|
from browserforge.fingerprints import Fingerprint, Screen
|
||||||
from playwright.sync_api import Browser, Playwright, PlaywrightContextManager
|
from playwright.sync_api import (
|
||||||
|
Browser,
|
||||||
|
BrowserContext,
|
||||||
|
Playwright,
|
||||||
|
PlaywrightContextManager,
|
||||||
|
)
|
||||||
|
|
||||||
from .addons import DefaultAddons
|
from .addons import DefaultAddons
|
||||||
from .utils import ListOrString, get_launch_options
|
from .utils import ListOrString, _clean_locals, get_launch_options
|
||||||
|
|
||||||
|
|
||||||
class Camoufox(PlaywrightContextManager):
|
class Camoufox(PlaywrightContextManager):
|
||||||
|
|
@ -16,9 +21,9 @@ class Camoufox(PlaywrightContextManager):
|
||||||
def __init__(self, **launch_options):
|
def __init__(self, **launch_options):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.launch_options = launch_options
|
self.launch_options = launch_options
|
||||||
self.browser: Optional[Browser] = None
|
self.browser: Optional[Union[Browser, BrowserContext]] = None
|
||||||
|
|
||||||
def __enter__(self) -> Browser:
|
def __enter__(self) -> Union[Browser, BrowserContext]:
|
||||||
super().__enter__()
|
super().__enter__()
|
||||||
self.browser = NewBrowser(self._playwright, **self.launch_options)
|
self.browser = NewBrowser(self._playwright, **self.launch_options)
|
||||||
return self.browser
|
return self.browser
|
||||||
|
|
@ -38,19 +43,23 @@ def NewBrowser(
|
||||||
block_webrtc: Optional[bool] = None,
|
block_webrtc: Optional[bool] = None,
|
||||||
allow_webgl: Optional[bool] = None,
|
allow_webgl: Optional[bool] = None,
|
||||||
geoip: Optional[Union[str, bool]] = None,
|
geoip: Optional[Union[str, bool]] = None,
|
||||||
|
humanize: Optional[Union[bool, float]] = None,
|
||||||
locale: Optional[str] = None,
|
locale: Optional[str] = None,
|
||||||
addons: Optional[List[str]] = None,
|
addons: Optional[List[str]] = None,
|
||||||
fonts: Optional[List[str]] = None,
|
fonts: Optional[List[str]] = None,
|
||||||
exclude_addons: Optional[List[DefaultAddons]] = None,
|
exclude_addons: Optional[List[DefaultAddons]] = None,
|
||||||
fingerprint: Optional[Fingerprint] = None,
|
|
||||||
screen: Optional[Screen] = None,
|
screen: Optional[Screen] = None,
|
||||||
|
fingerprint: Optional[Fingerprint] = None,
|
||||||
|
ff_version: Optional[int] = None,
|
||||||
headless: Optional[bool] = None,
|
headless: Optional[bool] = None,
|
||||||
executable_path: Optional[str] = None,
|
executable_path: Optional[str] = None,
|
||||||
firefox_user_prefs: Optional[Dict[str, Any]] = None,
|
firefox_user_prefs: Optional[Dict[str, Any]] = None,
|
||||||
proxy: Optional[Dict[str, str]] = None,
|
proxy: Optional[Dict[str, str]] = None,
|
||||||
ff_version: Optional[int] = None,
|
|
||||||
args: Optional[List[str]] = None,
|
args: Optional[List[str]] = None,
|
||||||
env: Optional[Dict[str, Union[str, float, bool]]] = None,
|
env: Optional[Dict[str, Union[str, float, bool]]] = None,
|
||||||
|
persistent_context: Optional[bool] = None,
|
||||||
|
i_know_what_im_doing: Optional[bool] = None,
|
||||||
|
debug: Optional[bool] = None,
|
||||||
**launch_options: Dict[str, Any]
|
**launch_options: Dict[str, Any]
|
||||||
) -> Browser:
|
) -> Browser:
|
||||||
"""
|
"""
|
||||||
|
|
@ -62,7 +71,7 @@ def NewBrowser(
|
||||||
Camoufox properties to use. (read https://github.com/daijro/camoufox/blob/main/README.md)
|
Camoufox properties to use. (read https://github.com/daijro/camoufox/blob/main/README.md)
|
||||||
os (Optional[ListOrString]):
|
os (Optional[ListOrString]):
|
||||||
Operating system to use for the fingerprint generation.
|
Operating system to use for the fingerprint generation.
|
||||||
Can be "windows", "macos", or "linux", or a list of these to choose from randomly.
|
Can be "windows", "macos", "linux", "android", "ios", or a list to randomly choose from.
|
||||||
Default: ["windows", "macos", "linux"]
|
Default: ["windows", "macos", "linux"]
|
||||||
block_images (Optional[bool]):
|
block_images (Optional[bool]):
|
||||||
Whether to block all images.
|
Whether to block all images.
|
||||||
|
|
@ -73,6 +82,10 @@ def NewBrowser(
|
||||||
geoip (Optional[Union[str, bool]]):
|
geoip (Optional[Union[str, bool]]):
|
||||||
Calculate longitude, latitude, timezone, country, & locale based on the IP address.
|
Calculate longitude, latitude, timezone, country, & locale based on the IP address.
|
||||||
Pass the target IP address to use, or `True` to find the IP address automatically.
|
Pass the target IP address to use, or `True` to find the IP address automatically.
|
||||||
|
humanize (Optional[Union[bool, float]]):
|
||||||
|
Humanize the cursor movement.
|
||||||
|
Takes either `True`, or the MAX duration in seconds of the cursor movement.
|
||||||
|
The cursor typically takes up to 1.5 seconds to move across the window.
|
||||||
locale (Optional[str]):
|
locale (Optional[str]):
|
||||||
Locale to use in Camoufox.
|
Locale to use in Camoufox.
|
||||||
addons (Optional[List[str]]):
|
addons (Optional[List[str]]):
|
||||||
|
|
@ -82,12 +95,16 @@ def NewBrowser(
|
||||||
Takes a list of font family names that are installed on the system.
|
Takes a list of font family names that are installed on the system.
|
||||||
exclude_addons (Optional[List[DefaultAddons]]):
|
exclude_addons (Optional[List[DefaultAddons]]):
|
||||||
Default addons to exclude. Passed as a list of camoufox.DefaultAddons enums.
|
Default addons to exclude. Passed as a list of camoufox.DefaultAddons enums.
|
||||||
fingerprint (Optional[Fingerprint]):
|
|
||||||
Use a custom BrowserForge fingerprint. Note: Not all values will be implemented.
|
|
||||||
If not provided, a random fingerprint will be generated based on the provided os & user_agent.
|
|
||||||
screen (Optional[Screen]):
|
screen (Optional[Screen]):
|
||||||
Constrains the screen dimensions of the generated fingerprint.
|
Constrains the screen dimensions of the generated fingerprint.
|
||||||
Takes a browserforge.fingerprints.Screen instance.
|
Takes a browserforge.fingerprints.Screen instance.
|
||||||
|
fingerprint (Optional[Fingerprint]):
|
||||||
|
Use a custom BrowserForge fingerprint. Note: Not all values will be implemented.
|
||||||
|
If not provided, a random fingerprint will be generated based on the provided
|
||||||
|
`os` & `screen` constraints.
|
||||||
|
ff_version (Optional[int]):
|
||||||
|
Firefox version to use. Defaults to the current Camoufox version.
|
||||||
|
To prevent leaks, only use this for special cases.
|
||||||
headless (Optional[bool]):
|
headless (Optional[bool]):
|
||||||
Whether to run the browser in headless mode. Defaults to True.
|
Whether to run the browser in headless mode. Defaults to True.
|
||||||
executable_path (Optional[str]):
|
executable_path (Optional[str]):
|
||||||
|
|
@ -97,18 +114,20 @@ def NewBrowser(
|
||||||
proxy (Optional[Dict[str, str]]):
|
proxy (Optional[Dict[str, str]]):
|
||||||
Proxy to use for the browser.
|
Proxy to use for the browser.
|
||||||
Note: If geoip is True, a request will be sent through this proxy to find the target IP.
|
Note: If geoip is True, a request will be sent through this proxy to find the target IP.
|
||||||
ff_version (Optional[int]):
|
|
||||||
Firefox version to use. Defaults to the current Camoufox version.
|
|
||||||
To prevent leaks, only use this for special cases.
|
|
||||||
args (Optional[List[str]]):
|
args (Optional[List[str]]):
|
||||||
Arguments to pass to the browser.
|
Arguments to pass to the browser.
|
||||||
env (Optional[Dict[str, Union[str, float, bool]]]):
|
env (Optional[Dict[str, Union[str, float, bool]]]):
|
||||||
Environment variables to set.
|
Environment variables to set.
|
||||||
|
persistent_context (Optional[bool]):
|
||||||
|
Whether to use a persistent context.
|
||||||
|
debug (Optional[bool]):
|
||||||
|
Prints the config being sent to Camoufox.
|
||||||
**launch_options (Dict[str, Any]):
|
**launch_options (Dict[str, Any]):
|
||||||
Additional Firefox launch options.
|
Additional Firefox launch options.
|
||||||
"""
|
"""
|
||||||
data = locals()
|
opt = get_launch_options(**_clean_locals(locals()))
|
||||||
data.pop('playwright')
|
|
||||||
|
if persistent_context:
|
||||||
|
return playwright.firefox.launch_persistent_context(**opt)
|
||||||
|
|
||||||
opt = get_launch_options(**data)
|
|
||||||
return playwright.firefox.launch(**opt)
|
return playwright.firefox.launch(**opt)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import warnings
|
||||||
from os import environ
|
from os import environ
|
||||||
|
from pprint import pprint
|
||||||
from random import randrange
|
from random import randrange
|
||||||
from typing import Any, Dict, List, Literal, Optional, Tuple, Union, cast
|
from typing import Any, Dict, List, Literal, Optional, Tuple, Union, cast
|
||||||
|
|
||||||
|
|
@ -17,7 +19,7 @@ from .addons import (
|
||||||
get_debug_port,
|
get_debug_port,
|
||||||
threaded_try_load_addons,
|
threaded_try_load_addons,
|
||||||
)
|
)
|
||||||
from .exceptions import InvalidPropertyType, UnknownProperty
|
from .exceptions import InvalidPropertyType, NonFirefoxFingerprint, UnknownProperty
|
||||||
from .fingerprints import from_browserforge, generate_fingerprint
|
from .fingerprints import from_browserforge, generate_fingerprint
|
||||||
from .ip import Proxy, public_ip, valid_ipv4, valid_ipv6
|
from .ip import Proxy, public_ip, valid_ipv4, valid_ipv6
|
||||||
from .locale import geoip_allowed, get_geolocation, normalize_locale
|
from .locale import geoip_allowed, get_geolocation, normalize_locale
|
||||||
|
|
@ -133,7 +135,7 @@ def determine_ua_os(user_agent: str) -> Literal['mac', 'win', 'lin']:
|
||||||
parsed_ua = user_agent_parser.ParseOS(user_agent).get('family')
|
parsed_ua = user_agent_parser.ParseOS(user_agent).get('family')
|
||||||
if not parsed_ua:
|
if not parsed_ua:
|
||||||
raise ValueError("Could not determine OS from user agent")
|
raise ValueError("Could not determine OS from user agent")
|
||||||
if parsed_ua.startswith("Mac"):
|
if parsed_ua.startswith("Mac") or parsed_ua.startswith("iOS"):
|
||||||
return "mac"
|
return "mac"
|
||||||
if parsed_ua.startswith("Windows"):
|
if parsed_ua.startswith("Windows"):
|
||||||
return "win"
|
return "win"
|
||||||
|
|
@ -155,8 +157,8 @@ def get_screen_cons(headless: Optional[bool] = None) -> Optional[Screen]:
|
||||||
|
|
||||||
# Use the dimensions from the monitor with greatest screen real estate
|
# Use the dimensions from the monitor with greatest screen real estate
|
||||||
monitor = max(monitors, key=lambda m: m.width * m.height)
|
monitor = max(monitors, key=lambda m: m.width * m.height)
|
||||||
# Add 25% buffer
|
# Add 15% buffer
|
||||||
return Screen(max_width=int(monitor.width * 1.25), max_height=int(monitor.height * 1.25))
|
return Screen(max_width=int(monitor.width * 1.15), max_height=int(monitor.height * 1.15))
|
||||||
|
|
||||||
|
|
||||||
def update_fonts(config: Dict[str, Any], target_os: str) -> None:
|
def update_fonts(config: Dict[str, Any], target_os: str) -> None:
|
||||||
|
|
@ -173,6 +175,40 @@ def update_fonts(config: Dict[str, Any], target_os: str) -> None:
|
||||||
config['fonts'] = fonts
|
config['fonts'] = fonts
|
||||||
|
|
||||||
|
|
||||||
|
def check_custom_fingerprint(fingerprint: Fingerprint) -> None:
|
||||||
|
"""
|
||||||
|
Asserts that the passed BrowserForge fingerprint is a valid Firefox fingerprint.
|
||||||
|
and warns the user that passing their own fingerprint is not recommended.
|
||||||
|
"""
|
||||||
|
if any(browser in fingerprint.navigator.userAgent for browser in ('Firefox', 'FxiOS')):
|
||||||
|
return
|
||||||
|
# Tell the user what browser they're using
|
||||||
|
parsed_ua = user_agent_parser.ParseUserAgent(fingerprint.navigator.userAgent).get(
|
||||||
|
'family', 'Non-Firefox'
|
||||||
|
)
|
||||||
|
if parsed_ua:
|
||||||
|
raise NonFirefoxFingerprint(
|
||||||
|
f'"{parsed_ua}" fingerprints are not supported in Camoufox. '
|
||||||
|
'Using fingerprints from a browser other than Firefox WILL lead to detection. '
|
||||||
|
'If this is intentional, pass `i_know_what_im_doing=True`.'
|
||||||
|
)
|
||||||
|
|
||||||
|
warnings.warn(
|
||||||
|
'Passing your own fingerprint is not recommended. '
|
||||||
|
'BrowserForge fingerprints are automatically generated within Camoufox '
|
||||||
|
'based on the provided `os` and `screen` constraints. '
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _clean_locals(data: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Gets the launch options from the locals of the function.
|
||||||
|
"""
|
||||||
|
del data['playwright']
|
||||||
|
del data['persistent_context']
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
def merge_into(target: Dict[str, Any], source: Dict[str, Any]) -> None:
|
def merge_into(target: Dict[str, Any], source: Dict[str, Any]) -> None:
|
||||||
"""
|
"""
|
||||||
Merges new keys/values from the source dictionary into the target dictionary.
|
Merges new keys/values from the source dictionary into the target dictionary.
|
||||||
|
|
@ -197,6 +233,8 @@ def get_launch_options(
|
||||||
config: Optional[Dict[str, Any]] = None,
|
config: Optional[Dict[str, Any]] = None,
|
||||||
addons: Optional[List[str]] = None,
|
addons: Optional[List[str]] = None,
|
||||||
fingerprint: Optional[Fingerprint] = None,
|
fingerprint: Optional[Fingerprint] = None,
|
||||||
|
humanize: Optional[Union[bool, float]] = None,
|
||||||
|
i_know_what_im_doing: Optional[bool] = None,
|
||||||
exclude_addons: Optional[List[DefaultAddons]] = None,
|
exclude_addons: Optional[List[DefaultAddons]] = None,
|
||||||
screen: Optional[Screen] = None,
|
screen: Optional[Screen] = None,
|
||||||
geoip: Optional[Union[str, bool]] = None,
|
geoip: Optional[Union[str, bool]] = None,
|
||||||
|
|
@ -214,6 +252,7 @@ def get_launch_options(
|
||||||
headless: Optional[bool] = None,
|
headless: Optional[bool] = None,
|
||||||
firefox_user_prefs: Optional[Dict[str, Any]] = None,
|
firefox_user_prefs: Optional[Dict[str, Any]] = None,
|
||||||
launch_options: Optional[Dict[str, Any]] = None,
|
launch_options: Optional[Dict[str, Any]] = None,
|
||||||
|
debug: Optional[bool] = None,
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Builds the launch options for the Camoufox browser.
|
Builds the launch options for the Camoufox browser.
|
||||||
|
|
@ -242,12 +281,18 @@ def get_launch_options(
|
||||||
else:
|
else:
|
||||||
ff_version_str = installed_verstr().split('.', 1)[0]
|
ff_version_str = installed_verstr().split('.', 1)[0]
|
||||||
|
|
||||||
# Inject a unique Firefox fingerprint
|
# Generate a fingerprint
|
||||||
if fingerprint is None:
|
if fingerprint is None:
|
||||||
fingerprint = generate_fingerprint(
|
fingerprint = generate_fingerprint(
|
||||||
screen=screen or get_screen_cons(headless),
|
screen=screen or get_screen_cons(headless),
|
||||||
os=os,
|
os=os,
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
# Or use the one passed by the user
|
||||||
|
if not i_know_what_im_doing:
|
||||||
|
check_custom_fingerprint(fingerprint)
|
||||||
|
|
||||||
|
# Inject the fingerprint into the config
|
||||||
merge_into(
|
merge_into(
|
||||||
config,
|
config,
|
||||||
from_browserforge(fingerprint, ff_version_str),
|
from_browserforge(fingerprint, ff_version_str),
|
||||||
|
|
@ -290,9 +335,20 @@ def get_launch_options(
|
||||||
parsed_locale = normalize_locale(locale)
|
parsed_locale = normalize_locale(locale)
|
||||||
config.update(parsed_locale.as_config())
|
config.update(parsed_locale.as_config())
|
||||||
|
|
||||||
|
# Pass the humanize option
|
||||||
|
if humanize:
|
||||||
|
set_into(config, 'humanize', True)
|
||||||
|
if isinstance(humanize, (int, float)):
|
||||||
|
set_into(config, 'humanize:maxTime', humanize)
|
||||||
|
|
||||||
# Validate the config
|
# Validate the config
|
||||||
validate_config(config)
|
validate_config(config)
|
||||||
|
|
||||||
|
# Print the config if debug is enabled
|
||||||
|
if debug:
|
||||||
|
print('[DEBUG] Config:')
|
||||||
|
pprint(config)
|
||||||
|
|
||||||
# Set Firefox user preferences
|
# Set Firefox user preferences
|
||||||
if block_images:
|
if block_images:
|
||||||
firefox_user_prefs['permissions.default.image'] = 2
|
firefox_user_prefs['permissions.default.image'] = 2
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
||||||
|
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "camoufox"
|
name = "camoufox"
|
||||||
version = "0.2.4"
|
version = "0.2.5"
|
||||||
description = "Wrapper around Playwright to help launch Camoufox"
|
description = "Wrapper around Playwright to help launch Camoufox"
|
||||||
authors = ["daijro <daijro.dev@gmail.com>"]
|
authors = ["daijro <daijro.dev@gmail.com>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue