Skip to content

Commit

Permalink
Merge pull request #4 from iamdual/headers
Browse files Browse the repository at this point in the history
Header generation
  • Loading branch information
iamdual authored Mar 9, 2024
2 parents 9041aff + a67f8df commit 9d63661
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 14 deletions.
61 changes: 52 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,30 @@ print(ua) # Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/604.1.38
```

# Customization
There are three different parameters to the generate user-agent by the certain conditions.
**There are three different parameters to the generate user-agent by the certain conditions.**

```python
device = ('desktop', 'mobile')
platform = ('windows', 'macos', 'ios', 'linux', 'android')
browser = ('chrome', 'edge', 'firefox', 'safari')
```
All of the parameters are optional, and the types can be set multiple times by using a tuple.*

All of the parameters are optional, and the types can be choose multiple.
## Customized user-agent generation:
```python
import ua_generator

ua = ua_generator.generate(device='desktop', browser='firefox')
print(ua.text) # Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0.1) Gecko/20100101 Firefox/121.0.1
print(ua.platform) # macos
print(ua.browser) # firefox
print(ua.ch.brands) # "Not A(Brand";v="99"
# Example 1:
ua = ua_generator.generate(device='desktop', browser=('chrome', 'edge'))
print(ua.text) # Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.145 Safari/537.36
print(ua.platform) # windows
print(ua.browser) # chrome
print(ua.ch.brands) # "Not A(Brand";v="99", "Chromium";v="108", "Google Chrome";v="108"
print(ua.ch.mobile) # ?0
print(ua.ch.platform) # "macOS"
print(ua.ch.platform_version) # "14.0.1"
print(ua.ch.platform) # "Windows"
print(ua.ch.platform_version) # "10.0"

# Example 2:
ua = ua_generator.generate(platform=('ios', 'macos'), browser='chrome')
print(ua.text) # Mozilla/5.0 (iPhone; CPU iPhone OS 17_0_2 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) CriOS/119.0.6045.176 Mobile/15E148 Safari/537.36
print(ua.platform) # ios
Expand All @@ -53,5 +57,44 @@ print(ua.ch.platform) # "iOS"
print(ua.ch.platform_version) # "17.0.2"
```

# Headers
```python
ua = ua_generator.generate(browser=('chrome', 'edge'))

# This will return a dictionary containing the generated user-agent:
print(ua.headers.get())
{
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.43 Safari/537.36',
'sec-ch-ua': '"Not A(Brand";v="99", "Chromium";v="103", "Google Chrome";v="103"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"macOS"'
}

# Extending the "Client Hints" by a value of the "Accept-CH" header:
print(ua.headers.accept_ch('Sec-CH-UA-Platform-Version, Sec-CH-UA-Full-Version-List'))
print(ua.headers.get())
{
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.94 Safari/537.36',
'sec-ch-ua': '"Not A(Brand";v="99", "Chromium";v="122", "Google Chrome";v="122"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"macOS"',
'sec-ch-ua-platform-version': '"14.1.0"',
'sec-ch-ua-full-version-list': '"Not A(Brand";v="99", "Chromium";v="122.0.6261.94", "Google Chrome";v="122.0.6261.94"'
}
```

## Integrating into the [requests](https://pypi.org/project/requests/):
```python
import requests
import ua_generator

ua = ua_generator.generate(browser=('chrome', 'edge'))
r = requests.get("https://httpbin.org/get", headers=ua.headers.get())
print(r.text)
```

# Issues
You can create an issue [from here](https://github.com/iamdual/ua-generator/issues) if you are experiencing a problem.

# Author
Ekin Karadeniz (iamdual@icloud.com)
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = ua-generator
version = 0.2.1
version = 0.3.0
author = Ekin Karadeniz
author_email = iamdual@icloud.com
description = A random user-agent generator
Expand Down
47 changes: 47 additions & 0 deletions src/ua_generator/headers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""
Random User-Agent
Copyright: 2022-2024 Ekin Karadeniz (github.com/iamdual)
License: Apache License 2.0
"""
from .data.generator import Generator
from .client_hints import ClientHints


# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-CH
class Headers:

def __init__(self, gen: Generator, ch: ClientHints):
self.__generator = gen
self.__client_hints = ch
self.__headers = {
'user-agent': gen.user_agent,
}

# https://developer.mozilla.org/en-US/docs/Web/HTTP/Client_hints#low_entropy_hints
if self.__generator.browser in ('chrome', 'edge'):
self.add('sec-ch-ua')
self.add('sec-ch-ua-mobile')
self.add('sec-ch-ua-platform')

def add(self, key: str):
if key == 'sec-ch-ua':
self.__headers[key] = self.__client_hints.brands
elif key == 'sec-ch-ua-full-version-list':
self.__headers[key] = self.__client_hints.brands_full_version_list
if key == 'sec-ch-ua-platform':
self.__headers[key] = self.__client_hints.platform
elif key == 'sec-ch-ua-platform-version':
self.__headers[key] = self.__client_hints.platform_version
elif key == 'sec-ch-ua-mobile':
self.__headers[key] = self.__client_hints.mobile

def accept_ch(self, val: str):
if self.__generator.browser not in ('chrome', 'edge'):
return

requested_hints = val.split(',')
for hint in requested_hints:
self.add(hint.strip().lower())

def get(self):
return self.__headers
9 changes: 5 additions & 4 deletions src/ua_generator/user_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
"""
from . import utils, exceptions
from .data import devices, platforms, platforms_desktop, platforms_mobile, browsers
from .data import generator
from .data.generator import Generator
from .client_hints import ClientHints
from .headers import Headers


class UserAgent:
Expand All @@ -18,9 +19,8 @@ def __init__(self, device=None, platform=None, browser=None):

# Type hinting only
self.text: str
self.platform_version: dict
self.browser_version: dict
self.ch: ClientHints
self.headers: Headers

def __find_device(self):
if self.device is not None:
Expand Down Expand Up @@ -77,9 +77,10 @@ def __complete(self):
self.platform = self.__find_platform()
self.browser = self.__find_browser()

ua = generator.Generator(device=self.device, platform=self.platform, browser=self.browser)
ua = Generator(device=self.device, platform=self.platform, browser=self.browser)
self.text = ua.user_agent
self.ch = ClientHints(ua)
self.headers = Headers(ua, self.ch)

def __str__(self):
return self.text
50 changes: 50 additions & 0 deletions tests/test_headers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""
Random User-Agent
Copyright: 2022 Ekin Karadeniz (github.com/iamdual)
License: Apache License 2.0
"""
import unittest

import src.ua_generator as ua_generator


class TestHeaders(unittest.TestCase):
def test_default(self):
for i in range(0, 100):
ua = ua_generator.generate()
self.assertIsNotNone(ua.headers)
self.assertTrue('user-agent' in ua.headers.get())

def test_client_hints(self):
for i in range(0, 100):
ua = ua_generator.generate(browser=('chrome', 'edge'))
self.assertIsNotNone(ua.headers)
self.assertTrue('sec-ch-ua' in ua.headers.get())
self.assertTrue('sec-ch-ua-mobile' in ua.headers.get())
self.assertTrue('sec-ch-ua-platform' in ua.headers.get())

def test_client_hints_not_exists(self):
for i in range(0, 100):
ua = ua_generator.generate(browser='firefox')
self.assertIsNotNone(ua.headers)
self.assertFalse('sec-ch-ua' in ua.headers.get())
self.assertFalse('sec-ch-ua-mobile' in ua.headers.get())
self.assertFalse('sec-ch-ua-platform' in ua.headers.get())

def test_accept_ch(self):
for i in range(0, 100):
ua = ua_generator.generate(browser=('chrome', 'edge'))
ua.headers.accept_ch('Sec-CH-UA-Platform-Version, Sec-CH-UA-Full-Version-List')
self.assertTrue('sec-ch-ua-platform-version' in ua.headers.get())
self.assertTrue('sec-ch-ua-full-version-list' in ua.headers.get())

def test_accept_ch_not_exists(self):
for i in range(0, 100):
ua = ua_generator.generate(browser=('chrome', 'edge'))
ua.headers.accept_ch('Sec-CH-Example')
self.assertFalse('sec-ch-ua-platform-version' in ua.headers.get())
self.assertFalse('sec-ch-ua-full-version-list' in ua.headers.get())


if __name__ == '__main__':
unittest.main()

0 comments on commit 9d63661

Please sign in to comment.