-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathllms-full.txt
More file actions
562 lines (407 loc) · 16 KB
/
Copy pathllms-full.txt
File metadata and controls
562 lines (407 loc) · 16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
# CycleTLS Python - Complete API Documentation
> Python HTTP client that impersonates real browsers - bypass anti-bot detection with TLS/JA3/JA4/HTTP2 fingerprinting. Unlike requests or httpx, CycleTLS makes your requests indistinguishable from real browser traffic.
CycleTLS is a high-performance Python HTTP client built on a Go backend, providing advanced TLS fingerprinting capabilities. Use it for web scraping, API access, and bypassing bot detection systems that rely on TLS fingerprinting (Cloudflare, Akamai, etc.).
## Installation
```bash
pip install cycletls
```
Or with uv:
```bash
uv add cycletls
```
Requirements: Python >=3.8
---
## Quick Start
### Simple API (Zero Boilerplate)
```python
import cycletls
# Basic GET request
response = cycletls.get('https://httpbin.org/get')
print(response.status_code) # 200
print(response.json())
# POST with JSON
response = cycletls.post('https://httpbin.org/post', json_data={'key': 'value'})
# With TLS fingerprinting
response = cycletls.get(
'https://ja3er.com/json',
ja3='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',
user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
)
```
### Context Manager Pattern
```python
from cycletls import CycleTLS
with CycleTLS() as client:
response = client.get('https://httpbin.org/get')
print(response.json())
```
### Async Pattern
```python
import asyncio
import cycletls
async def main():
response = await cycletls.aget('https://httpbin.org/get')
print(response.json())
asyncio.run(main())
```
---
## Module-Level Functions
All HTTP methods available as module-level functions:
### Synchronous Functions
```python
import cycletls
cycletls.get(url, **kwargs) -> Response
cycletls.post(url, data=None, json_data=None, **kwargs) -> Response
cycletls.put(url, data=None, json_data=None, **kwargs) -> Response
cycletls.patch(url, data=None, json_data=None, **kwargs) -> Response
cycletls.delete(url, **kwargs) -> Response
cycletls.head(url, **kwargs) -> Response
cycletls.options(url, **kwargs) -> Response
cycletls.request(method, url, **kwargs) -> Response
```
### Async Functions
```python
import cycletls
await cycletls.aget(url, **kwargs) -> Response
await cycletls.apost(url, data=None, json_data=None, **kwargs) -> Response
await cycletls.aput(url, data=None, json_data=None, **kwargs) -> Response
await cycletls.apatch(url, data=None, json_data=None, **kwargs) -> Response
await cycletls.adelete(url, **kwargs) -> Response
await cycletls.ahead(url, **kwargs) -> Response
await cycletls.aoptions(url, **kwargs) -> Response
await cycletls.async_request(method, url, **kwargs) -> Response
```
### Configuration Functions
```python
# Set default values for all requests
cycletls.set_default(
proxy='socks5://127.0.0.1:9050',
timeout=10,
ja3='771,4865-4866-4867...',
user_agent='Mozilla/5.0...',
enable_connection_reuse=True
)
# Get a default value
value = cycletls.get_default('timeout')
# Reset all defaults
cycletls.reset_defaults()
# Manually close global session
cycletls.close_global_session()
```
---
## Request Parameters
All parameters available for any request method:
### URL and Method Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `url` | str | Required | Target URL |
| `method` | str | GET | HTTP method: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS |
| `params` | dict | None | Query parameters to append to URL |
### Body Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `data` | dict/str/bytes | None | Request body (form data or raw) |
| `json_data` | dict | None | JSON request body (auto-serialized with Content-Type header) |
| `body_bytes` | bytes | None | Raw binary body |
| `files` | dict | None | File uploads (not yet implemented) |
### Header Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `headers` | dict | None | Custom HTTP headers |
| `user_agent` | str | None | User-Agent header (convenience parameter) |
| `header_order` | list[str] | None | Custom header ordering (e.g., ['accept', 'user-agent']) |
| `order_headers_as_provided` | bool | False | Use provided header order exactly |
### Cookie Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `cookies` | dict/list/CookieJar | None | Cookies to send with request |
### TLS Fingerprinting Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `ja3` | str | None | JA3 fingerprint string (format: TLSVersion,Ciphers,Extensions,EllipticCurves,ECPointFormats) |
| `ja4r` | str | None | JA4R raw format fingerprint (advanced TLS control) |
| `http2_fingerprint` | str | None | HTTP/2 Akamai fingerprint (format: settings\|window_update\|priority\|pseudo_header_order) |
| `quic_fingerprint` | str | None | QUIC fingerprint string |
| `disable_grease` | bool | False | Disable GREASE for exact JA4 matching |
### TLS Configuration Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `server_name` | str | None | Custom SNI (Server Name Indication) for domain fronting |
| `insecure_skip_verify` | bool | False | Skip TLS certificate verification |
| `tls13_auto_retry` | bool | False | Auto-retry with TLS 1.3 compatible curves |
### Protocol Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `force_http1` | bool | False | Force HTTP/1.1 protocol |
| `force_http3` | bool | False | Force HTTP/3 (QUIC) protocol |
| `protocol` | str | None | Explicit protocol: 'http1', 'http2', 'http3', 'websocket', 'sse' |
### Connection Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `proxy` | str | None | Proxy URL (http://, https://, socks4://, socks5://, socks5h://) |
| `timeout` | int | 6 | Request timeout in seconds |
| `disable_redirect` | bool | False | Disable automatic redirect following |
| `enable_connection_reuse` | bool | False | Enable connection pooling for subsequent requests |
### Async-Specific Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `timeout` | float | 30.0 | Maximum time to wait for request completion (seconds) |
| `poll_interval` | float | 0.0 | Polling interval (0.0 = adaptive: tight loop → 100μs → 1ms) |
---
## Response Object
Properties and methods available on Response objects:
### Status Properties
| Property | Type | Description |
|----------|------|-------------|
| `status_code` | int | HTTP status code (200, 404, etc.) |
| `ok` | bool | True if 200 <= status_code < 400 |
| `is_redirect` | bool | True if 300 <= status_code < 400 |
| `is_error` | bool | True if status_code >= 400 |
| `is_client_error` | bool | True if 400 <= status_code < 500 |
| `is_server_error` | bool | True if 500 <= status_code < 600 |
| `reason` | str | HTTP reason phrase ("OK", "Not Found", etc.) |
### Content Properties
| Property | Type | Description |
|----------|------|-------------|
| `text` | str | Response body as decoded string |
| `body` | str | Alias for text |
| `content` | bytes | Response body as raw bytes |
| `encoding` | str | Character encoding (auto-detected from headers) |
| `url` | str | Final URL after redirects |
### Header and Cookie Properties
| Property | Type | Description |
|----------|------|-------------|
| `headers` | CaseInsensitiveDict | Response headers (case-insensitive access) |
| `cookies` | CookieJar | Response cookies |
### Methods
```python
response.json() -> dict
"""Parse response body as JSON. Raises ValueError if not valid JSON."""
response.raise_for_status() -> None
"""Raise HTTPError if status_code >= 400."""
```
---
## CycleTLS Class
Main synchronous client class.
```python
from cycletls import CycleTLS
class CycleTLS:
def __init__(self, port: int = None):
"""
Initialize CycleTLS client.
Args:
port: Optional port for Go backend (auto-assigned if None)
"""
def request(self, method: str, url: str, **kwargs) -> Response:
"""Send an HTTP request with any method."""
def get(self, url: str, params: dict = None, **kwargs) -> Response:
"""Send a GET request."""
def post(self, url: str, data=None, json_data=None, **kwargs) -> Response:
"""Send a POST request."""
def put(self, url: str, data=None, json_data=None, **kwargs) -> Response:
"""Send a PUT request."""
def patch(self, url: str, data=None, json_data=None, **kwargs) -> Response:
"""Send a PATCH request."""
def delete(self, url: str, **kwargs) -> Response:
"""Send a DELETE request."""
def head(self, url: str, **kwargs) -> Response:
"""Send a HEAD request."""
def options(self, url: str, **kwargs) -> Response:
"""Send an OPTIONS request."""
def batch(self, requests: list[dict]) -> list[Response]:
"""
Send multiple requests in a batch.
Args:
requests: List of request dicts with 'url', 'method', and optional params
Returns:
List of Response objects
"""
def close(self) -> None:
"""Close the client and cleanup resources."""
def __enter__(self) -> CycleTLS:
"""Context manager entry."""
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
"""Context manager exit with automatic cleanup."""
```
---
## AsyncCycleTLS Class
Async client for concurrent requests.
```python
from cycletls import AsyncCycleTLS
class AsyncCycleTLS:
def __init__(self, port: int = None):
"""Initialize async CycleTLS client."""
async def request(self, method: str, url: str, poll_interval: float = 0.0,
timeout: float = 30.0, **kwargs) -> Response:
"""Send an async HTTP request."""
async def get(self, url: str, **kwargs) -> Response:
"""Send an async GET request."""
async def post(self, url: str, data=None, json_data=None, **kwargs) -> Response:
"""Send an async POST request."""
async def put(self, url: str, **kwargs) -> Response:
"""Send an async PUT request."""
async def patch(self, url: str, **kwargs) -> Response:
"""Send an async PATCH request."""
async def delete(self, url: str, **kwargs) -> Response:
"""Send an async DELETE request."""
async def head(self, url: str, **kwargs) -> Response:
"""Send an async HEAD request."""
async def options(self, url: str, **kwargs) -> Response:
"""Send an async OPTIONS request."""
async def close(self) -> None:
"""Close the async client."""
async def __aenter__(self) -> AsyncCycleTLS:
"""Async context manager entry."""
async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
"""Async context manager exit."""
```
---
## Session Class
Session with persistent cookies and headers.
```python
from cycletls import Session
class Session(CycleTLS):
cookies: CookieJar # Persistent cookie jar
headers: CaseInsensitiveDict # Persistent headers
def __init__(self):
"""Initialize a Session with persistent cookies/headers."""
```
Usage:
```python
with Session() as session:
session.headers['Authorization'] = 'Bearer token123'
# Login - cookies automatically saved
session.post('https://example.com/login', json_data={'user': 'admin'})
# Subsequent requests include cookies automatically
profile = session.get('https://example.com/profile')
```
---
## Cookie Class
For advanced cookie configuration.
```python
from cycletls import Cookie
class Cookie:
name: str
value: str
path: str = None
domain: str = None
expires: datetime = None
max_age: int = None
secure: bool = False
http_only: bool = False
same_site: str = None # "Strict", "Lax", or "None"
```
---
## Exceptions
```python
from cycletls import (
CycleTLSError, # Base exception
RequestException, # Base for request errors
HTTPError, # HTTP error (4xx, 5xx) - has .response attribute
ConnectionError, # Connection failed
Timeout, # Request timeout
ConnectTimeout, # Connection timeout
ReadTimeout, # Read timeout
TooManyRedirects, # Exceeded redirect limit
InvalidURL, # Malformed URL
TLSError, # TLS handshake error
ProxyError, # Proxy connection error
InvalidHeader, # Invalid header value
)
```
---
## JA3 Fingerprinting
JA3 format: `TLSVersion,Ciphers,Extensions,EllipticCurves,ECPointFormats`
Example Chrome 83:
```
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
```
Components:
- `771` = TLS 1.2
- `4865-4866-4867...` = Cipher suites
- `0-23-65281...` = TLS extensions
- `29-23-24` = Elliptic curves
- `0` = EC point formats
Common browser fingerprints:
```python
BROWSER_FINGERPRINTS = {
'chrome_83': {
'ja3': '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',
'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36'
},
'firefox_87': {
'ja3': '771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-51-57-47-53-10,0-23-65281-10-11-35-16-5-51-43-13-45-28-21,29-23-24-25-256-257,0',
'user_agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0'
},
'safari_15': {
'ja3': '771,4865-4867-4866-49196-49195-52393-49200-49199-52392-49162-49161-49172-49171-157-156-53-47-49160-49170-10,0-23-65281-10-11-35-16-5-13-45-28-21,29-23-24-25,0',
'user_agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15'
}
}
```
---
## HTTP/2 Fingerprinting
HTTP/2 Akamai fingerprint format: `settings|window_update|priority|pseudo_header_order`
Example Firefox:
```
1:65536;2:0;4:131072;5:16384|12517377|0|m,p,a,s
```
Components:
- `1:65536` = HEADER_TABLE_SIZE
- `2:0` = ENABLE_PUSH
- `4:131072` = MAX_CONCURRENT_STREAMS
- `5:16384` = INITIAL_WINDOW_SIZE
- `12517377` = Window update value
- `0` = Priority (0 = no priority frame)
- `m,p,a,s` = Pseudo-header order (method, path, authority, scheme)
---
## Proxy Configuration
Supported proxy protocols:
```python
# HTTP proxy
response = cycletls.get(url, proxy='http://host:port')
# HTTP proxy with auth
response = cycletls.get(url, proxy='http://user:pass@host:port')
# HTTPS proxy
response = cycletls.get(url, proxy='https://host:port')
# SOCKS4 proxy
response = cycletls.get(url, proxy='socks4://host:port')
# SOCKS5 proxy
response = cycletls.get(url, proxy='socks5://host:port')
# SOCKS5 with hostname resolution through proxy
response = cycletls.get(url, proxy='socks5h://host:port')
```
---
## Concurrent Requests Example
```python
import asyncio
import cycletls
async def main():
# Make 10 requests concurrently
responses = await asyncio.gather(*[
cycletls.aget(f'https://httpbin.org/get?id={i}')
for i in range(10)
])
print(f"Completed {len(responses)} requests")
print(f"All successful: {all(r.status_code == 200 for r in responses)}")
asyncio.run(main())
```
---
## Batch Requests
```python
from cycletls import CycleTLS
with CycleTLS() as client:
requests = [
{"url": "https://httpbin.org/get", "method": "GET"},
{"url": "https://httpbin.org/post", "method": "POST", "json_data": {"key": "value"}},
{"url": "https://httpbin.org/headers", "method": "GET"},
]
responses = client.batch(requests)
for response in responses:
print(response.status_code)
```
---
## Source Code
- GitHub: https://github.com/Danny-Dasilva/cycletls_python
- PyPI: https://pypi.org/project/cycletls/
- Examples: https://github.com/Danny-Dasilva/cycletls_python/tree/main/examples