whosyouragent.whosyouragent

  1import json
  2import random
  3from concurrent.futures import ThreadPoolExecutor
  4from pathlib import Path
  5
  6import requests
  7from bs4 import BeautifulSoup
  8
  9
 10class VersionUpdater:
 11    def __init__(self):
 12        self.versions_path = Path(__file__).parent / "browserVersions.json"
 13        if not self.versions_path.exists():
 14            self.versions_path.write_text(json.dumps({}))
 15
 16    def update_firefox(self):
 17        try:
 18            url = "https://www.mozilla.org/en-US/firefox/releases/"
 19            soup = BeautifulSoup(requests.get(url).text, "html.parser")
 20            release_list = soup.find("ol", class_="c-release-list")
 21            version = release_list.ol.li.a.text
 22            self.firefox = version
 23        except Exception as e:
 24            print(e)
 25            raise Exception("Error updating firefox")
 26
 27    def update_chrome(self):
 28        try:
 29            url = "https://en.wikipedia.org/wiki/Google_Chrome"
 30            soup = BeautifulSoup(requests.get(url).text, "html.parser")
 31            info_boxes = soup.find_all("td", class_="infobox-data")
 32            version = info_boxes[8].text[
 33                : min([info_boxes[8].text.find("["), info_boxes[8].text.find("/")])
 34            ]
 35            self.chrome = version
 36        except Exception as e:
 37            print(e)
 38            raise Exception("Error updating chrome")
 39
 40    def update_safari(self):
 41        try:
 42            url = "https://en.wikipedia.org/wiki/Safari_(web_browser)"
 43            soup = BeautifulSoup(requests.get(url).text, "html.parser")
 44            info_boxes = soup.find_all("td", class_="infobox-data")
 45            version = info_boxes[2].text[: info_boxes[2].text.find("[")]
 46            self.safari = version
 47        except Exception as e:
 48            print(e)
 49            raise Exception("Error updating safari")
 50
 51    def update_edge(self):
 52        try:
 53            url = "https://www.techspot.com/downloads/7158-microsoft-edge.html"
 54            soup = BeautifulSoup(requests.get(url).text, "html.parser")
 55            version = soup.find("span", class_="subver").text
 56            self.edge = version
 57        except Exception as e:
 58            print(e)
 59            raise Exception("Error updating edge")
 60
 61    def update_vivaldi(self):
 62        try:
 63            url = "https://vivaldi.com/blog/"
 64            soup = BeautifulSoup(requests.get(url).text, "html.parser")
 65            text = soup.find("div", class_="download-vivaldi-sidebar").text
 66            text = text.split(" - ")[1]
 67            text = text.replace(" (", ".")
 68            version = text[: text.find(")")]
 69            self.vivaldi = version
 70        except Exception as e:
 71            print(e)
 72            raise Exception("Error updating vivaldi")
 73
 74    def update_opera(self) -> str:
 75        try:
 76            url = "https://en.wikipedia.org/wiki/Opera_(web_browser)"
 77            soup = BeautifulSoup(requests.get(url).text, "html.parser")
 78            info_boxes = soup.find_all("td", class_="infobox-data")
 79            version = info_boxes[2].div.text[: info_boxes[2].div.text.find("[")]
 80            self.opera = version
 81        except Exception as e:
 82            print(e)
 83            raise Exception("Error updating Opera")
 84
 85    def update_all(self):
 86        updaters = [
 87            self.update_firefox,
 88            self.update_chrome,
 89            self.update_safari,
 90            self.update_edge,
 91            self.update_vivaldi,
 92            self.update_opera,
 93        ]
 94        with ThreadPoolExecutor(6) as executor:
 95            for updater in updaters:
 96                executor.submit(updater)
 97        versions = {
 98            "Firefox": self.firefox,
 99            "Chrome": self.chrome,
100            "Edg": self.edge,
101            "Vivaldi": self.vivaldi,
102            "OPR": self.opera,
103            "Safari": self.safari,
104        }
105        # Remove any keys that failed to update and keep previous version number
106        poppers = [
107            version
108            for version in versions
109            if not ((versions[version]).replace(".", "")).isnumeric()
110        ]
111        for popper in poppers:
112            versions.pop(popper)
113        previous_versions = json.loads(self.versions_path.read_text())
114        versions = previous_versions | versions
115        self.versions_path.write_text(json.dumps(versions))
116
117
118platforms = [
119    "(Windows NT 10.0; Win64; x64)",
120    "(x11; Ubuntu; Linux x86_64)",
121    "(Windows NT 11.0; Win64; x64)",
122    "(Macintosh; Intel Mac OS X 13_0_0)",
123]
124
125
126def randomize_version_number(version: str) -> str:
127    """Randomize a version number so that it's in between
128    the previous major version and the current one."""
129    parts = [int(part) for part in version.split(".")]
130    parts[0] = random.randint(parts[0] - 1, parts[0])
131    for i, part in enumerate(parts[1:]):
132        parts[i + 1] = random.randint(0, part)
133    return ".".join(str(part) for part in parts)
134
135
136def get_agent(as_dict: bool = False) -> str:
137    """Build and return a user agent string.
138
139    :param as_dict: If True, return {"User-Agent": useragent} instead of just the useragent string.
140    Note: Leaving this parameter in place to maintain backwards compatibility,
141    but it's advised to use the `get_header()` function instead."""
142    browsers = json.loads((Path(__file__).parent / "browserVersions.json").read_text())
143    for browser in browsers:
144        browsers[browser] = randomize_version_number(browsers[browser])
145    browser = random.choice(list(browsers.keys()))
146    if browser == "Safari":
147        platform = platforms[-1]
148        useragent = f'Mozilla/5.0 {platform} AppleWebKit/605.1.15 (KHTML, like Gecko) Version/{browsers["Safari"]} Safari/605.1.15'
149    else:
150        platform = random.choice(platforms)
151        if browser == "Firefox":
152            platform = platform[: platform.rfind(")")] + f"; rv:{browsers[browser]})"
153            useragent = (
154                f"Mozilla/5.0 {platform} Gecko/20100101 Firefox/{browsers[browser]}"
155            )
156        else:
157            useragent = f'Mozilla/5.0 {platform} AppleWebKit/537.36 (KHTML, like Gecko) Chrome/{browsers["Chrome"]} Safari/537.36'
158            if browser == "Edg":
159                useragent += f' Edg/{browsers["Edg"]}'
160            elif browser == "OPR":
161                useragent += f' OPR/{browsers["OPR"]}'
162            elif browser == "Vivaldi":
163                useragent += f' Vivaldi/{browsers["Vivaldi"]}'
164    if as_dict:
165        return {"User-Agent": useragent}
166    else:
167        return useragent
168
169
170def get_header() -> dict[str, str]:
171    """Returns a dictionary `{'User-Agent': <random user agent string>}` for convenience.
172    >>> response = requests.get(url, headers=get_header())"""
173    return {"User-Agent": get_agent()}
class VersionUpdater:
 11class VersionUpdater:
 12    def __init__(self):
 13        self.versions_path = Path(__file__).parent / "browserVersions.json"
 14        if not self.versions_path.exists():
 15            self.versions_path.write_text(json.dumps({}))
 16
 17    def update_firefox(self):
 18        try:
 19            url = "https://www.mozilla.org/en-US/firefox/releases/"
 20            soup = BeautifulSoup(requests.get(url).text, "html.parser")
 21            release_list = soup.find("ol", class_="c-release-list")
 22            version = release_list.ol.li.a.text
 23            self.firefox = version
 24        except Exception as e:
 25            print(e)
 26            raise Exception("Error updating firefox")
 27
 28    def update_chrome(self):
 29        try:
 30            url = "https://en.wikipedia.org/wiki/Google_Chrome"
 31            soup = BeautifulSoup(requests.get(url).text, "html.parser")
 32            info_boxes = soup.find_all("td", class_="infobox-data")
 33            version = info_boxes[8].text[
 34                : min([info_boxes[8].text.find("["), info_boxes[8].text.find("/")])
 35            ]
 36            self.chrome = version
 37        except Exception as e:
 38            print(e)
 39            raise Exception("Error updating chrome")
 40
 41    def update_safari(self):
 42        try:
 43            url = "https://en.wikipedia.org/wiki/Safari_(web_browser)"
 44            soup = BeautifulSoup(requests.get(url).text, "html.parser")
 45            info_boxes = soup.find_all("td", class_="infobox-data")
 46            version = info_boxes[2].text[: info_boxes[2].text.find("[")]
 47            self.safari = version
 48        except Exception as e:
 49            print(e)
 50            raise Exception("Error updating safari")
 51
 52    def update_edge(self):
 53        try:
 54            url = "https://www.techspot.com/downloads/7158-microsoft-edge.html"
 55            soup = BeautifulSoup(requests.get(url).text, "html.parser")
 56            version = soup.find("span", class_="subver").text
 57            self.edge = version
 58        except Exception as e:
 59            print(e)
 60            raise Exception("Error updating edge")
 61
 62    def update_vivaldi(self):
 63        try:
 64            url = "https://vivaldi.com/blog/"
 65            soup = BeautifulSoup(requests.get(url).text, "html.parser")
 66            text = soup.find("div", class_="download-vivaldi-sidebar").text
 67            text = text.split(" - ")[1]
 68            text = text.replace(" (", ".")
 69            version = text[: text.find(")")]
 70            self.vivaldi = version
 71        except Exception as e:
 72            print(e)
 73            raise Exception("Error updating vivaldi")
 74
 75    def update_opera(self) -> str:
 76        try:
 77            url = "https://en.wikipedia.org/wiki/Opera_(web_browser)"
 78            soup = BeautifulSoup(requests.get(url).text, "html.parser")
 79            info_boxes = soup.find_all("td", class_="infobox-data")
 80            version = info_boxes[2].div.text[: info_boxes[2].div.text.find("[")]
 81            self.opera = version
 82        except Exception as e:
 83            print(e)
 84            raise Exception("Error updating Opera")
 85
 86    def update_all(self):
 87        updaters = [
 88            self.update_firefox,
 89            self.update_chrome,
 90            self.update_safari,
 91            self.update_edge,
 92            self.update_vivaldi,
 93            self.update_opera,
 94        ]
 95        with ThreadPoolExecutor(6) as executor:
 96            for updater in updaters:
 97                executor.submit(updater)
 98        versions = {
 99            "Firefox": self.firefox,
100            "Chrome": self.chrome,
101            "Edg": self.edge,
102            "Vivaldi": self.vivaldi,
103            "OPR": self.opera,
104            "Safari": self.safari,
105        }
106        # Remove any keys that failed to update and keep previous version number
107        poppers = [
108            version
109            for version in versions
110            if not ((versions[version]).replace(".", "")).isnumeric()
111        ]
112        for popper in poppers:
113            versions.pop(popper)
114        previous_versions = json.loads(self.versions_path.read_text())
115        versions = previous_versions | versions
116        self.versions_path.write_text(json.dumps(versions))
VersionUpdater()
12    def __init__(self):
13        self.versions_path = Path(__file__).parent / "browserVersions.json"
14        if not self.versions_path.exists():
15            self.versions_path.write_text(json.dumps({}))
def update_firefox(self):
17    def update_firefox(self):
18        try:
19            url = "https://www.mozilla.org/en-US/firefox/releases/"
20            soup = BeautifulSoup(requests.get(url).text, "html.parser")
21            release_list = soup.find("ol", class_="c-release-list")
22            version = release_list.ol.li.a.text
23            self.firefox = version
24        except Exception as e:
25            print(e)
26            raise Exception("Error updating firefox")
def update_chrome(self):
28    def update_chrome(self):
29        try:
30            url = "https://en.wikipedia.org/wiki/Google_Chrome"
31            soup = BeautifulSoup(requests.get(url).text, "html.parser")
32            info_boxes = soup.find_all("td", class_="infobox-data")
33            version = info_boxes[8].text[
34                : min([info_boxes[8].text.find("["), info_boxes[8].text.find("/")])
35            ]
36            self.chrome = version
37        except Exception as e:
38            print(e)
39            raise Exception("Error updating chrome")
def update_safari(self):
41    def update_safari(self):
42        try:
43            url = "https://en.wikipedia.org/wiki/Safari_(web_browser)"
44            soup = BeautifulSoup(requests.get(url).text, "html.parser")
45            info_boxes = soup.find_all("td", class_="infobox-data")
46            version = info_boxes[2].text[: info_boxes[2].text.find("[")]
47            self.safari = version
48        except Exception as e:
49            print(e)
50            raise Exception("Error updating safari")
def update_edge(self):
52    def update_edge(self):
53        try:
54            url = "https://www.techspot.com/downloads/7158-microsoft-edge.html"
55            soup = BeautifulSoup(requests.get(url).text, "html.parser")
56            version = soup.find("span", class_="subver").text
57            self.edge = version
58        except Exception as e:
59            print(e)
60            raise Exception("Error updating edge")
def update_vivaldi(self):
62    def update_vivaldi(self):
63        try:
64            url = "https://vivaldi.com/blog/"
65            soup = BeautifulSoup(requests.get(url).text, "html.parser")
66            text = soup.find("div", class_="download-vivaldi-sidebar").text
67            text = text.split(" - ")[1]
68            text = text.replace(" (", ".")
69            version = text[: text.find(")")]
70            self.vivaldi = version
71        except Exception as e:
72            print(e)
73            raise Exception("Error updating vivaldi")
def update_opera(self) -> str:
75    def update_opera(self) -> str:
76        try:
77            url = "https://en.wikipedia.org/wiki/Opera_(web_browser)"
78            soup = BeautifulSoup(requests.get(url).text, "html.parser")
79            info_boxes = soup.find_all("td", class_="infobox-data")
80            version = info_boxes[2].div.text[: info_boxes[2].div.text.find("[")]
81            self.opera = version
82        except Exception as e:
83            print(e)
84            raise Exception("Error updating Opera")
def update_all(self):
 86    def update_all(self):
 87        updaters = [
 88            self.update_firefox,
 89            self.update_chrome,
 90            self.update_safari,
 91            self.update_edge,
 92            self.update_vivaldi,
 93            self.update_opera,
 94        ]
 95        with ThreadPoolExecutor(6) as executor:
 96            for updater in updaters:
 97                executor.submit(updater)
 98        versions = {
 99            "Firefox": self.firefox,
100            "Chrome": self.chrome,
101            "Edg": self.edge,
102            "Vivaldi": self.vivaldi,
103            "OPR": self.opera,
104            "Safari": self.safari,
105        }
106        # Remove any keys that failed to update and keep previous version number
107        poppers = [
108            version
109            for version in versions
110            if not ((versions[version]).replace(".", "")).isnumeric()
111        ]
112        for popper in poppers:
113            versions.pop(popper)
114        previous_versions = json.loads(self.versions_path.read_text())
115        versions = previous_versions | versions
116        self.versions_path.write_text(json.dumps(versions))
def randomize_version_number(version: str) -> str:
127def randomize_version_number(version: str) -> str:
128    """Randomize a version number so that it's in between
129    the previous major version and the current one."""
130    parts = [int(part) for part in version.split(".")]
131    parts[0] = random.randint(parts[0] - 1, parts[0])
132    for i, part in enumerate(parts[1:]):
133        parts[i + 1] = random.randint(0, part)
134    return ".".join(str(part) for part in parts)

Randomize a version number so that it's in between the previous major version and the current one.

def get_agent(as_dict: bool = False) -> str:
137def get_agent(as_dict: bool = False) -> str:
138    """Build and return a user agent string.
139
140    :param as_dict: If True, return {"User-Agent": useragent} instead of just the useragent string.
141    Note: Leaving this parameter in place to maintain backwards compatibility,
142    but it's advised to use the `get_header()` function instead."""
143    browsers = json.loads((Path(__file__).parent / "browserVersions.json").read_text())
144    for browser in browsers:
145        browsers[browser] = randomize_version_number(browsers[browser])
146    browser = random.choice(list(browsers.keys()))
147    if browser == "Safari":
148        platform = platforms[-1]
149        useragent = f'Mozilla/5.0 {platform} AppleWebKit/605.1.15 (KHTML, like Gecko) Version/{browsers["Safari"]} Safari/605.1.15'
150    else:
151        platform = random.choice(platforms)
152        if browser == "Firefox":
153            platform = platform[: platform.rfind(")")] + f"; rv:{browsers[browser]})"
154            useragent = (
155                f"Mozilla/5.0 {platform} Gecko/20100101 Firefox/{browsers[browser]}"
156            )
157        else:
158            useragent = f'Mozilla/5.0 {platform} AppleWebKit/537.36 (KHTML, like Gecko) Chrome/{browsers["Chrome"]} Safari/537.36'
159            if browser == "Edg":
160                useragent += f' Edg/{browsers["Edg"]}'
161            elif browser == "OPR":
162                useragent += f' OPR/{browsers["OPR"]}'
163            elif browser == "Vivaldi":
164                useragent += f' Vivaldi/{browsers["Vivaldi"]}'
165    if as_dict:
166        return {"User-Agent": useragent}
167    else:
168        return useragent

Build and return a user agent string.

Parameters
  • as_dict: If True, return {"User-Agent": useragent} instead of just the useragent string. Note: Leaving this parameter in place to maintain backwards compatibility, but it's advised to use the get_header() function instead.
def get_header() -> dict[str, str]:
171def get_header() -> dict[str, str]:
172    """Returns a dictionary `{'User-Agent': <random user agent string>}` for convenience.
173    >>> response = requests.get(url, headers=get_header())"""
174    return {"User-Agent": get_agent()}

Returns a dictionary {'User-Agent': <random user agent string>} for convenience.

>>> response = requests.get(url, headers=get_header())