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))
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())