webscout 8.3.6__py3-none-any.whl โ†’ 2025.10.11__py3-none-any.whl

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.

Potentially problematic release.


This version of webscout might be problematic. Click here for more details.

Files changed (304) hide show
  1. webscout/AIauto.py +250 -250
  2. webscout/AIbase.py +379 -379
  3. webscout/AIutel.py +60 -58
  4. webscout/Bard.py +1012 -1012
  5. webscout/Bing_search.py +417 -417
  6. webscout/DWEBS.py +529 -529
  7. webscout/Extra/Act.md +309 -309
  8. webscout/Extra/GitToolkit/__init__.py +10 -10
  9. webscout/Extra/GitToolkit/gitapi/README.md +110 -110
  10. webscout/Extra/GitToolkit/gitapi/__init__.py +11 -11
  11. webscout/Extra/GitToolkit/gitapi/repository.py +195 -195
  12. webscout/Extra/GitToolkit/gitapi/user.py +96 -96
  13. webscout/Extra/GitToolkit/gitapi/utils.py +61 -61
  14. webscout/Extra/YTToolkit/README.md +375 -375
  15. webscout/Extra/YTToolkit/YTdownloader.py +956 -956
  16. webscout/Extra/YTToolkit/__init__.py +2 -2
  17. webscout/Extra/YTToolkit/transcriber.py +475 -475
  18. webscout/Extra/YTToolkit/ytapi/README.md +44 -44
  19. webscout/Extra/YTToolkit/ytapi/__init__.py +6 -6
  20. webscout/Extra/YTToolkit/ytapi/channel.py +307 -307
  21. webscout/Extra/YTToolkit/ytapi/errors.py +13 -13
  22. webscout/Extra/YTToolkit/ytapi/extras.py +118 -118
  23. webscout/Extra/YTToolkit/ytapi/https.py +88 -88
  24. webscout/Extra/YTToolkit/ytapi/patterns.py +61 -61
  25. webscout/Extra/YTToolkit/ytapi/playlist.py +58 -58
  26. webscout/Extra/YTToolkit/ytapi/pool.py +7 -7
  27. webscout/Extra/YTToolkit/ytapi/query.py +39 -39
  28. webscout/Extra/YTToolkit/ytapi/stream.py +62 -62
  29. webscout/Extra/YTToolkit/ytapi/utils.py +62 -62
  30. webscout/Extra/YTToolkit/ytapi/video.py +232 -232
  31. webscout/Extra/autocoder/__init__.py +9 -9
  32. webscout/Extra/autocoder/autocoder.py +1105 -1105
  33. webscout/Extra/autocoder/autocoder_utiles.py +332 -332
  34. webscout/Extra/gguf.md +429 -429
  35. webscout/Extra/gguf.py +1213 -1213
  36. webscout/Extra/tempmail/README.md +487 -487
  37. webscout/Extra/tempmail/__init__.py +27 -27
  38. webscout/Extra/tempmail/async_utils.py +140 -140
  39. webscout/Extra/tempmail/base.py +160 -160
  40. webscout/Extra/tempmail/cli.py +186 -186
  41. webscout/Extra/tempmail/emailnator.py +84 -84
  42. webscout/Extra/tempmail/mail_tm.py +360 -360
  43. webscout/Extra/tempmail/temp_mail_io.py +291 -291
  44. webscout/Extra/weather.md +281 -281
  45. webscout/Extra/weather.py +193 -193
  46. webscout/Litlogger/README.md +10 -10
  47. webscout/Litlogger/__init__.py +15 -15
  48. webscout/Litlogger/formats.py +13 -13
  49. webscout/Litlogger/handlers.py +121 -121
  50. webscout/Litlogger/levels.py +13 -13
  51. webscout/Litlogger/logger.py +134 -134
  52. webscout/Provider/AISEARCH/Perplexity.py +332 -332
  53. webscout/Provider/AISEARCH/README.md +279 -279
  54. webscout/Provider/AISEARCH/__init__.py +33 -11
  55. webscout/Provider/AISEARCH/felo_search.py +206 -206
  56. webscout/Provider/AISEARCH/genspark_search.py +323 -323
  57. webscout/Provider/AISEARCH/hika_search.py +185 -185
  58. webscout/Provider/AISEARCH/iask_search.py +410 -410
  59. webscout/Provider/AISEARCH/monica_search.py +219 -219
  60. webscout/Provider/AISEARCH/scira_search.py +316 -314
  61. webscout/Provider/AISEARCH/stellar_search.py +177 -177
  62. webscout/Provider/AISEARCH/webpilotai_search.py +255 -255
  63. webscout/Provider/Aitopia.py +314 -315
  64. webscout/Provider/Andi.py +3 -3
  65. webscout/Provider/Apriel.py +306 -0
  66. webscout/Provider/ChatGPTClone.py +236 -236
  67. webscout/Provider/ChatSandbox.py +343 -342
  68. webscout/Provider/Cloudflare.py +324 -324
  69. webscout/Provider/Cohere.py +208 -207
  70. webscout/Provider/Deepinfra.py +370 -369
  71. webscout/Provider/ExaAI.py +260 -260
  72. webscout/Provider/ExaChat.py +308 -387
  73. webscout/Provider/Flowith.py +221 -221
  74. webscout/Provider/GMI.py +293 -0
  75. webscout/Provider/Gemini.py +164 -162
  76. webscout/Provider/GeminiProxy.py +167 -166
  77. webscout/Provider/GithubChat.py +371 -370
  78. webscout/Provider/Groq.py +800 -800
  79. webscout/Provider/HeckAI.py +383 -379
  80. webscout/Provider/Jadve.py +282 -297
  81. webscout/Provider/K2Think.py +308 -0
  82. webscout/Provider/Koboldai.py +206 -384
  83. webscout/Provider/LambdaChat.py +423 -425
  84. webscout/Provider/Nemotron.py +244 -245
  85. webscout/Provider/Netwrck.py +248 -247
  86. webscout/Provider/OLLAMA.py +395 -394
  87. webscout/Provider/OPENAI/Cloudflare.py +394 -395
  88. webscout/Provider/OPENAI/FalconH1.py +452 -457
  89. webscout/Provider/OPENAI/FreeGemini.py +297 -299
  90. webscout/Provider/OPENAI/{monochat.py โ†’ K2Think.py} +432 -329
  91. webscout/Provider/OPENAI/NEMOTRON.py +241 -244
  92. webscout/Provider/OPENAI/PI.py +428 -427
  93. webscout/Provider/OPENAI/README.md +959 -959
  94. webscout/Provider/OPENAI/TogetherAI.py +345 -345
  95. webscout/Provider/OPENAI/TwoAI.py +466 -467
  96. webscout/Provider/OPENAI/__init__.py +33 -59
  97. webscout/Provider/OPENAI/ai4chat.py +313 -303
  98. webscout/Provider/OPENAI/base.py +249 -269
  99. webscout/Provider/OPENAI/chatglm.py +528 -0
  100. webscout/Provider/OPENAI/chatgpt.py +593 -588
  101. webscout/Provider/OPENAI/chatgptclone.py +521 -524
  102. webscout/Provider/OPENAI/chatsandbox.py +202 -177
  103. webscout/Provider/OPENAI/deepinfra.py +319 -315
  104. webscout/Provider/OPENAI/e2b.py +1665 -1665
  105. webscout/Provider/OPENAI/exaai.py +420 -420
  106. webscout/Provider/OPENAI/exachat.py +452 -452
  107. webscout/Provider/OPENAI/friendli.py +232 -232
  108. webscout/Provider/OPENAI/{refact.py โ†’ gmi.py} +324 -274
  109. webscout/Provider/OPENAI/groq.py +364 -364
  110. webscout/Provider/OPENAI/heckai.py +314 -311
  111. webscout/Provider/OPENAI/llmchatco.py +337 -337
  112. webscout/Provider/OPENAI/netwrck.py +355 -354
  113. webscout/Provider/OPENAI/oivscode.py +290 -290
  114. webscout/Provider/OPENAI/opkfc.py +518 -518
  115. webscout/Provider/OPENAI/pydantic_imports.py +1 -1
  116. webscout/Provider/OPENAI/scirachat.py +535 -529
  117. webscout/Provider/OPENAI/sonus.py +308 -308
  118. webscout/Provider/OPENAI/standardinput.py +442 -442
  119. webscout/Provider/OPENAI/textpollinations.py +340 -348
  120. webscout/Provider/OPENAI/toolbaz.py +419 -413
  121. webscout/Provider/OPENAI/typefully.py +362 -362
  122. webscout/Provider/OPENAI/utils.py +295 -295
  123. webscout/Provider/OPENAI/venice.py +436 -436
  124. webscout/Provider/OPENAI/wisecat.py +387 -387
  125. webscout/Provider/OPENAI/writecream.py +166 -166
  126. webscout/Provider/OPENAI/x0gpt.py +378 -378
  127. webscout/Provider/OPENAI/yep.py +389 -389
  128. webscout/Provider/OpenGPT.py +230 -230
  129. webscout/Provider/Openai.py +244 -496
  130. webscout/Provider/PI.py +405 -404
  131. webscout/Provider/Perplexitylabs.py +430 -431
  132. webscout/Provider/QwenLM.py +272 -254
  133. webscout/Provider/STT/__init__.py +32 -2
  134. webscout/Provider/{Llama3.py โ†’ Sambanova.py} +257 -258
  135. webscout/Provider/StandardInput.py +309 -309
  136. webscout/Provider/TTI/README.md +82 -82
  137. webscout/Provider/TTI/__init__.py +33 -12
  138. webscout/Provider/TTI/aiarta.py +413 -413
  139. webscout/Provider/TTI/base.py +136 -136
  140. webscout/Provider/TTI/bing.py +243 -243
  141. webscout/Provider/TTI/gpt1image.py +149 -149
  142. webscout/Provider/TTI/imagen.py +196 -196
  143. webscout/Provider/TTI/infip.py +211 -211
  144. webscout/Provider/TTI/magicstudio.py +232 -232
  145. webscout/Provider/TTI/monochat.py +219 -219
  146. webscout/Provider/TTI/piclumen.py +214 -214
  147. webscout/Provider/TTI/pixelmuse.py +232 -232
  148. webscout/Provider/TTI/pollinations.py +232 -232
  149. webscout/Provider/TTI/together.py +288 -288
  150. webscout/Provider/TTI/utils.py +12 -12
  151. webscout/Provider/TTI/venice.py +367 -367
  152. webscout/Provider/TTS/README.md +192 -192
  153. webscout/Provider/TTS/__init__.py +33 -10
  154. webscout/Provider/TTS/parler.py +110 -110
  155. webscout/Provider/TTS/streamElements.py +333 -333
  156. webscout/Provider/TTS/utils.py +280 -280
  157. webscout/Provider/TeachAnything.py +237 -236
  158. webscout/Provider/TextPollinationsAI.py +311 -318
  159. webscout/Provider/TogetherAI.py +356 -357
  160. webscout/Provider/TwoAI.py +313 -569
  161. webscout/Provider/TypliAI.py +312 -311
  162. webscout/Provider/UNFINISHED/ChatHub.py +208 -208
  163. webscout/Provider/UNFINISHED/ChutesAI.py +313 -313
  164. webscout/Provider/{GizAI.py โ†’ UNFINISHED/GizAI.py} +294 -294
  165. webscout/Provider/{Marcus.py โ†’ UNFINISHED/Marcus.py} +198 -198
  166. webscout/Provider/{Qodo.py โ†’ UNFINISHED/Qodo.py} +477 -477
  167. webscout/Provider/UNFINISHED/VercelAIGateway.py +338 -338
  168. webscout/Provider/{XenAI.py โ†’ UNFINISHED/XenAI.py} +324 -324
  169. webscout/Provider/UNFINISHED/Youchat.py +330 -330
  170. webscout/Provider/UNFINISHED/liner.py +334 -0
  171. webscout/Provider/UNFINISHED/liner_api_request.py +262 -262
  172. webscout/Provider/UNFINISHED/puterjs.py +634 -634
  173. webscout/Provider/UNFINISHED/samurai.py +223 -223
  174. webscout/Provider/UNFINISHED/test_lmarena.py +119 -119
  175. webscout/Provider/Venice.py +251 -250
  176. webscout/Provider/VercelAI.py +256 -255
  177. webscout/Provider/WiseCat.py +232 -231
  178. webscout/Provider/WrDoChat.py +367 -366
  179. webscout/Provider/__init__.py +33 -86
  180. webscout/Provider/ai4chat.py +174 -174
  181. webscout/Provider/akashgpt.py +331 -334
  182. webscout/Provider/cerebras.py +446 -340
  183. webscout/Provider/chatglm.py +394 -214
  184. webscout/Provider/cleeai.py +211 -212
  185. webscout/Provider/deepseek_assistant.py +1 -1
  186. webscout/Provider/elmo.py +282 -282
  187. webscout/Provider/geminiapi.py +208 -208
  188. webscout/Provider/granite.py +261 -261
  189. webscout/Provider/hermes.py +263 -265
  190. webscout/Provider/julius.py +223 -222
  191. webscout/Provider/learnfastai.py +309 -309
  192. webscout/Provider/llama3mitril.py +214 -214
  193. webscout/Provider/llmchat.py +243 -243
  194. webscout/Provider/llmchatco.py +290 -290
  195. webscout/Provider/meta.py +801 -801
  196. webscout/Provider/oivscode.py +309 -309
  197. webscout/Provider/scira_chat.py +384 -457
  198. webscout/Provider/searchchat.py +292 -291
  199. webscout/Provider/sonus.py +258 -258
  200. webscout/Provider/toolbaz.py +370 -364
  201. webscout/Provider/turboseek.py +274 -265
  202. webscout/Provider/typefully.py +208 -207
  203. webscout/Provider/x0gpt.py +1 -0
  204. webscout/Provider/yep.py +372 -371
  205. webscout/__init__.py +30 -31
  206. webscout/__main__.py +5 -5
  207. webscout/auth/api_key_manager.py +189 -189
  208. webscout/auth/config.py +175 -175
  209. webscout/auth/models.py +185 -185
  210. webscout/auth/routes.py +664 -664
  211. webscout/auth/simple_logger.py +236 -236
  212. webscout/cli.py +523 -523
  213. webscout/conversation.py +438 -438
  214. webscout/exceptions.py +361 -361
  215. webscout/litagent/Readme.md +298 -298
  216. webscout/litagent/__init__.py +28 -28
  217. webscout/litagent/agent.py +581 -581
  218. webscout/litagent/constants.py +59 -59
  219. webscout/litprinter/__init__.py +58 -58
  220. webscout/models.py +181 -181
  221. webscout/optimizers.py +419 -419
  222. webscout/prompt_manager.py +288 -288
  223. webscout/sanitize.py +1078 -1078
  224. webscout/scout/README.md +401 -401
  225. webscout/scout/__init__.py +8 -8
  226. webscout/scout/core/__init__.py +6 -6
  227. webscout/scout/core/crawler.py +297 -297
  228. webscout/scout/core/scout.py +706 -706
  229. webscout/scout/core/search_result.py +95 -95
  230. webscout/scout/core/text_analyzer.py +62 -62
  231. webscout/scout/core/text_utils.py +277 -277
  232. webscout/scout/core/web_analyzer.py +51 -51
  233. webscout/scout/element.py +599 -599
  234. webscout/scout/parsers/__init__.py +69 -69
  235. webscout/scout/parsers/html5lib_parser.py +172 -172
  236. webscout/scout/parsers/html_parser.py +236 -236
  237. webscout/scout/parsers/lxml_parser.py +178 -178
  238. webscout/scout/utils.py +37 -37
  239. webscout/swiftcli/Readme.md +323 -323
  240. webscout/swiftcli/__init__.py +95 -95
  241. webscout/swiftcli/core/__init__.py +7 -7
  242. webscout/swiftcli/core/cli.py +308 -308
  243. webscout/swiftcli/core/context.py +104 -104
  244. webscout/swiftcli/core/group.py +241 -241
  245. webscout/swiftcli/decorators/__init__.py +28 -28
  246. webscout/swiftcli/decorators/command.py +221 -221
  247. webscout/swiftcli/decorators/options.py +220 -220
  248. webscout/swiftcli/decorators/output.py +302 -302
  249. webscout/swiftcli/exceptions.py +21 -21
  250. webscout/swiftcli/plugins/__init__.py +9 -9
  251. webscout/swiftcli/plugins/base.py +135 -135
  252. webscout/swiftcli/plugins/manager.py +269 -269
  253. webscout/swiftcli/utils/__init__.py +59 -59
  254. webscout/swiftcli/utils/formatting.py +252 -252
  255. webscout/swiftcli/utils/parsing.py +267 -267
  256. webscout/update_checker.py +117 -117
  257. webscout/version.py +1 -1
  258. webscout/webscout_search.py +1183 -1183
  259. webscout/webscout_search_async.py +649 -649
  260. webscout/yep_search.py +346 -346
  261. webscout/zeroart/README.md +89 -89
  262. webscout/zeroart/__init__.py +134 -134
  263. webscout/zeroart/base.py +66 -66
  264. webscout/zeroart/effects.py +100 -100
  265. webscout/zeroart/fonts.py +1238 -1238
  266. {webscout-8.3.6.dist-info โ†’ webscout-2025.10.11.dist-info}/METADATA +937 -936
  267. webscout-2025.10.11.dist-info/RECORD +300 -0
  268. webscout/Provider/AISEARCH/DeepFind.py +0 -254
  269. webscout/Provider/AllenAI.py +0 -440
  270. webscout/Provider/Blackboxai.py +0 -793
  271. webscout/Provider/FreeGemini.py +0 -250
  272. webscout/Provider/GptOss.py +0 -207
  273. webscout/Provider/Hunyuan.py +0 -283
  274. webscout/Provider/Kimi.py +0 -445
  275. webscout/Provider/MCPCore.py +0 -322
  276. webscout/Provider/MiniMax.py +0 -207
  277. webscout/Provider/OPENAI/BLACKBOXAI.py +0 -1045
  278. webscout/Provider/OPENAI/MiniMax.py +0 -298
  279. webscout/Provider/OPENAI/Qwen3.py +0 -304
  280. webscout/Provider/OPENAI/autoproxy.py +0 -1067
  281. webscout/Provider/OPENAI/copilot.py +0 -321
  282. webscout/Provider/OPENAI/gptoss.py +0 -288
  283. webscout/Provider/OPENAI/kimi.py +0 -469
  284. webscout/Provider/OPENAI/mcpcore.py +0 -431
  285. webscout/Provider/OPENAI/multichat.py +0 -378
  286. webscout/Provider/OPENAI/qodo.py +0 -630
  287. webscout/Provider/OPENAI/xenai.py +0 -514
  288. webscout/Provider/Reka.py +0 -214
  289. webscout/Provider/UNFINISHED/fetch_together_models.py +0 -90
  290. webscout/Provider/asksteve.py +0 -220
  291. webscout/Provider/copilot.py +0 -441
  292. webscout/Provider/freeaichat.py +0 -294
  293. webscout/Provider/koala.py +0 -182
  294. webscout/Provider/lmarena.py +0 -198
  295. webscout/Provider/monochat.py +0 -275
  296. webscout/Provider/multichat.py +0 -375
  297. webscout/Provider/scnet.py +0 -244
  298. webscout/Provider/talkai.py +0 -194
  299. webscout/tempid.py +0 -128
  300. webscout-8.3.6.dist-info/RECORD +0 -327
  301. {webscout-8.3.6.dist-info โ†’ webscout-2025.10.11.dist-info}/WHEEL +0 -0
  302. {webscout-8.3.6.dist-info โ†’ webscout-2025.10.11.dist-info}/entry_points.txt +0 -0
  303. {webscout-8.3.6.dist-info โ†’ webscout-2025.10.11.dist-info}/licenses/LICENSE.md +0 -0
  304. {webscout-8.3.6.dist-info โ†’ webscout-2025.10.11.dist-info}/top_level.txt +0 -0
@@ -1,582 +1,582 @@
1
- """Main LitAgent implementation."""
2
-
3
- import random
4
- import threading
5
- from typing import Any, Dict, List, Optional
6
-
7
- from webscout.litagent.constants import BROWSERS, DEVICES, FINGERPRINTS, OS_VERSIONS
8
-
9
-
10
- class LitAgent:
11
- """A lit user agent generator that keeps it fresh! ๐ŸŒŸ"""
12
-
13
- def __init__(self, thread_safe: bool = False):
14
- """Initialize LitAgent with style! ๐Ÿ’ซ
15
-
16
- Args:
17
- thread_safe (bool): Enable thread-safety for multi-threaded applications
18
- """
19
- self.agents = self._generate_agents(100) # Keep 100 agents in memory
20
- self.thread_safe = thread_safe
21
- self.lock = threading.RLock() if thread_safe else None
22
- self.ip_pool = self._generate_ip_pool(20)
23
- self._ip_index = 0
24
- self._refresh_timer = None
25
- self._stats = {
26
- "total_generated": 100,
27
- "requests_served": 0,
28
- "browser_usage": {browser: 0 for browser in BROWSERS.keys()},
29
- "device_usage": {device: 0 for device in DEVICES.keys()}
30
- }
31
-
32
- def _generate_agents(self, count: int) -> List[str]:
33
- """Generate some lit user agents! ๐Ÿ› ๏ธ"""
34
- agents = []
35
- for _ in range(count):
36
- browser = random.choice(list(BROWSERS.keys()))
37
- version = random.randint(*BROWSERS[browser])
38
-
39
- if browser in ['chrome', 'firefox', 'edge', 'opera', 'brave', 'vivaldi']:
40
- os_type = random.choice(['windows', 'mac', 'linux'])
41
- os_ver = random.choice(OS_VERSIONS[os_type])
42
-
43
- if os_type == 'windows':
44
- platform = f"Windows NT {os_ver}"
45
- elif os_type == 'mac':
46
- platform = f"Macintosh; Intel Mac OS X {os_ver}"
47
- else:
48
- platform = f"X11; Linux {os_ver}"
49
-
50
- agent = f"Mozilla/5.0 ({platform}) AppleWebKit/537.36 (KHTML, like Gecko) "
51
- if browser == 'chrome':
52
- agent += f"Chrome/{version}.0.0.0 Safari/537.36"
53
- elif browser == 'firefox':
54
- agent += f"Firefox/{version}.0"
55
- elif browser == 'edge':
56
- agent += f"Edge/{version}.0.0.0"
57
- elif browser == 'opera':
58
- agent += f"OPR/{version}.0.0.0"
59
- elif browser == 'brave':
60
- agent += f"Chrome/{version}.0.0.0 Safari/537.36 Brave/{version}.0.0.0"
61
- elif browser == 'vivaldi':
62
- agent += f"Chrome/{version}.0.0.0 Safari/537.36 Vivaldi/{version}.0.{random.randint(1000, 9999)}"
63
-
64
- elif browser == 'safari':
65
- device = random.choice(['mac', 'ios'])
66
- if device == 'mac':
67
- ver = random.choice(OS_VERSIONS['mac'])
68
- agent = f"Mozilla/5.0 (Macintosh; Intel Mac OS X {ver}) "
69
- else:
70
- ver = random.choice(OS_VERSIONS['ios'])
71
- device = random.choice(['iPhone', 'iPad'])
72
- agent = f"Mozilla/5.0 ({device}; CPU OS {ver} like Mac OS X) "
73
- agent += f"AppleWebKit/{version}.1.15 (KHTML, like Gecko) Version/{version//100}.0 Safari/{version}.1.15"
74
-
75
- agents.append(agent)
76
-
77
- return list(set(agents)) # Remove any duplicates
78
-
79
- def _update_stats(self, browser_type=None, device_type=None):
80
- """Update usage statistics."""
81
- if self.thread_safe and self.lock:
82
- with self.lock:
83
- self._stats["requests_served"] += 1
84
- if browser_type:
85
- self._stats["browser_usage"][browser_type] = self._stats["browser_usage"].get(browser_type, 0) + 1
86
- if device_type:
87
- self._stats["device_usage"][device_type] = self._stats["device_usage"].get(device_type, 0) + 1
88
- else:
89
- self._stats["requests_served"] += 1
90
- if browser_type:
91
- self._stats["browser_usage"][browser_type] = self._stats["browser_usage"].get(browser_type, 0) + 1
92
- if device_type:
93
- self._stats["device_usage"][device_type] = self._stats["device_usage"].get(device_type, 0) + 1
94
-
95
- def random(self) -> str:
96
- """Get a random user agent! ๐ŸŽฒ (with blacklist/whitelist support)"""
97
- if hasattr(self, '_whitelist') and self._whitelist:
98
- pool = list(self._whitelist)
99
- else:
100
- pool = [a for a in self.agents if not hasattr(self, '_blacklist') or a not in self._blacklist]
101
- if not pool:
102
- pool = self.agents
103
- if self.thread_safe and self.lock:
104
- with self.lock:
105
- agent = random.choice(pool)
106
- self._update_stats()
107
- self._add_to_history(agent)
108
- return agent
109
- else:
110
- agent = random.choice(pool)
111
- self._update_stats()
112
- self._add_to_history(agent)
113
- return agent
114
-
115
- def browser(self, name: str) -> str:
116
- """Get a browser-specific agent! ๐ŸŒ"""
117
- name = name.lower()
118
- if name not in BROWSERS:
119
- return self.random()
120
-
121
- if self.thread_safe and self.lock:
122
- with self.lock:
123
- agents = [a for a in self.agents if name in a.lower()]
124
- agent = random.choice(agents) if agents else self.random()
125
- self._update_stats(browser_type=name)
126
- return agent
127
- else:
128
- agents = [a for a in self.agents if name in a.lower()]
129
- agent = random.choice(agents) if agents else self.random()
130
- self._update_stats(browser_type=name)
131
- return agent
132
-
133
- def mobile(self) -> str:
134
- """Get a mobile device agent! ๐Ÿ“ฑ"""
135
- if self.thread_safe and self.lock:
136
- with self.lock:
137
- agents = [a for a in self.agents if any(d in a for d in DEVICES['mobile'])]
138
- agent = random.choice(agents) if agents else self.random()
139
- self._update_stats(device_type="mobile")
140
- return agent
141
- else:
142
- agents = [a for a in self.agents if any(d in a for d in DEVICES['mobile'])]
143
- agent = random.choice(agents) if agents else self.random()
144
- self._update_stats(device_type="mobile")
145
- return agent
146
-
147
- def desktop(self) -> str:
148
- """Get a desktop agent! ๐Ÿ’ป"""
149
- if self.thread_safe and self.lock:
150
- with self.lock:
151
- agents = [a for a in self.agents if 'Windows' in a or 'Macintosh' in a or 'Linux' in a]
152
- agent = random.choice(agents) if agents else self.random()
153
- self._update_stats(device_type="desktop")
154
- return agent
155
- else:
156
- agents = [a for a in self.agents if 'Windows' in a or 'Macintosh' in a or 'Linux' in a]
157
- agent = random.choice(agents) if agents else self.random()
158
- self._update_stats(device_type="desktop")
159
- return agent
160
-
161
- def tablet(self) -> str:
162
- """Get a tablet agent! ๐Ÿ“ฑ"""
163
- if self.thread_safe and self.lock:
164
- with self.lock:
165
- # Focus on iPad and Android tablets
166
- agents = [a for a in self.agents if 'iPad' in a or 'Android' in a and 'Mobile' not in a]
167
- agent = random.choice(agents) if agents else self.random()
168
- self._update_stats(device_type="tablet")
169
- return agent
170
- else:
171
- agents = [a for a in self.agents if 'iPad' in a or 'Android' in a and 'Mobile' not in a]
172
- agent = random.choice(agents) if agents else self.random()
173
- self._update_stats(device_type="tablet")
174
- return agent
175
-
176
- def smart_tv(self) -> str:
177
- """Get a Smart TV agent! ๐Ÿ“บ"""
178
- # Create a TV-specific agent since they may not be in our standard pool
179
- tv_type = random.choice(DEVICES['tv'])
180
- if 'Samsung' in tv_type:
181
- agent = f"Mozilla/5.0 (SMART-TV; SAMSUNG; {tv_type}; Tizen 5.5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.38 Safari/537.36"
182
- elif 'LG' in tv_type:
183
- agent = f"Mozilla/5.0 (Web0S; {tv_type}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36"
184
- elif 'Android' in tv_type:
185
- agent = f"Mozilla/5.0 (Linux; Android 9; {tv_type}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36"
186
- elif 'Apple' in tv_type:
187
- agent = "Mozilla/5.0 (AppleTV; CPU like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148"
188
- else:
189
- agent = f"Mozilla/5.0 (Linux; {tv_type}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36"
190
-
191
- self._update_stats(device_type="tv")
192
- return agent
193
-
194
- def gaming(self) -> str:
195
- """Get a gaming console agent! ๐ŸŽฎ"""
196
- console_type = random.choice(DEVICES['console'])
197
- if 'PlayStation' in console_type:
198
- agent = f"Mozilla/5.0 ({console_type}/5.0) AppleWebKit/601.2 (KHTML, like Gecko)"
199
- elif 'Xbox' in console_type:
200
- agent = f"Mozilla/5.0 ({console_type}; Xbox; Xbox One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19041"
201
- elif 'Nintendo' in console_type:
202
- agent = f"Mozilla/5.0 (Nintendo Switch; {console_type}) AppleWebKit/601.6 (KHTML, like Gecko) NintendoBrowser/5.1.0.13343"
203
- else:
204
- agent = self.random()
205
-
206
- self._update_stats(device_type="console")
207
- return agent
208
-
209
- def chrome(self) -> str:
210
- """Get a Chrome agent! ๐ŸŒ"""
211
- return self.browser('chrome')
212
-
213
- def firefox(self) -> str:
214
- """Get a Firefox agent! ๐ŸฆŠ"""
215
- return self.browser('firefox')
216
-
217
- def safari(self) -> str:
218
- """Get a Safari agent! ๐Ÿงญ"""
219
- return self.browser('safari')
220
-
221
- def edge(self) -> str:
222
- """Get an Edge agent! ๐Ÿ“"""
223
- return self.browser('edge')
224
-
225
- def opera(self) -> str:
226
- """Get an Opera agent! ๐ŸŽญ"""
227
- return self.browser('opera')
228
-
229
- def brave(self) -> str:
230
- """Get a Brave agent! ๐Ÿฆ"""
231
- return self.browser('brave')
232
-
233
- def vivaldi(self) -> str:
234
- """Get a Vivaldi agent! ๐ŸŽจ"""
235
- return self.browser('vivaldi')
236
-
237
- # OS-specific agents
238
- def windows(self) -> str:
239
- """Get a Windows agent! ๐ŸชŸ"""
240
- agents = [a for a in self.agents if 'Windows' in a]
241
- agent = random.choice(agents) if agents else self.random()
242
- self._update_stats()
243
- return agent
244
-
245
- def macos(self) -> str:
246
- """Get a macOS agent! ๐ŸŽ"""
247
- agents = [a for a in self.agents if 'Macintosh' in a]
248
- agent = random.choice(agents) if agents else self.random()
249
- self._update_stats()
250
- return agent
251
-
252
- def linux(self) -> str:
253
- """Get a Linux agent! ๐Ÿง"""
254
- agents = [a for a in self.agents if 'Linux' in a and 'Android' not in a]
255
- agent = random.choice(agents) if agents else self.random()
256
- self._update_stats()
257
- return agent
258
-
259
- def android(self) -> str:
260
- """Get an Android agent! ๐Ÿค–"""
261
- agents = [a for a in self.agents if 'Android' in a]
262
- agent = random.choice(agents) if agents else self.random()
263
- self._update_stats()
264
- return agent
265
-
266
- def ios(self) -> str:
267
- """Get an iOS agent! ๐Ÿ“ฑ"""
268
- agents = [a for a in self.agents if 'iPhone' in a or 'iPad' in a]
269
- agent = random.choice(agents) if agents else self.random()
270
- self._update_stats()
271
- return agent
272
-
273
- def custom(self, browser: str, version: Optional[str] = None,
274
- os: Optional[str] = None, os_version: Optional[str] = None,
275
- device_type: Optional[str] = None) -> str:
276
- """Generate a custom user agent with specified parameters! ๐Ÿ› ๏ธ
277
-
278
- Args:
279
- browser: Browser name (chrome, firefox, safari, edge, opera)
280
- version: Browser version (optional)
281
- os: Operating system (windows, mac, linux, android, ios)
282
- os_version: OS version (optional)
283
- device_type: Device type (desktop, mobile, tablet)
284
- Returns:
285
- Customized user agent string
286
- """
287
- browser = browser.lower() if browser else 'chrome'
288
- if browser not in BROWSERS:
289
- browser = 'chrome'
290
-
291
- if version:
292
- try:
293
- version_num = int(version.split('.')[0])
294
- except (ValueError, IndexError):
295
- version_num = random.randint(*BROWSERS[browser])
296
- else:
297
- version_num = random.randint(*BROWSERS[browser])
298
-
299
- os = os.lower() if os else random.choice(['windows', 'mac', 'linux'])
300
- if os not in OS_VERSIONS:
301
- os = 'windows'
302
-
303
- os_ver = os_version or random.choice(OS_VERSIONS[os])
304
-
305
- device_type = device_type.lower() if device_type else 'desktop'
306
-
307
- # Build the user agent
308
- if os == 'windows':
309
- platform = f"Windows NT {os_ver}"
310
- elif os == 'mac':
311
- platform = f"Macintosh; Intel Mac OS X {os_ver}"
312
- elif os == 'linux':
313
- platform = f"X11; Linux {OS_VERSIONS['linux'][0]}"
314
- elif os == 'android':
315
- platform = f"Linux; Android {os_ver}; {random.choice(DEVICES['mobile'])}"
316
- elif os == 'ios':
317
- device = 'iPhone' if device_type == 'mobile' else 'iPad'
318
- platform = f"{device}; CPU OS {os_ver} like Mac OS X"
319
- else:
320
- platform = "Windows NT 10.0" # Default fallback
321
-
322
- agent = f"Mozilla/5.0 ({platform}) AppleWebKit/537.36 (KHTML, like Gecko) "
323
-
324
- if browser == 'chrome':
325
- agent += f"Chrome/{version_num}.0.0.0 Safari/537.36"
326
- elif browser == 'firefox':
327
- agent += f"Firefox/{version_num}.0"
328
- elif browser == 'safari':
329
- safari_ver = random.randint(*BROWSERS['safari'])
330
- agent += f"Version/{version_num}.0 Safari/{safari_ver}.0"
331
- elif browser == 'edge':
332
- agent += f"Chrome/{version_num}.0.0.0 Safari/537.36 Edg/{version_num}.0.0.0"
333
- elif browser == 'opera':
334
- agent += f"Chrome/{version_num}.0.0.0 Safari/537.36 OPR/{version_num}.0.0.0"
335
- elif browser == 'brave':
336
- agent += f"Chrome/{version_num}.0.0.0 Safari/537.36 Brave/{version_num}.1.0"
337
-
338
- self._update_stats(browser_type=browser, device_type=device_type)
339
- return agent
340
-
341
- @staticmethod
342
- def generate_fingerprint(browser: Optional[str] = None) -> Dict[str, str]:
343
- """
344
- Generate a consistent browser fingerprint for anti-fingerprinting purposes.
345
-
346
- This method creates a dictionary of HTTP headers and related values that simulate
347
- a realistic browser fingerprint, including user agent, accept headers, platform,
348
- sec-ch-ua, and various IP-related headers. Optionally, a specific browser type
349
- can be requested.
350
-
351
- Args:
352
- browser (Optional[str]): The browser name to generate the fingerprint for.
353
- If not specified, a random browser is used.
354
-
355
- Returns:
356
- Dict[str, str]: A dictionary containing fingerprinting headers and values.
357
- """
358
- # Get a random user agent using the random() method
359
- agent = LitAgent()
360
- user_agent = agent.random()
361
-
362
- # If browser is specified, try to get a matching one
363
- if browser:
364
- browser = browser.lower()
365
- if browser in BROWSERS:
366
- user_agent = agent.browser(browser)
367
-
368
- accept_language = random.choice(FINGERPRINTS["accept_language"])
369
- accept = random.choice(FINGERPRINTS["accept"])
370
- platform = random.choice(FINGERPRINTS["platforms"])
371
-
372
- # Generate sec-ch-ua based on the user agent
373
- sec_ch_ua = ""
374
- for browser_name in FINGERPRINTS["sec_ch_ua"]:
375
- if browser_name in user_agent.lower():
376
- version = random.randint(*BROWSERS[browser_name])
377
- sec_ch_ua = FINGERPRINTS["sec_ch_ua"][browser_name].format(version, version)
378
- break
379
-
380
- ip = agent.rotate_ip()
381
- fingerprint = {
382
- "user_agent": user_agent,
383
- "accept_language": accept_language,
384
- "accept": accept,
385
- "sec_ch_ua": sec_ch_ua,
386
- "platform": platform,
387
- "x-forwarded-for": ip,
388
- "x-real-ip": ip,
389
- "x-client-ip": ip,
390
- "forwarded": f"for={ip};proto=https",
391
- "x-forwarded-proto": "https",
392
- "x-request-id": agent.random_id(8) if hasattr(agent, 'random_id') else ''.join(random.choices('0123456789abcdef', k=8)),
393
- }
394
-
395
- agent._update_stats(browser_type=browser)
396
- return fingerprint
397
-
398
- def refresh(self) -> None:
399
- """Refresh the agents with new ones! ๐Ÿ”„"""
400
- if self.thread_safe and self.lock:
401
- with self.lock:
402
- self.agents = self._generate_agents(100)
403
- self._stats["total_generated"] += 100
404
- else:
405
- self.agents = self._generate_agents(100)
406
- self._stats["total_generated"] += 100
407
-
408
-
409
- def auto_refresh(self, interval_minutes: int = 30) -> None:
410
- """Set up automatic refreshing of agents pool! โฑ๏ธ
411
-
412
- Args:
413
- interval_minutes: Minutes between refreshes
414
- """
415
- if self._refresh_timer:
416
- self._refresh_timer.cancel()
417
-
418
- def _refresh_task():
419
- self.refresh()
420
- self._refresh_timer = threading.Timer(interval_minutes * 60, _refresh_task)
421
- self._refresh_timer.daemon = True
422
- self._refresh_timer.start()
423
-
424
- self._refresh_timer = threading.Timer(interval_minutes * 60, _refresh_task)
425
- self._refresh_timer.daemon = True
426
- self._refresh_timer.start()
427
-
428
- def get_stats(self) -> Dict[str, Any]:
429
- """Get statistics about agent usage! ๐Ÿ“Š
430
-
431
- Returns:
432
- Dictionary with usage statistics
433
- """
434
- stats_copy = self._stats.copy()
435
- # Calculate top browser
436
- top_browser = max(stats_copy["browser_usage"].items(), key=lambda x: x[1])[0] if stats_copy["browser_usage"] else None
437
- stats_copy["top_browser"] = top_browser
438
-
439
- # Calculate fake detection avoidance rate (just for fun)
440
- stats_copy["avoidance_rate"] = min(99.9, 90 + (stats_copy["total_generated"] / 1000))
441
-
442
- return stats_copy
443
-
444
- def export_stats(self, filename: str) -> bool:
445
- """Export usage statistics to a file! ๐Ÿ’พ
446
- Args:
447
- filename: Path to export the stats
448
- Returns:
449
- True if export was successful, False otherwise
450
- """
451
- try:
452
- import json
453
- with open(filename, 'w') as f:
454
- json.dump(self.get_stats(), f, indent=2)
455
- return True
456
- except Exception:
457
- return False
458
-
459
- def random_crypto_ip(self) -> str:
460
- """Generate a random IP address for cryptography purposes."""
461
- return ".".join(str(random.randint(0, 255)) for _ in range(4))
462
-
463
- def _generate_ip_pool(self, count: int = 20) -> List[str]:
464
- """Generate a pool of random IP addresses."""
465
- return [self.random_crypto_ip() for _ in range(count)]
466
-
467
- def rotate_ip(self) -> str:
468
- """Rotate through the IP pool and return the next IP."""
469
- if not self.ip_pool:
470
- self.ip_pool = self._generate_ip_pool(20)
471
- self._ip_index = 0
472
-
473
- ip = self.ip_pool[self._ip_index]
474
- self._ip_index = (self._ip_index + 1) % len(self.ip_pool)
475
- return ip
476
-
477
- # Backwards compatibility for older versions expecting _random_ip
478
- def _random_ip(self) -> str:
479
- return self.rotate_ip()
480
-
481
- def random_id(self, length: int = 16) -> str:
482
- """Generate a random identifier string."""
483
- return ''.join(random.choices('0123456789abcdef', k=length)).lower()
484
-
485
- def wearable(self) -> str:
486
- """Get a wearable device agent! โŒš"""
487
- wearable_type = random.choice(DEVICES['wearable'])
488
- # Example user agent for wearables (simplified)
489
- if 'Apple Watch' in wearable_type:
490
- agent = f"Mozilla/5.0 (AppleWatch; CPU WatchOS like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/9.0 Mobile/13S344 Safari/602.1"
491
- elif 'Samsung' in wearable_type:
492
- agent = f"Mozilla/5.0 (Linux; Tizen 3.0; {wearable_type}) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/1.0"
493
- elif 'Fitbit' in wearable_type:
494
- agent = f"Mozilla/5.0 (Linux; {wearable_type}) AppleWebKit/537.36 (KHTML, like Gecko)"
495
- elif 'Garmin' in wearable_type:
496
- agent = f"Mozilla/5.0 (Linux; {wearable_type}) AppleWebKit/537.36 (KHTML, like Gecko)"
497
- else:
498
- agent = self.random()
499
- self._update_stats(device_type="wearable")
500
- return agent
501
-
502
- def set_proxy_pool(self, proxies: List[str]):
503
- """Set a pool of proxies for rotation."""
504
- self._proxy_pool = proxies
505
- self._proxy_index = 0
506
-
507
- def rotate_proxy(self) -> Optional[str]:
508
- """Rotate through the proxy pool and return the next proxy."""
509
- if not hasattr(self, '_proxy_pool') or not self._proxy_pool:
510
- return None
511
- proxy = self._proxy_pool[self._proxy_index]
512
- self._proxy_index = (self._proxy_index + 1) % len(self._proxy_pool)
513
- return proxy
514
-
515
- def add_to_blacklist(self, agent: str):
516
- """Add a user agent to the blacklist."""
517
- if not hasattr(self, '_blacklist'):
518
- self._blacklist = set()
519
- self._blacklist.add(agent)
520
-
521
- def add_to_whitelist(self, agent: str):
522
- """Add a user agent to the whitelist."""
523
- if not hasattr(self, '_whitelist'):
524
- self._whitelist = set()
525
- self._whitelist.add(agent)
526
-
527
- def _add_to_history(self, agent: str):
528
- if not hasattr(self, '_history'):
529
- self._history = []
530
- self._history.append(agent)
531
- if len(self._history) > 50:
532
- self._history.pop(0)
533
-
534
- def get_history(self) -> List[str]:
535
- """Get the last 50 user agents served."""
536
- return getattr(self, '_history', [])
537
-
538
- def validate_agent(self, agent: str) -> bool:
539
- """Validate if a user agent string is realistic (basic check)."""
540
- return agent.startswith("Mozilla/5.0") and any(b in agent for b in BROWSERS.keys())
541
-
542
- if __name__ == "__main__":
543
- # Test it out! ๐Ÿงช
544
- agent = LitAgent()
545
- print("Random:", agent.random())
546
- print("Chrome:", agent.chrome())
547
- print("Firefox:", agent.firefox())
548
- print("Safari:", agent.safari())
549
- print("Mobile:", agent.mobile())
550
- print("Desktop:", agent.desktop())
551
- print("Tablet:", agent.tablet())
552
- print("Smart TV:", agent.smart_tv())
553
- print("Gaming:", agent.gaming())
554
- print("Wearable:", agent.wearable())
555
-
556
- # Test custom agent
557
- print("Custom:", agent.custom(browser="chrome", os="windows", os_version="10.0"))
558
-
559
- # Test fingerprinting
560
- print("Fingerprint:", agent.generate_fingerprint("chrome"))
561
-
562
- # Test proxy rotation
563
- agent.set_proxy_pool(["http://proxy1.com", "http://proxy2.com"])
564
- print("Proxy 1:", agent.rotate_proxy())
565
- print("Proxy 2:", agent.rotate_proxy())
566
-
567
- # Test blacklist/whitelist
568
- agent.add_to_blacklist("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36")
569
- agent.add_to_whitelist("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
570
- print("Blacklisted:", agent.random())
571
- print("Whitelisted:", agent.random())
572
-
573
- # Test agent history
574
- for _ in range(55):
575
- agent.random()
576
- print("History:", agent.get_history())
577
-
578
- # Test agent validation
579
- print("Valid agent:", agent.validate_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"))
580
- print("Invalid agent:", agent.validate_agent("InvalidUserAgentString"))
581
- ip = agent.rotate_ip()
1
+ """Main LitAgent implementation."""
2
+
3
+ import random
4
+ import threading
5
+ from typing import Any, Dict, List, Optional
6
+
7
+ from webscout.litagent.constants import BROWSERS, DEVICES, FINGERPRINTS, OS_VERSIONS
8
+
9
+
10
+ class LitAgent:
11
+ """A lit user agent generator that keeps it fresh! ๐ŸŒŸ"""
12
+
13
+ def __init__(self, thread_safe: bool = False):
14
+ """Initialize LitAgent with style! ๐Ÿ’ซ
15
+
16
+ Args:
17
+ thread_safe (bool): Enable thread-safety for multi-threaded applications
18
+ """
19
+ self.agents = self._generate_agents(100) # Keep 100 agents in memory
20
+ self.thread_safe = thread_safe
21
+ self.lock = threading.RLock() if thread_safe else None
22
+ self.ip_pool = self._generate_ip_pool(20)
23
+ self._ip_index = 0
24
+ self._refresh_timer = None
25
+ self._stats = {
26
+ "total_generated": 100,
27
+ "requests_served": 0,
28
+ "browser_usage": {browser: 0 for browser in BROWSERS.keys()},
29
+ "device_usage": {device: 0 for device in DEVICES.keys()}
30
+ }
31
+
32
+ def _generate_agents(self, count: int) -> List[str]:
33
+ """Generate some lit user agents! ๐Ÿ› ๏ธ"""
34
+ agents = []
35
+ for _ in range(count):
36
+ browser = random.choice(list(BROWSERS.keys()))
37
+ version = random.randint(*BROWSERS[browser])
38
+
39
+ if browser in ['chrome', 'firefox', 'edge', 'opera', 'brave', 'vivaldi']:
40
+ os_type = random.choice(['windows', 'mac', 'linux'])
41
+ os_ver = random.choice(OS_VERSIONS[os_type])
42
+
43
+ if os_type == 'windows':
44
+ platform = f"Windows NT {os_ver}"
45
+ elif os_type == 'mac':
46
+ platform = f"Macintosh; Intel Mac OS X {os_ver}"
47
+ else:
48
+ platform = f"X11; Linux {os_ver}"
49
+
50
+ agent = f"Mozilla/5.0 ({platform}) AppleWebKit/537.36 (KHTML, like Gecko) "
51
+ if browser == 'chrome':
52
+ agent += f"Chrome/{version}.0.0.0 Safari/537.36"
53
+ elif browser == 'firefox':
54
+ agent += f"Firefox/{version}.0"
55
+ elif browser == 'edge':
56
+ agent += f"Edge/{version}.0.0.0"
57
+ elif browser == 'opera':
58
+ agent += f"OPR/{version}.0.0.0"
59
+ elif browser == 'brave':
60
+ agent += f"Chrome/{version}.0.0.0 Safari/537.36 Brave/{version}.0.0.0"
61
+ elif browser == 'vivaldi':
62
+ agent += f"Chrome/{version}.0.0.0 Safari/537.36 Vivaldi/{version}.0.{random.randint(1000, 9999)}"
63
+
64
+ elif browser == 'safari':
65
+ device = random.choice(['mac', 'ios'])
66
+ if device == 'mac':
67
+ ver = random.choice(OS_VERSIONS['mac'])
68
+ agent = f"Mozilla/5.0 (Macintosh; Intel Mac OS X {ver}) "
69
+ else:
70
+ ver = random.choice(OS_VERSIONS['ios'])
71
+ device = random.choice(['iPhone', 'iPad'])
72
+ agent = f"Mozilla/5.0 ({device}; CPU OS {ver} like Mac OS X) "
73
+ agent += f"AppleWebKit/{version}.1.15 (KHTML, like Gecko) Version/{version//100}.0 Safari/{version}.1.15"
74
+
75
+ agents.append(agent)
76
+
77
+ return list(set(agents)) # Remove any duplicates
78
+
79
+ def _update_stats(self, browser_type=None, device_type=None):
80
+ """Update usage statistics."""
81
+ if self.thread_safe and self.lock:
82
+ with self.lock:
83
+ self._stats["requests_served"] += 1
84
+ if browser_type:
85
+ self._stats["browser_usage"][browser_type] = self._stats["browser_usage"].get(browser_type, 0) + 1
86
+ if device_type:
87
+ self._stats["device_usage"][device_type] = self._stats["device_usage"].get(device_type, 0) + 1
88
+ else:
89
+ self._stats["requests_served"] += 1
90
+ if browser_type:
91
+ self._stats["browser_usage"][browser_type] = self._stats["browser_usage"].get(browser_type, 0) + 1
92
+ if device_type:
93
+ self._stats["device_usage"][device_type] = self._stats["device_usage"].get(device_type, 0) + 1
94
+
95
+ def random(self) -> str:
96
+ """Get a random user agent! ๐ŸŽฒ (with blacklist/whitelist support)"""
97
+ if hasattr(self, '_whitelist') and self._whitelist:
98
+ pool = list(self._whitelist)
99
+ else:
100
+ pool = [a for a in self.agents if not hasattr(self, '_blacklist') or a not in self._blacklist]
101
+ if not pool:
102
+ pool = self.agents
103
+ if self.thread_safe and self.lock:
104
+ with self.lock:
105
+ agent = random.choice(pool)
106
+ self._update_stats()
107
+ self._add_to_history(agent)
108
+ return agent
109
+ else:
110
+ agent = random.choice(pool)
111
+ self._update_stats()
112
+ self._add_to_history(agent)
113
+ return agent
114
+
115
+ def browser(self, name: str) -> str:
116
+ """Get a browser-specific agent! ๐ŸŒ"""
117
+ name = name.lower()
118
+ if name not in BROWSERS:
119
+ return self.random()
120
+
121
+ if self.thread_safe and self.lock:
122
+ with self.lock:
123
+ agents = [a for a in self.agents if name in a.lower()]
124
+ agent = random.choice(agents) if agents else self.random()
125
+ self._update_stats(browser_type=name)
126
+ return agent
127
+ else:
128
+ agents = [a for a in self.agents if name in a.lower()]
129
+ agent = random.choice(agents) if agents else self.random()
130
+ self._update_stats(browser_type=name)
131
+ return agent
132
+
133
+ def mobile(self) -> str:
134
+ """Get a mobile device agent! ๐Ÿ“ฑ"""
135
+ if self.thread_safe and self.lock:
136
+ with self.lock:
137
+ agents = [a for a in self.agents if any(d in a for d in DEVICES['mobile'])]
138
+ agent = random.choice(agents) if agents else self.random()
139
+ self._update_stats(device_type="mobile")
140
+ return agent
141
+ else:
142
+ agents = [a for a in self.agents if any(d in a for d in DEVICES['mobile'])]
143
+ agent = random.choice(agents) if agents else self.random()
144
+ self._update_stats(device_type="mobile")
145
+ return agent
146
+
147
+ def desktop(self) -> str:
148
+ """Get a desktop agent! ๐Ÿ’ป"""
149
+ if self.thread_safe and self.lock:
150
+ with self.lock:
151
+ agents = [a for a in self.agents if 'Windows' in a or 'Macintosh' in a or 'Linux' in a]
152
+ agent = random.choice(agents) if agents else self.random()
153
+ self._update_stats(device_type="desktop")
154
+ return agent
155
+ else:
156
+ agents = [a for a in self.agents if 'Windows' in a or 'Macintosh' in a or 'Linux' in a]
157
+ agent = random.choice(agents) if agents else self.random()
158
+ self._update_stats(device_type="desktop")
159
+ return agent
160
+
161
+ def tablet(self) -> str:
162
+ """Get a tablet agent! ๐Ÿ“ฑ"""
163
+ if self.thread_safe and self.lock:
164
+ with self.lock:
165
+ # Focus on iPad and Android tablets
166
+ agents = [a for a in self.agents if 'iPad' in a or 'Android' in a and 'Mobile' not in a]
167
+ agent = random.choice(agents) if agents else self.random()
168
+ self._update_stats(device_type="tablet")
169
+ return agent
170
+ else:
171
+ agents = [a for a in self.agents if 'iPad' in a or 'Android' in a and 'Mobile' not in a]
172
+ agent = random.choice(agents) if agents else self.random()
173
+ self._update_stats(device_type="tablet")
174
+ return agent
175
+
176
+ def smart_tv(self) -> str:
177
+ """Get a Smart TV agent! ๐Ÿ“บ"""
178
+ # Create a TV-specific agent since they may not be in our standard pool
179
+ tv_type = random.choice(DEVICES['tv'])
180
+ if 'Samsung' in tv_type:
181
+ agent = f"Mozilla/5.0 (SMART-TV; SAMSUNG; {tv_type}; Tizen 5.5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.38 Safari/537.36"
182
+ elif 'LG' in tv_type:
183
+ agent = f"Mozilla/5.0 (Web0S; {tv_type}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36"
184
+ elif 'Android' in tv_type:
185
+ agent = f"Mozilla/5.0 (Linux; Android 9; {tv_type}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36"
186
+ elif 'Apple' in tv_type:
187
+ agent = "Mozilla/5.0 (AppleTV; CPU like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148"
188
+ else:
189
+ agent = f"Mozilla/5.0 (Linux; {tv_type}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36"
190
+
191
+ self._update_stats(device_type="tv")
192
+ return agent
193
+
194
+ def gaming(self) -> str:
195
+ """Get a gaming console agent! ๐ŸŽฎ"""
196
+ console_type = random.choice(DEVICES['console'])
197
+ if 'PlayStation' in console_type:
198
+ agent = f"Mozilla/5.0 ({console_type}/5.0) AppleWebKit/601.2 (KHTML, like Gecko)"
199
+ elif 'Xbox' in console_type:
200
+ agent = f"Mozilla/5.0 ({console_type}; Xbox; Xbox One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19041"
201
+ elif 'Nintendo' in console_type:
202
+ agent = f"Mozilla/5.0 (Nintendo Switch; {console_type}) AppleWebKit/601.6 (KHTML, like Gecko) NintendoBrowser/5.1.0.13343"
203
+ else:
204
+ agent = self.random()
205
+
206
+ self._update_stats(device_type="console")
207
+ return agent
208
+
209
+ def chrome(self) -> str:
210
+ """Get a Chrome agent! ๐ŸŒ"""
211
+ return self.browser('chrome')
212
+
213
+ def firefox(self) -> str:
214
+ """Get a Firefox agent! ๐ŸฆŠ"""
215
+ return self.browser('firefox')
216
+
217
+ def safari(self) -> str:
218
+ """Get a Safari agent! ๐Ÿงญ"""
219
+ return self.browser('safari')
220
+
221
+ def edge(self) -> str:
222
+ """Get an Edge agent! ๐Ÿ“"""
223
+ return self.browser('edge')
224
+
225
+ def opera(self) -> str:
226
+ """Get an Opera agent! ๐ŸŽญ"""
227
+ return self.browser('opera')
228
+
229
+ def brave(self) -> str:
230
+ """Get a Brave agent! ๐Ÿฆ"""
231
+ return self.browser('brave')
232
+
233
+ def vivaldi(self) -> str:
234
+ """Get a Vivaldi agent! ๐ŸŽจ"""
235
+ return self.browser('vivaldi')
236
+
237
+ # OS-specific agents
238
+ def windows(self) -> str:
239
+ """Get a Windows agent! ๐ŸชŸ"""
240
+ agents = [a for a in self.agents if 'Windows' in a]
241
+ agent = random.choice(agents) if agents else self.random()
242
+ self._update_stats()
243
+ return agent
244
+
245
+ def macos(self) -> str:
246
+ """Get a macOS agent! ๐ŸŽ"""
247
+ agents = [a for a in self.agents if 'Macintosh' in a]
248
+ agent = random.choice(agents) if agents else self.random()
249
+ self._update_stats()
250
+ return agent
251
+
252
+ def linux(self) -> str:
253
+ """Get a Linux agent! ๐Ÿง"""
254
+ agents = [a for a in self.agents if 'Linux' in a and 'Android' not in a]
255
+ agent = random.choice(agents) if agents else self.random()
256
+ self._update_stats()
257
+ return agent
258
+
259
+ def android(self) -> str:
260
+ """Get an Android agent! ๐Ÿค–"""
261
+ agents = [a for a in self.agents if 'Android' in a]
262
+ agent = random.choice(agents) if agents else self.random()
263
+ self._update_stats()
264
+ return agent
265
+
266
+ def ios(self) -> str:
267
+ """Get an iOS agent! ๐Ÿ“ฑ"""
268
+ agents = [a for a in self.agents if 'iPhone' in a or 'iPad' in a]
269
+ agent = random.choice(agents) if agents else self.random()
270
+ self._update_stats()
271
+ return agent
272
+
273
+ def custom(self, browser: str, version: Optional[str] = None,
274
+ os: Optional[str] = None, os_version: Optional[str] = None,
275
+ device_type: Optional[str] = None) -> str:
276
+ """Generate a custom user agent with specified parameters! ๐Ÿ› ๏ธ
277
+
278
+ Args:
279
+ browser: Browser name (chrome, firefox, safari, edge, opera)
280
+ version: Browser version (optional)
281
+ os: Operating system (windows, mac, linux, android, ios)
282
+ os_version: OS version (optional)
283
+ device_type: Device type (desktop, mobile, tablet)
284
+ Returns:
285
+ Customized user agent string
286
+ """
287
+ browser = browser.lower() if browser else 'chrome'
288
+ if browser not in BROWSERS:
289
+ browser = 'chrome'
290
+
291
+ if version:
292
+ try:
293
+ version_num = int(version.split('.')[0])
294
+ except (ValueError, IndexError):
295
+ version_num = random.randint(*BROWSERS[browser])
296
+ else:
297
+ version_num = random.randint(*BROWSERS[browser])
298
+
299
+ os = os.lower() if os else random.choice(['windows', 'mac', 'linux'])
300
+ if os not in OS_VERSIONS:
301
+ os = 'windows'
302
+
303
+ os_ver = os_version or random.choice(OS_VERSIONS[os])
304
+
305
+ device_type = device_type.lower() if device_type else 'desktop'
306
+
307
+ # Build the user agent
308
+ if os == 'windows':
309
+ platform = f"Windows NT {os_ver}"
310
+ elif os == 'mac':
311
+ platform = f"Macintosh; Intel Mac OS X {os_ver}"
312
+ elif os == 'linux':
313
+ platform = f"X11; Linux {OS_VERSIONS['linux'][0]}"
314
+ elif os == 'android':
315
+ platform = f"Linux; Android {os_ver}; {random.choice(DEVICES['mobile'])}"
316
+ elif os == 'ios':
317
+ device = 'iPhone' if device_type == 'mobile' else 'iPad'
318
+ platform = f"{device}; CPU OS {os_ver} like Mac OS X"
319
+ else:
320
+ platform = "Windows NT 10.0" # Default fallback
321
+
322
+ agent = f"Mozilla/5.0 ({platform}) AppleWebKit/537.36 (KHTML, like Gecko) "
323
+
324
+ if browser == 'chrome':
325
+ agent += f"Chrome/{version_num}.0.0.0 Safari/537.36"
326
+ elif browser == 'firefox':
327
+ agent += f"Firefox/{version_num}.0"
328
+ elif browser == 'safari':
329
+ safari_ver = random.randint(*BROWSERS['safari'])
330
+ agent += f"Version/{version_num}.0 Safari/{safari_ver}.0"
331
+ elif browser == 'edge':
332
+ agent += f"Chrome/{version_num}.0.0.0 Safari/537.36 Edg/{version_num}.0.0.0"
333
+ elif browser == 'opera':
334
+ agent += f"Chrome/{version_num}.0.0.0 Safari/537.36 OPR/{version_num}.0.0.0"
335
+ elif browser == 'brave':
336
+ agent += f"Chrome/{version_num}.0.0.0 Safari/537.36 Brave/{version_num}.1.0"
337
+
338
+ self._update_stats(browser_type=browser, device_type=device_type)
339
+ return agent
340
+
341
+ @staticmethod
342
+ def generate_fingerprint(browser: Optional[str] = None) -> Dict[str, str]:
343
+ """
344
+ Generate a consistent browser fingerprint for anti-fingerprinting purposes.
345
+
346
+ This method creates a dictionary of HTTP headers and related values that simulate
347
+ a realistic browser fingerprint, including user agent, accept headers, platform,
348
+ sec-ch-ua, and various IP-related headers. Optionally, a specific browser type
349
+ can be requested.
350
+
351
+ Args:
352
+ browser (Optional[str]): The browser name to generate the fingerprint for.
353
+ If not specified, a random browser is used.
354
+
355
+ Returns:
356
+ Dict[str, str]: A dictionary containing fingerprinting headers and values.
357
+ """
358
+ # Get a random user agent using the random() method
359
+ agent = LitAgent()
360
+ user_agent = agent.random()
361
+
362
+ # If browser is specified, try to get a matching one
363
+ if browser:
364
+ browser = browser.lower()
365
+ if browser in BROWSERS:
366
+ user_agent = agent.browser(browser)
367
+
368
+ accept_language = random.choice(FINGERPRINTS["accept_language"])
369
+ accept = random.choice(FINGERPRINTS["accept"])
370
+ platform = random.choice(FINGERPRINTS["platforms"])
371
+
372
+ # Generate sec-ch-ua based on the user agent
373
+ sec_ch_ua = ""
374
+ for browser_name in FINGERPRINTS["sec_ch_ua"]:
375
+ if browser_name in user_agent.lower():
376
+ version = random.randint(*BROWSERS[browser_name])
377
+ sec_ch_ua = FINGERPRINTS["sec_ch_ua"][browser_name].format(version, version)
378
+ break
379
+
380
+ ip = agent.rotate_ip()
381
+ fingerprint = {
382
+ "user_agent": user_agent,
383
+ "accept_language": accept_language,
384
+ "accept": accept,
385
+ "sec_ch_ua": sec_ch_ua,
386
+ "platform": platform,
387
+ "x-forwarded-for": ip,
388
+ "x-real-ip": ip,
389
+ "x-client-ip": ip,
390
+ "forwarded": f"for={ip};proto=https",
391
+ "x-forwarded-proto": "https",
392
+ "x-request-id": agent.random_id(8) if hasattr(agent, 'random_id') else ''.join(random.choices('0123456789abcdef', k=8)),
393
+ }
394
+
395
+ agent._update_stats(browser_type=browser)
396
+ return fingerprint
397
+
398
+ def refresh(self) -> None:
399
+ """Refresh the agents with new ones! ๐Ÿ”„"""
400
+ if self.thread_safe and self.lock:
401
+ with self.lock:
402
+ self.agents = self._generate_agents(100)
403
+ self._stats["total_generated"] += 100
404
+ else:
405
+ self.agents = self._generate_agents(100)
406
+ self._stats["total_generated"] += 100
407
+
408
+
409
+ def auto_refresh(self, interval_minutes: int = 30) -> None:
410
+ """Set up automatic refreshing of agents pool! โฑ๏ธ
411
+
412
+ Args:
413
+ interval_minutes: Minutes between refreshes
414
+ """
415
+ if self._refresh_timer:
416
+ self._refresh_timer.cancel()
417
+
418
+ def _refresh_task():
419
+ self.refresh()
420
+ self._refresh_timer = threading.Timer(interval_minutes * 60, _refresh_task)
421
+ self._refresh_timer.daemon = True
422
+ self._refresh_timer.start()
423
+
424
+ self._refresh_timer = threading.Timer(interval_minutes * 60, _refresh_task)
425
+ self._refresh_timer.daemon = True
426
+ self._refresh_timer.start()
427
+
428
+ def get_stats(self) -> Dict[str, Any]:
429
+ """Get statistics about agent usage! ๐Ÿ“Š
430
+
431
+ Returns:
432
+ Dictionary with usage statistics
433
+ """
434
+ stats_copy = self._stats.copy()
435
+ # Calculate top browser
436
+ top_browser = max(stats_copy["browser_usage"].items(), key=lambda x: x[1])[0] if stats_copy["browser_usage"] else None
437
+ stats_copy["top_browser"] = top_browser
438
+
439
+ # Calculate fake detection avoidance rate (just for fun)
440
+ stats_copy["avoidance_rate"] = min(99.9, 90 + (stats_copy["total_generated"] / 1000))
441
+
442
+ return stats_copy
443
+
444
+ def export_stats(self, filename: str) -> bool:
445
+ """Export usage statistics to a file! ๐Ÿ’พ
446
+ Args:
447
+ filename: Path to export the stats
448
+ Returns:
449
+ True if export was successful, False otherwise
450
+ """
451
+ try:
452
+ import json
453
+ with open(filename, 'w') as f:
454
+ json.dump(self.get_stats(), f, indent=2)
455
+ return True
456
+ except Exception:
457
+ return False
458
+
459
+ def random_crypto_ip(self) -> str:
460
+ """Generate a random IP address for cryptography purposes."""
461
+ return ".".join(str(random.randint(0, 255)) for _ in range(4))
462
+
463
+ def _generate_ip_pool(self, count: int = 20) -> List[str]:
464
+ """Generate a pool of random IP addresses."""
465
+ return [self.random_crypto_ip() for _ in range(count)]
466
+
467
+ def rotate_ip(self) -> str:
468
+ """Rotate through the IP pool and return the next IP."""
469
+ if not self.ip_pool:
470
+ self.ip_pool = self._generate_ip_pool(20)
471
+ self._ip_index = 0
472
+
473
+ ip = self.ip_pool[self._ip_index]
474
+ self._ip_index = (self._ip_index + 1) % len(self.ip_pool)
475
+ return ip
476
+
477
+ # Backwards compatibility for older versions expecting _random_ip
478
+ def _random_ip(self) -> str:
479
+ return self.rotate_ip()
480
+
481
+ def random_id(self, length: int = 16) -> str:
482
+ """Generate a random identifier string."""
483
+ return ''.join(random.choices('0123456789abcdef', k=length)).lower()
484
+
485
+ def wearable(self) -> str:
486
+ """Get a wearable device agent! โŒš"""
487
+ wearable_type = random.choice(DEVICES['wearable'])
488
+ # Example user agent for wearables (simplified)
489
+ if 'Apple Watch' in wearable_type:
490
+ agent = f"Mozilla/5.0 (AppleWatch; CPU WatchOS like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/9.0 Mobile/13S344 Safari/602.1"
491
+ elif 'Samsung' in wearable_type:
492
+ agent = f"Mozilla/5.0 (Linux; Tizen 3.0; {wearable_type}) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/1.0"
493
+ elif 'Fitbit' in wearable_type:
494
+ agent = f"Mozilla/5.0 (Linux; {wearable_type}) AppleWebKit/537.36 (KHTML, like Gecko)"
495
+ elif 'Garmin' in wearable_type:
496
+ agent = f"Mozilla/5.0 (Linux; {wearable_type}) AppleWebKit/537.36 (KHTML, like Gecko)"
497
+ else:
498
+ agent = self.random()
499
+ self._update_stats(device_type="wearable")
500
+ return agent
501
+
502
+ def set_proxy_pool(self, proxies: List[str]):
503
+ """Set a pool of proxies for rotation."""
504
+ self._proxy_pool = proxies
505
+ self._proxy_index = 0
506
+
507
+ def rotate_proxy(self) -> Optional[str]:
508
+ """Rotate through the proxy pool and return the next proxy."""
509
+ if not hasattr(self, '_proxy_pool') or not self._proxy_pool:
510
+ return None
511
+ proxy = self._proxy_pool[self._proxy_index]
512
+ self._proxy_index = (self._proxy_index + 1) % len(self._proxy_pool)
513
+ return proxy
514
+
515
+ def add_to_blacklist(self, agent: str):
516
+ """Add a user agent to the blacklist."""
517
+ if not hasattr(self, '_blacklist'):
518
+ self._blacklist = set()
519
+ self._blacklist.add(agent)
520
+
521
+ def add_to_whitelist(self, agent: str):
522
+ """Add a user agent to the whitelist."""
523
+ if not hasattr(self, '_whitelist'):
524
+ self._whitelist = set()
525
+ self._whitelist.add(agent)
526
+
527
+ def _add_to_history(self, agent: str):
528
+ if not hasattr(self, '_history'):
529
+ self._history = []
530
+ self._history.append(agent)
531
+ if len(self._history) > 50:
532
+ self._history.pop(0)
533
+
534
+ def get_history(self) -> List[str]:
535
+ """Get the last 50 user agents served."""
536
+ return getattr(self, '_history', [])
537
+
538
+ def validate_agent(self, agent: str) -> bool:
539
+ """Validate if a user agent string is realistic (basic check)."""
540
+ return agent.startswith("Mozilla/5.0") and any(b in agent for b in BROWSERS.keys())
541
+
542
+ if __name__ == "__main__":
543
+ # Test it out! ๐Ÿงช
544
+ agent = LitAgent()
545
+ print("Random:", agent.random())
546
+ print("Chrome:", agent.chrome())
547
+ print("Firefox:", agent.firefox())
548
+ print("Safari:", agent.safari())
549
+ print("Mobile:", agent.mobile())
550
+ print("Desktop:", agent.desktop())
551
+ print("Tablet:", agent.tablet())
552
+ print("Smart TV:", agent.smart_tv())
553
+ print("Gaming:", agent.gaming())
554
+ print("Wearable:", agent.wearable())
555
+
556
+ # Test custom agent
557
+ print("Custom:", agent.custom(browser="chrome", os="windows", os_version="10.0"))
558
+
559
+ # Test fingerprinting
560
+ print("Fingerprint:", agent.generate_fingerprint("chrome"))
561
+
562
+ # Test proxy rotation
563
+ agent.set_proxy_pool(["http://proxy1.com", "http://proxy2.com"])
564
+ print("Proxy 1:", agent.rotate_proxy())
565
+ print("Proxy 2:", agent.rotate_proxy())
566
+
567
+ # Test blacklist/whitelist
568
+ agent.add_to_blacklist("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36")
569
+ agent.add_to_whitelist("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
570
+ print("Blacklisted:", agent.random())
571
+ print("Whitelisted:", agent.random())
572
+
573
+ # Test agent history
574
+ for _ in range(55):
575
+ agent.random()
576
+ print("History:", agent.get_history())
577
+
578
+ # Test agent validation
579
+ print("Valid agent:", agent.validate_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"))
580
+ print("Invalid agent:", agent.validate_agent("InvalidUserAgentString"))
581
+ ip = agent.rotate_ip()
582
582
  print(ip) # 192.168.1.10 (example)