|
1 | 1 | # Python-TLS-Client-Async |
2 | 2 |
|
3 | 3 | [](https://pypi.org/project/async_tls_client/) |
| 4 | +[](https://pypi.org/project/async_tls_client/) |
| 5 | +[](https://opensource.org/licenses/MIT) |
4 | 6 |
|
5 | | -> Asyncio fork of [Florian Zager's Python-TLS-Client](https://github.com/FlorianREGAZ/Python-Tls-Client) |
6 | | -> with updated dependencies and modern Python support. |
| 7 | +Asyncio-first TLS client for Python with advanced fingerprinting capabilities. Modern fork of [Python-TLS-Client](https://github.com/FlorianREGAZ/Python-Tls-Client) with enhanced features and active maintenance. |
7 | 8 |
|
8 | | -Python-TLS-Client-Async is a fork of [Python-TLS-Client](https://github.com/FlorianREGAZ/Python-Tls-Client) with added |
9 | | -support for asyncio. This library allows you to perform advanced HTTP requests while maintaining compatibility with |
10 | | -asynchronous programming patterns in Python. |
11 | | - |
12 | | -The fork was created due to the lack of updates in the original repository, while the underlying GoLang |
13 | | -library [tls-client](https://github.com/bogdanfinn/tls-client) continues to evolve actively. This project aims to keep |
14 | | -up with the latest developments in the GoLang library and provide a modern, asynchronous interface for Python users. |
| 9 | +```python |
| 10 | +from async_tls_client import AsyncClient |
| 11 | +import asyncio |
15 | 12 |
|
16 | | -# Installation |
| 13 | +async def main(): |
| 14 | + async with AsyncClient( |
| 15 | + client_identifier="chrome120", |
| 16 | + random_tls_extension_order=True |
| 17 | + ) as client: |
| 18 | + response = await client.get("https://tls.peet.ws/api/all") |
| 19 | + print(f"Detected TLS fingerprint: {response.json()['tls']['ja3_hash']}") |
17 | 20 |
|
18 | | -```bash |
19 | | -pip install async_tls_client |
| 21 | +asyncio.run(main()) |
20 | 22 | ``` |
21 | 23 |
|
22 | | -# Features |
23 | | - |
24 | | -- Asyncio-based API for making HTTP requests. |
25 | | -- Inspired by the syntax of [requests](https://github.com/psf/requests), making it familiar and easy to use. |
26 | | -- Supports advanced TLS configurations like JA3, HTTP/2 settings, and more. |
27 | | - |
28 | | -# Asynchronous Design |
| 24 | +## Features ✨ |
29 | 25 |
|
30 | | -The project achieves asynchronicity by leveraging Python's `asyncio` framework. Here’s how it works: |
| 26 | +- **Full Async Support**: Built with asyncio for high-performance concurrent requests |
| 27 | +- **Modern TLS Fingerprinting**: JA3, JA4, HTTP/2 fingerprints and TLS 1.3 support |
| 28 | +- **Client Profiles**: 50+ preconfigured clients (Chrome, Firefox, Safari, iOS, Android) |
| 29 | +- **Advanced Configuration**: |
| 30 | + - Custom TLS cipher suites & extensions |
| 31 | + - HTTP/2 and QUIC protocol support |
| 32 | + - Certificate pinning and compression |
| 33 | + - Proxy support (HTTP/S, SOCKS4/5) |
| 34 | +- **Auto-Cookie Management**: Session persistence with configurable cookie jars |
| 35 | +- **Request Manipulation**: Header ordering, pseudo-header customization, and priority control |
31 | 36 |
|
32 | | -1. **Thread Offloading for Blocking Operations:** |
33 | | - Since the underlying `tls-client` library is implemented in Go and provides a blocking API, the project uses |
34 | | - `asyncio.to_thread` to offload these blocking operations to separate threads. This allows the Python event loop to |
35 | | - remain non-blocking while interacting with the synchronous Go library. |
| 37 | +## Why This Fork? 🚀 |
36 | 38 |
|
37 | | -2. **Custom Async Session Class:** |
38 | | - The `AsyncSession` class wraps synchronous operations in asynchronous methods. For example, requests are executed in |
39 | | - threads to ensure compatibility with asyncio, while responses are processed asynchronously. |
| 39 | +This project was created to address the lack of updates in the original Python-TLS-Client while incorporating: |
| 40 | +- Modern Python 3.9+ features and async/await syntax |
| 41 | +- Active updates from the underlying [tls-client](https://github.com/bogdanfinn/tls-client) Go library |
| 42 | +- Improved error handling and debugging capabilities |
| 43 | +- Better documentation and developer experience |
| 44 | +- Enhanced security features for enterprise use cases |
40 | 45 |
|
41 | | -3. **Async Context Management:** |
42 | | - The session supports asynchronous context management using `async with`, ensuring proper cleanup of resources like |
43 | | - sessions and memory allocations when the session is closed. |
| 46 | +## Installation 📦 |
44 | 47 |
|
45 | | -4. **Seamless Integration with Asyncio:** |
46 | | - By providing async versions of common HTTP methods (`get`, `post`, `put`, etc.), the library integrates smoothly into |
47 | | - existing asyncio-based workflows. |
48 | | - |
49 | | -# Examples |
| 48 | +```bash |
| 49 | +pip install async_tls_client |
| 50 | +``` |
50 | 51 |
|
51 | | -The syntax is similar to the original Python-TLS-Client library but adapted for asynchronous workflows. |
| 52 | +## Quickstart 🚀 |
52 | 53 |
|
53 | | -## Example 1 - Preset |
| 54 | +### Basic Usage |
54 | 55 |
|
55 | 56 | ```python |
56 | | -import async_tls_client |
| 57 | +from async_tls_client import AsyncClient |
57 | 58 | import asyncio |
58 | 59 |
|
59 | | - |
60 | | -# Example of client identifiers: |
61 | | -# Chrome --> chrome_103, chrome_104, chrome_105, chrome_106, chrome_107, chrome_108, chrome109, chrome110, |
62 | | -# chrome111, chrome112, chrome_116_PSK, chrome_116_PSK_PQ, chrome_117, chrome_120 |
63 | | -# Firefox --> firefox_102, firefox_104, firefox108, Firefox110, firefox_117, firefox_120 |
64 | | -# Opera --> opera_89, opera_90 |
65 | | -# Safari --> safari_15_3, safari_15_6_1, safari_16_0 |
66 | | -# iOS --> safari_ios_15_5, safari_ios_15_6, safari_ios_16_0 |
67 | | -# iPadOS --> safari_ios_15_6 |
68 | | -# Android --> okhttp4_android_7, okhttp4_android_8, okhttp4_android_9, okhttp4_android_10, okhttp4_android_11, |
69 | | -# okhttp4_android_12, okhttp4_android_13 |
70 | | - |
71 | 60 | async def main(): |
72 | | - session = async_tls_client.AsyncSession( |
73 | | - client_identifier="chrome112", |
74 | | - random_tls_extension_order=True |
75 | | - ) |
76 | | - |
77 | | - response = await session.get( |
78 | | - "https://www.example.com/", |
79 | | - headers={"key1": "value1"}, |
80 | | - proxy="http://user:password@host:port" |
81 | | - ) |
82 | | - |
83 | | - print(response.text) |
84 | | - await session.close() |
85 | | - |
| 61 | + async with AsyncClient("chrome120") as client: |
| 62 | + response = await client.get( |
| 63 | + "https://httpbin.org/json", |
| 64 | + headers={"X-API-Key": "secret"}, |
| 65 | + proxy="http://user:pass@proxy:port" |
| 66 | + ) |
| 67 | + print(f"Status: {response.status_code}") |
| 68 | + print(f"Headers: {response.headers}") |
| 69 | + print(f"JSON: {response.json()}") |
86 | 70 |
|
87 | 71 | asyncio.run(main()) |
88 | 72 | ``` |
89 | 73 |
|
90 | | -## Example 2 - Custom |
| 74 | +### Advanced Configuration |
91 | 75 |
|
92 | 76 | ```python |
93 | | -import async_tls_client |
94 | | -import asyncio |
| 77 | +from async_tls_client import AsyncClient |
| 78 | + |
| 79 | +client = AsyncClient( |
| 80 | + ja3_string="771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513,29-23-24,0", |
| 81 | + h2_settings={ |
| 82 | + "HEADER_TABLE_SIZE": 65536, |
| 83 | + "MAX_CONCURRENT_STREAMS": 1000, |
| 84 | + "INITIAL_WINDOW_SIZE": 6291456, |
| 85 | + "MAX_HEADER_LIST_SIZE": 262144 |
| 86 | + }, |
| 87 | + supported_signature_algorithms=[ |
| 88 | + "ECDSAWithP256AndSHA256", |
| 89 | + "PSSWithSHA256", |
| 90 | + "PKCS1WithSHA256", |
| 91 | + "ECDSAWithP384AndSHA384", |
| 92 | + "PSSWithSHA384", |
| 93 | + "PKCS1WithSHA512", |
| 94 | + ], |
| 95 | + certificate_pinning={ |
| 96 | + "example.com": [ |
| 97 | + "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" |
| 98 | + ] |
| 99 | + } |
| 100 | +) |
| 101 | +``` |
95 | 102 |
|
| 103 | +## Client Profiles 🕶️ |
96 | 104 |
|
97 | | -async def main(): |
98 | | - session = async_tls_client.AsyncSession( |
99 | | - ja3_string="771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513,29-23-24,0", |
100 | | - h2_settings={ |
101 | | - "HEADER_TABLE_SIZE": 65536, |
102 | | - "MAX_CONCURRENT_STREAMS": 1000, |
103 | | - "INITIAL_WINDOW_SIZE": 6291456, |
104 | | - "MAX_HEADER_LIST_SIZE": 262144 |
105 | | - }, |
106 | | - h2_settings_order=[ |
107 | | - "HEADER_TABLE_SIZE", |
108 | | - "MAX_CONCURRENT_STREAMS", |
109 | | - "INITIAL_WINDOW_SIZE", |
110 | | - "MAX_HEADER_LIST_SIZE" |
111 | | - ], |
112 | | - supported_signature_algorithms=[ |
113 | | - "ECDSAWithP256AndSHA256", |
114 | | - "PSSWithSHA256", |
115 | | - "PKCS1WithSHA256", |
116 | | - "ECDSAWithP384AndSHA384", |
117 | | - "PSSWithSHA384", |
118 | | - "PKCS1WithSHA384", |
119 | | - "PSSWithSHA512", |
120 | | - "PKCS1WithSHA512", |
121 | | - ], |
122 | | - supported_versions=["GREASE", "1.3", "1.2"], |
123 | | - key_share_curves=["GREASE", "X25519"], |
124 | | - cert_compression_algo="brotli", |
125 | | - pseudo_header_order=[ |
126 | | - ":method", |
127 | | - ":authority", |
128 | | - ":scheme", |
129 | | - ":path" |
130 | | - ], |
131 | | - connection_flow=15663105, |
132 | | - header_order=[ |
133 | | - "accept", |
134 | | - "user-agent", |
135 | | - "accept-encoding", |
136 | | - "accept-language" |
137 | | - ] |
138 | | - ) |
| 105 | +Preconfigured client identifiers (https://github.com/bogdanfinn/tls-client/blob/master/profiles/profiles.go): |
139 | 106 |
|
140 | | - response = await session.post( |
141 | | - "https://www.example.com/", |
142 | | - headers={"key1": "value1"}, |
143 | | - json={"key1": "key2"} |
144 | | - ) |
| 107 | +| Browser/Framework | Available Profiles | |
| 108 | +|-------------------------|------------------------------------------------------------------------------------| |
| 109 | +| Chrome | chrome_103 - chrome_133 (including PSK variants: 116_PSK, 116_PSK_PQ, 131_PSK, 133_PSK) | |
| 110 | +| Firefox | firefox_102 - firefox_135 | |
| 111 | +| Safari (Desktop) | safari_15_6_1, safari_16_0, safari_ipad_15_6 | |
| 112 | +| Safari (iOS) | safari_ios_15_5 - safari_ios_18_0 | |
| 113 | +| Opera | opera_89 - opera_91 | |
| 114 | +| Android (OkHttp) | okhttp4_android_7 - okhttp4_android_13 | |
| 115 | +| iOS (Custom) | mms_ios (v1, v2, v3), mesh_ios (v1, v2), confirmed_ios, zalando_ios_mobile, nike_ios_mobile | |
| 116 | +| Android (Custom) | mesh_android (v1, v2), confirmed_android, zalando_android_mobile, nike_android_mobile | |
| 117 | +| Cloudflare | cloudscraper | |
145 | 118 |
|
146 | | - print(response.text) |
147 | | - await session.close() |
| 119 | +## Advanced Features 🔧 |
148 | 120 |
|
| 121 | +### Custom Fingerprint Configuration |
149 | 122 |
|
150 | | -asyncio.run(main()) |
| 123 | +```python |
| 124 | +client = AsyncClient( |
| 125 | + ja3_string="771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513,29-23-24,0", |
| 126 | + h2_settings_order=["HEADER_TABLE_SIZE", "MAX_CONCURRENT_STREAMS"], |
| 127 | + pseudo_header_order=[":method", ":authority", ":scheme", ":path"], |
| 128 | + header_order=["accept", "user-agent", "accept-encoding"], |
| 129 | + force_http1=False, |
| 130 | + cert_compression_algo="brotli" |
| 131 | +) |
151 | 132 | ``` |
152 | 133 |
|
153 | | -# PyInstaller / PyArmor |
| 134 | +### Certificate Pinning |
154 | 135 |
|
155 | | -If you want to package the library with PyInstaller or PyArmor, make sure to include the necessary dependencies: |
| 136 | +```python |
| 137 | +client = AsyncClient( |
| 138 | + certificate_pinning={ |
| 139 | + "api.bank.com": [ |
| 140 | + "sha256/7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=", |
| 141 | + "sha256/YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg=" |
| 142 | + ] |
| 143 | + } |
| 144 | +) |
| 145 | +``` |
156 | 146 |
|
157 | | -## Linux - Ubuntu / x86 |
| 147 | +### Proxy Support |
158 | 148 |
|
159 | | -```bash |
160 | | ---add-binary '{path_to_library}/async_tls_client/dependencies/tls-client-x86.so:async_tls_client/dependencies' |
| 149 | +```python |
| 150 | +response = await client.get( |
| 151 | + "https://api.example.com", |
| 152 | + proxy="socks5://user:pass@proxy:1080" |
| 153 | +) |
161 | 154 | ``` |
162 | 155 |
|
163 | | -## Linux Alpine / AMD64 |
| 156 | +## Asynchronous Design 🚧 |
164 | 157 |
|
165 | | -```bash |
166 | | ---add-binary '{path_to_library}/async_tls_client/dependencies/tls-client-amd64.so:async_tls_client/dependencies' |
167 | | -``` |
| 158 | +The client leverages Python's asyncio through three key strategies: |
168 | 159 |
|
169 | | -## MacOS M1 and older |
| 160 | +1. **Non-blocking I/O** |
| 161 | + - Network operations run in separate threads using `asyncio.to_thread` |
| 162 | + - Go TLS client handles remain managed in background executors |
170 | 163 |
|
171 | | -```bash |
172 | | ---add-binary '{path_to_library}/async_tls_client/dependencies/tls-client-x86.dylib:async_tls_client/dependencies' |
173 | | -``` |
| 164 | +2. **Session Management** |
| 165 | + - `AsyncClient` context manager handles automatic cleanup |
| 166 | + - Connection pooling with automatic keep-alives |
| 167 | + - Cookie persistence across requests |
| 168 | + |
| 169 | +3. **Resource Optimization** |
| 170 | + - Zero-copy body handling for large responses |
| 171 | + - Lazy initialization of heavy resources |
| 172 | + - Automatic memory cleanup of Go pointers |
| 173 | + |
| 174 | +## Packaging 📦 |
174 | 175 |
|
175 | | -## MacOS M2 |
| 176 | +When using PyInstaller/PyArmor, include the shared library: |
176 | 177 |
|
| 178 | +### Windows |
177 | 179 | ```bash |
178 | | ---add-binary '{path_to_library}/async_tls_client/dependencies/tls-client-arm64.dylib:async_tls_client/dependencies' |
| 180 | +--add-binary 'async_tls_client/dependencies/tls-client-64.dll;async_tls_client/dependencies' |
179 | 181 | ``` |
180 | 182 |
|
181 | | -## Windows |
| 183 | +### Linux |
| 184 | +```bash |
| 185 | +--add-binary 'async_tls_client/dependencies/tls-client-x86.so:async_tls_client/dependencies' |
| 186 | +``` |
182 | 187 |
|
| 188 | +### macOS |
183 | 189 | ```bash |
184 | | ---add-binary '{path_to_library}/async_tls_client/dependencies/tls-client-64.dll;async_tls_client/dependencies' |
| 190 | +--add-binary 'async_tls_client/dependencies/tls-client-arm64.dylib:async_tls_client/dependencies' |
185 | 191 | ``` |
186 | 192 |
|
187 | | -# Acknowledgements |
| 193 | +## Acknowledgements 🙏 |
188 | 194 |
|
189 | | -This project is a fork of [Python-TLS-Client](https://github.com/FlorianREGAZ/Python-Tls-Client), with significant |
190 | | -contributions to support asyncio. The original library is based |
191 | | -on [tls-client](https://github.com/bogdanfinn/tls-client) by [Bogdanfinn](https://github.com/bogdanfinn). |
| 195 | +- Original Python implementation: [FlorianREGAZ/Python-Tls-Client](https://github.com/FlorianREGAZ/Python-Tls-Client) |
| 196 | +- Core TLS implementation: [bogdanfinn/tls-client](https://github.com/bogdanfinn/tls-client) |
| 197 | +- Inspiration: [psf/requests](https://github.com/psf/requests) |
192 | 198 |
|
193 | | -The syntax aims to remain close to [requests](https://github.com/psf/requests) to ensure ease of use and familiarity for |
194 | | -Python developers. |
| 199 | +## License 📄 |
195 | 200 |
|
| 201 | +MIT License - See [LICENSE](LICENSE) for details |
0 commit comments