Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Header generation #4

Merged
merged 5 commits into from
Mar 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()
Loading