244 lines
8.3 KiB
Python
244 lines
8.3 KiB
Python
|
import random
|
||
|
|
||
|
from fake_useragent import settings
|
||
|
from fake_useragent.errors import FakeUserAgentError
|
||
|
from fake_useragent.log import logger
|
||
|
from fake_useragent.utils import load, str_types
|
||
|
|
||
|
|
||
|
class FakeUserAgent:
|
||
|
def __init__( # noqa: PLR0913
|
||
|
self,
|
||
|
browsers=["chrome", "edge", "firefox", "safari"],
|
||
|
os=["windows", "macos", "linux", "android", "ios"],
|
||
|
min_version=0.0,
|
||
|
min_percentage=0.0,
|
||
|
platforms=["pc", "mobile", "tablet"],
|
||
|
fallback=(
|
||
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
|
||
|
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
||
|
"Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0"
|
||
|
),
|
||
|
safe_attrs=tuple(),
|
||
|
):
|
||
|
# Check inputs
|
||
|
assert isinstance(browsers, (list, str)), "browsers must be list or string"
|
||
|
if isinstance(browsers, str):
|
||
|
browsers = [browsers]
|
||
|
self.browsers = browsers
|
||
|
|
||
|
assert isinstance(os, (list, str)), "OS must be list or string"
|
||
|
if isinstance(os, str):
|
||
|
os = [os]
|
||
|
# OS replacement (windows -> [win10, win7])
|
||
|
self.os = []
|
||
|
for os_name in os:
|
||
|
if os_name in settings.OS_REPLACEMENTS:
|
||
|
self.os.extend(settings.OS_REPLACEMENTS[os_name])
|
||
|
else:
|
||
|
self.os.append(os_name)
|
||
|
|
||
|
assert isinstance(
|
||
|
min_percentage, (float, int)
|
||
|
), "Minimum usage percentage must be float or int"
|
||
|
if isinstance(min_percentage, int):
|
||
|
min_percentage = float(min_percentage)
|
||
|
self.min_percentage = min_percentage
|
||
|
|
||
|
assert isinstance(
|
||
|
min_version, (float, int)
|
||
|
), "Minimum version must be float or int"
|
||
|
if isinstance(min_version, int):
|
||
|
min_version = float(min_version)
|
||
|
self.min_version = min_version
|
||
|
|
||
|
assert isinstance(platforms, (list, str)), "platforms must be list or string"
|
||
|
if isinstance(platforms, str):
|
||
|
platforms = [platforms]
|
||
|
self.platforms = platforms
|
||
|
|
||
|
assert isinstance(fallback, str), "fallback must be string"
|
||
|
self.fallback = fallback
|
||
|
|
||
|
assert isinstance(
|
||
|
safe_attrs, (list, set, tuple)
|
||
|
), "safe_attrs must be list\\tuple\\set of strings or unicode"
|
||
|
|
||
|
if safe_attrs:
|
||
|
str_types_safe_attrs = [isinstance(attr, str_types) for attr in safe_attrs]
|
||
|
|
||
|
assert all(
|
||
|
str_types_safe_attrs
|
||
|
), "safe_attrs must be list\\tuple\\set of strings or unicode"
|
||
|
self.safe_attrs = set(safe_attrs)
|
||
|
|
||
|
# Next, load our local data file into memory (browsers.json)
|
||
|
self.data_browsers = load()
|
||
|
|
||
|
# This method will return a filtered list of user agents.
|
||
|
# The request parameter can be used to specify a browser.
|
||
|
def _filter_useragents(self, request=None):
|
||
|
# filter based on browser, os, platform and version.
|
||
|
filtered_useragents = list(
|
||
|
filter(
|
||
|
lambda x: x["browser"] in self.browsers
|
||
|
and x["os"] in self.os
|
||
|
and x["type"] in self.platforms
|
||
|
and x["version"] >= self.min_version
|
||
|
and x["percent"] >= self.min_percentage,
|
||
|
self.data_browsers,
|
||
|
)
|
||
|
)
|
||
|
# filter based on a specific browser request
|
||
|
if request:
|
||
|
filtered_useragents = list(
|
||
|
filter(lambda x: x["browser"] == request, filtered_useragents)
|
||
|
)
|
||
|
|
||
|
return filtered_useragents
|
||
|
|
||
|
# This method will return an object
|
||
|
# Usage: ua.getBrowser('firefox')
|
||
|
def getBrowser(self, request):
|
||
|
try:
|
||
|
# Handle request value
|
||
|
for value, replacement in settings.REPLACEMENTS.items():
|
||
|
request = request.replace(value, replacement)
|
||
|
request = request.lower()
|
||
|
request = settings.SHORTCUTS.get(request, request)
|
||
|
|
||
|
if request == "random":
|
||
|
# Filter the browser list based on the browsers array using lambda
|
||
|
# And based on OS list
|
||
|
# And percentage is bigger then min percentage
|
||
|
# And convert the iterator back to a list
|
||
|
filtered_browsers = self._filter_useragents()
|
||
|
else:
|
||
|
# Or when random isn't select, we filter the browsers array based on the 'request' using lamba
|
||
|
# And based on OS list
|
||
|
# And percentage is bigger then min percentage
|
||
|
# And convert the iterator back to a list
|
||
|
filtered_browsers = self._filter_useragents(request=request)
|
||
|
|
||
|
# Pick a random browser user-agent from the filtered browsers
|
||
|
# And return the full dict
|
||
|
return random.choice(filtered_browsers) # noqa: S311
|
||
|
except (KeyError, IndexError):
|
||
|
if self.fallback is None:
|
||
|
raise FakeUserAgentError(
|
||
|
f"Error occurred during getting browser: {request}"
|
||
|
) # noqa
|
||
|
else:
|
||
|
logger.warning(
|
||
|
f"Error occurred during getting browser: {request}, "
|
||
|
"but was suppressed with fallback.",
|
||
|
)
|
||
|
# Return fallback object
|
||
|
return {
|
||
|
"useragent": self.fallback,
|
||
|
"system": "Chrome 122.0 Win10",
|
||
|
"browser": "chrome",
|
||
|
"version": 122.0,
|
||
|
"os": "win10",
|
||
|
}
|
||
|
|
||
|
# This method will use the method below, returning a string
|
||
|
# Usage: ua['random']
|
||
|
def __getitem__(self, attr):
|
||
|
return self.__getattr__(attr)
|
||
|
|
||
|
# This method will returns a string
|
||
|
# Usage: ua.random
|
||
|
def __getattr__(self, attr):
|
||
|
if attr in self.safe_attrs:
|
||
|
return super(UserAgent, self).__getattribute__(attr)
|
||
|
|
||
|
try:
|
||
|
# Handle input value
|
||
|
for value, replacement in settings.REPLACEMENTS.items():
|
||
|
attr = attr.replace(value, replacement)
|
||
|
attr = attr.lower()
|
||
|
attr = settings.SHORTCUTS.get(attr, attr)
|
||
|
|
||
|
if attr == "random":
|
||
|
# Filter the browser list based on the browsers array using lambda
|
||
|
# And based on OS list
|
||
|
# And percentage is bigger then min percentage
|
||
|
# And convert the iterator back to a list
|
||
|
filtered_browsers = self._filter_useragents()
|
||
|
else:
|
||
|
# Or when random isn't select, we filter the browsers array based on the 'attr' using lamba
|
||
|
# And based on OS list
|
||
|
# And percentage is bigger then min percentage
|
||
|
# And convert the iterator back to a list
|
||
|
filtered_browsers = self._filter_useragents(request=attr)
|
||
|
|
||
|
# Pick a random browser user-agent from the filtered browsers
|
||
|
# And return the useragent string.
|
||
|
return random.choice(filtered_browsers).get("useragent") # noqa: S311
|
||
|
except (KeyError, IndexError):
|
||
|
if self.fallback is None:
|
||
|
raise FakeUserAgentError(
|
||
|
f"Error occurred during getting browser: {attr}"
|
||
|
) # noqa
|
||
|
else:
|
||
|
logger.warning(
|
||
|
f"Error occurred during getting browser: {attr}, "
|
||
|
"but was suppressed with fallback.",
|
||
|
)
|
||
|
|
||
|
return self.fallback
|
||
|
|
||
|
@property
|
||
|
def chrome(self):
|
||
|
return self.__getattr__("chrome")
|
||
|
|
||
|
@property
|
||
|
def googlechrome(self):
|
||
|
return self.chrome
|
||
|
|
||
|
@property
|
||
|
def edge(self):
|
||
|
return self.__getattr__("edge")
|
||
|
|
||
|
@property
|
||
|
def firefox(self):
|
||
|
return self.__getattr__("firefox")
|
||
|
|
||
|
@property
|
||
|
def ff(self):
|
||
|
return self.firefox
|
||
|
|
||
|
@property
|
||
|
def safari(self):
|
||
|
return self.__getattr__("safari")
|
||
|
|
||
|
@property
|
||
|
def random(self):
|
||
|
return self.__getattr__("random")
|
||
|
|
||
|
# The following 'get' methods return an object rather than only the UA string
|
||
|
@property
|
||
|
def getFirefox(self):
|
||
|
return self.getBrowser("firefox")
|
||
|
|
||
|
@property
|
||
|
def getChrome(self):
|
||
|
return self.getBrowser("chrome")
|
||
|
|
||
|
@property
|
||
|
def getEdge(self):
|
||
|
return self.getBrowser("edge")
|
||
|
|
||
|
@property
|
||
|
def getSafari(self):
|
||
|
return self.getBrowser("safari")
|
||
|
|
||
|
@property
|
||
|
def getRandom(self):
|
||
|
return self.getBrowser("random")
|
||
|
|
||
|
|
||
|
# common alias
|
||
|
UserAgent = FakeUserAgent
|