notify-tls-client 2.0.0__py3-none-any.whl → 2.0.2__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.
@@ -44,10 +44,15 @@ class RecoveryConfig:
44
44
  instantiate_new_client_on_forbidden_response: bool = False
45
45
  instantiate_new_client_on_exception: bool = False
46
46
  change_client_identifier_on_forbidden_response: bool = False
47
- status_codes_to_forbidden_response_handle: list[int] = field(default_factory=lambda: [403])
47
+ status_codes_to_forbidden_response_handle: tuple[int, ...] = field(default_factory=lambda: (403,))
48
48
 
49
49
  def __post_init__(self):
50
50
  """Valida os parâmetros de configuração."""
51
+ # Converter lista para tuple se necessário (compatibilidade)
52
+ if isinstance(self.status_codes_to_forbidden_response_handle, list):
53
+ object.__setattr__(self, 'status_codes_to_forbidden_response_handle',
54
+ tuple(self.status_codes_to_forbidden_response_handle))
55
+
51
56
  if not self.status_codes_to_forbidden_response_handle:
52
57
  raise ValueError("status_codes_to_forbidden_response_handle não pode ser vazio")
53
58
 
@@ -3,6 +3,8 @@ from datetime import datetime
3
3
  from typing import Optional
4
4
  from urllib.parse import urlparse
5
5
 
6
+ import orjson
7
+
6
8
  from notify_tls_client.tls_client.response import Response
7
9
 
8
10
  logger = logging.getLogger(__name__)
@@ -79,41 +81,65 @@ def _log_request_info(self,
79
81
  response: Optional[Response],
80
82
  request_url: Optional[str],
81
83
  request_headers: dict):
84
+ if not logger.isEnabledFor(logging.DEBUG):
85
+ return
86
+
82
87
  if response:
83
- logger.debug(f"""Request finished
84
- client_identifier={self.get_current_client_identifier()}
85
- request_url={request_url}
86
- request_headers={request_headers}
87
- response_url={response.url}
88
- status_code={response.status_code}
89
- response_time={response.elapsed}ms
90
- response_headers={dict(response.headers)}
91
- proxy={self.client.proxies['http'] if self.client.proxies else None}
92
- """,
88
+ proxy = self.client.proxies['http'] if self.client.proxies else None
89
+ client_id = self.get_current_client_identifier()
90
+ response_headers_dict = dict(response.headers)
91
+
92
+ # Serializar dados complexos com orjson (mais rápido)
93
+ try:
94
+ request_headers_json = orjson.dumps(request_headers).decode('utf-8')
95
+ response_headers_json = orjson.dumps(response_headers_dict).decode('utf-8')
96
+ except Exception:
97
+ request_headers_json = str(request_headers)
98
+ response_headers_json = str(response_headers_dict)
99
+
100
+ logger.debug("Request finished\n"
101
+ " client_identifier=%s\n"
102
+ " request_url=%s\n"
103
+ " request_headers=%s\n"
104
+ " response_url=%s\n"
105
+ " status_code=%s\n"
106
+ " response_time=%sms\n"
107
+ " response_headers=%s\n"
108
+ " proxy=%s",
109
+ client_id, request_url, request_headers_json, response.url,
110
+ response.status_code, response.elapsed, response_headers_json, proxy,
93
111
  extra={
94
112
  "date": datetime.now().strftime("%d-%m-%Y %H:%M:%S.%f")[:-3],
95
113
  "request_url": request_url,
96
114
  "request_headers": request_headers,
97
115
  "response_url": response.url,
98
116
  "status_code": response.status_code,
99
- "response_headers": dict(response.headers),
117
+ "response_headers": response_headers_dict,
100
118
  "response_elapsed_ms": response.elapsed,
101
- "proxy": self.client.proxies['http'] if self.client.proxies else None,
102
- "client_identifier": self.get_current_client_identifier()
103
-
119
+ "proxy": proxy,
120
+ "client_identifier": client_id
104
121
  })
105
122
 
106
123
  if not response:
107
- logger.debug(f"""Request failed before getting a response
108
- client_identifier={self.get_current_client_identifier()}
109
- request_url={request_url}
110
- request_headers={request_headers}
111
- response_url=None
112
- status_code=None
113
- response_headers=None
114
- response_time=0
115
- proxy={self.client.proxies['http'] if self.client.proxies else None}
116
- """,
124
+ proxy = self.client.proxies['http'] if self.client.proxies else None
125
+ client_id = self.get_current_client_identifier()
126
+
127
+ # Serializar request_headers com orjson
128
+ try:
129
+ request_headers_json = orjson.dumps(request_headers).decode('utf-8')
130
+ except Exception:
131
+ request_headers_json = str(request_headers)
132
+
133
+ logger.debug("Request failed before getting a response\n"
134
+ " client_identifier=%s\n"
135
+ " request_url=%s\n"
136
+ " request_headers=%s\n"
137
+ " response_url=None\n"
138
+ " status_code=None\n"
139
+ " response_headers=None\n"
140
+ " response_time=0\n"
141
+ " proxy=%s",
142
+ client_id, request_url, request_headers_json, proxy,
117
143
  extra={
118
144
  "date": datetime.now().strftime("%d-%m-%Y %H:%M:%S.%f")[:-3],
119
145
  "request_url": request_url,
@@ -122,9 +148,8 @@ def _log_request_info(self,
122
148
  "status_code": None,
123
149
  "response_headers": None,
124
150
  "response_elapsed_ms": 0,
125
- "proxy": self.client.proxies['http'] if self.client.proxies else None,
126
- "client_identifier": self.get_current_client_identifier()
127
-
151
+ "proxy": proxy,
152
+ "client_identifier": client_id
128
153
  })
129
154
 
130
155
 
@@ -7,12 +7,15 @@ from notify_tls_client.tls_client.settings import ClientIdentifiers
7
7
 
8
8
  @dataclass
9
9
  class ClientIdentifiersManager:
10
- _items: list[ClientIdentifiers] = field(default_factory=list)
10
+ _items: tuple[ClientIdentifiers, ...] = field(default_factory=tuple)
11
11
  _current_index: int = 0
12
12
  _current_item: Optional[ClientIdentifiers] = None
13
13
 
14
14
  def __post_init__(self):
15
15
  self._lock = threading.Lock()
16
+ # Converter lista para tuple se necessário
17
+ if isinstance(self._items, list):
18
+ object.__setattr__(self, '_items', tuple(self._items))
16
19
 
17
20
  def get_next(self) -> ClientIdentifiers:
18
21
  with self._lock:
@@ -26,19 +29,19 @@ class ClientIdentifiersManager:
26
29
  return _item
27
30
 
28
31
  def get_current_item(self) -> Optional[ClientIdentifiers]:
29
- with self._lock:
30
- return self._current_item
32
+ # Lock-free read - safe para strings imutáveis
33
+ return self._current_item
31
34
 
32
35
  def set_items(self, items: list[ClientIdentifiers]):
33
36
  with self._lock:
34
- self._items = items
37
+ self._items = tuple(items) if isinstance(items, list) else items
35
38
  self._current_index = 0
36
39
  self._current_item = None
37
40
 
38
- def get_item(self) -> list[ClientIdentifiers]:
39
- with self._lock:
40
- return self._items.copy()
41
+ def get_item(self) -> tuple[ClientIdentifiers, ...]:
42
+ # Lock-free read - tuple é imutável
43
+ return self._items
41
44
 
42
45
  def get_total_items(self) -> int:
43
- with self._lock:
44
- return len(self._items)
46
+ # Lock-free read - len é thread-safe para objetos imutáveis
47
+ return len(self._items)
@@ -143,34 +143,35 @@ class NotifyTLSClient:
143
143
  random_tls_extension_order: bool = False,
144
144
  proxy: Optional[Proxy] = None):
145
145
 
146
- with self._lock:
147
- old_client_identifier = None
148
- old_client = None
146
+ # Preparar novo cliente fora do lock
147
+ new_client = Session(client_identifier=client_identifier,
148
+ random_tls_extension_order=random_tls_extension_order,
149
+ disable_http3=self.disable_http3)
150
+
151
+ # Aplicar configurações ao novo cliente
152
+ if proxy:
153
+ new_client.proxies = proxy.to_proxy_dict()
149
154
 
150
- if self.client:
151
- old_client_identifier = self.client.client_identifier
152
- old_client = self.client
155
+ if self.headers:
156
+ new_client.headers = CaseInsensitiveDict(self.headers)
153
157
 
154
- self.client = Session(client_identifier=client_identifier,
155
- random_tls_extension_order=random_tls_extension_order,
156
- disable_http3=self.disable_http3)
158
+ # Lock apenas para swap atômico
159
+ with self._lock:
160
+ old_client = self.client
161
+ old_client_identifier = old_client.client_identifier if old_client else None
157
162
 
158
- if old_client:
159
- old_client.close()
163
+ self.client = new_client
160
164
 
161
165
  if old_client_identifier != client_identifier:
162
166
  self.requests_amount_with_current_client_identifier = 0
163
167
 
164
- if proxy:
165
- self.client.proxies = proxy.to_proxy_dict()
166
-
167
- if self.current_proxy != proxy:
168
- self.current_proxy = proxy
169
- self.requests_amount_with_current_proxy = 0
168
+ if proxy and self.current_proxy != proxy:
169
+ self.current_proxy = proxy
170
+ self.requests_amount_with_current_proxy = 0
170
171
 
171
- # Aplicar headers padrão
172
- if self.headers:
173
- self.client.headers = CaseInsensitiveDict(self.headers)
172
+ # Fechar cliente antigo fora do lock
173
+ if old_client:
174
+ old_client.close()
174
175
 
175
176
 
176
177
  def set_requests_limit_same_proxy(self, requests_limit_same_proxy: int):
@@ -6,24 +6,30 @@ from dataclasses_json import dataclass_json
6
6
 
7
7
 
8
8
  @dataclass_json
9
- @dataclass
9
+ @dataclass(slots=True)
10
10
  class Proxy:
11
11
  host: str
12
12
  port: int
13
13
  username: Optional[str] = None
14
14
  password: Optional[str] = None
15
+ _proxy_dict_cache: Optional[dict] = field(default=None, init=False, repr=False)
15
16
 
16
17
  def to_proxy_dict(self):
18
+ if self._proxy_dict_cache is not None:
19
+ return self._proxy_dict_cache
20
+
17
21
  if self.username is None:
18
- return {
19
- 'http': f'http://{self.host}:{self.port}',
20
- 'https': f'https://{self.host}:{self.port}'
22
+ self._proxy_dict_cache = {
23
+ 'http': 'http://' + self.host + ':' + str(self.port),
24
+ 'https': 'https://' + self.host + ':' + str(self.port)
25
+ }
26
+ else:
27
+ self._proxy_dict_cache = {
28
+ 'http': 'http://' + self.username + ':' + self.password + '@' + self.host + ':' + str(self.port),
29
+ 'https': 'https://' + self.username + ':' + self.password + '@' + self.host + ':' + str(self.port)
21
30
  }
22
31
 
23
- return {
24
- 'http': f'http://{self.username}:{self.password}@{self.host}:{self.port}',
25
- 'https': f'https://{self.username}:{self.password}@{self.host}:{self.port}'
26
- }
32
+ return self._proxy_dict_cache
27
33
 
28
34
  def __eq__(self, other):
29
35
  if not isinstance(other, Proxy):
@@ -58,8 +64,8 @@ class ProxiesManager:
58
64
  return proxy
59
65
 
60
66
  def get_current_proxy(self) -> Optional[Proxy]:
61
- with self._lock:
62
- return self._current_proxy
67
+ # Lock-free read - Proxy é imutável (frozen dataclass)
68
+ return self._current_proxy
63
69
 
64
70
  def set_proxies(self, proxies: list[Proxy]):
65
71
  with self._lock:
@@ -69,11 +75,14 @@ class ProxiesManager:
69
75
 
70
76
  def add_proxy(self, proxy: Proxy):
71
77
  with self._lock:
72
- self._proxies.append(proxy)
78
+ # Criar nova lista ao invés de modificar in-place
79
+ new_proxies = self._proxies.copy()
80
+ new_proxies.append(proxy)
81
+ self._proxies = new_proxies
73
82
 
74
83
  def get_proxies(self) -> list[Proxy]:
75
- with self._lock:
76
- return self._proxies.copy()
84
+ # Lock-free read - retornar referência direta (lista é copiada pelo caller se necessário)
85
+ return self._proxies
77
86
 
78
87
 
79
88
 
@@ -1,14 +1,14 @@
1
- from orjson import orjson
1
+ import orjson
2
2
 
3
3
  from .cookies import cookiejar_from_dict, RequestsCookieJar
4
4
  from .structures import CaseInsensitiveDict
5
5
 
6
6
  from typing import Union
7
- import json
8
7
 
9
8
 
10
9
  class Response:
11
10
  """object, which contains the response to an HTTP request."""
11
+ __slots__ = ('elapsed', 'url', 'status_code', 'text', 'headers', 'cookies', '_content', '_content_consumed', '__weakref__')
12
12
 
13
13
  def __init__(self):
14
14
 
@@ -0,0 +1,338 @@
1
+ Metadata-Version: 2.4
2
+ Name: notify-tls-client
3
+ Version: 2.0.2
4
+ Summary: Cliente HTTP avançado com TLS fingerprinting, rotação automática de proxies e recuperação inteligente para web scraping profissional
5
+ Author-email: Jeferson Albara <jeferson.albara@example.com>
6
+ Maintainer-email: Jeferson Albara <jeferson.albara@example.com>
7
+ License: MIT
8
+ Project-URL: Homepage, https://github.com/jefersonAlbara/notify-tls-client
9
+ Project-URL: Documentation, https://github.com/jefersonAlbara/notify-tls-client#readme
10
+ Project-URL: Repository, https://github.com/jefersonAlbara/notify-tls-client
11
+ Project-URL: Issues, https://github.com/jefersonAlbara/notify-tls-client/issues
12
+ Project-URL: Changelog, https://github.com/jefersonAlbara/notify-tls-client/blob/main/CHANGELOG.md
13
+ Keywords: tls-client,http-client,web-scraping,proxy-rotation,tls-fingerprinting,browser-emulation,http2,http3,requests,automation
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Internet :: WWW/HTTP
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: Internet :: Proxy Servers
23
+ Classifier: Operating System :: OS Independent
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.12
26
+ Description-Content-Type: text/markdown
27
+ Requires-Dist: dataclasses-json>=0.6.0
28
+ Requires-Dist: typing-extensions>=4.8.0
29
+ Requires-Dist: orjson>=3.9.0
30
+ Provides-Extra: dev
31
+ Requires-Dist: pytest>=7.4.0; extra == "dev"
32
+ Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
33
+ Requires-Dist: black>=23.0.0; extra == "dev"
34
+ Requires-Dist: mypy>=1.5.0; extra == "dev"
35
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
36
+
37
+ # Notify TLS Client
38
+
39
+ [![PyPI version](https://badge.fury.io/py/notify-tls-client.svg)](https://badge.fury.io/py/notify-tls-client)
40
+ [![Python Version](https://img.shields.io/pypi/pyversions/notify-tls-client.svg)](https://pypi.org/project/notify-tls-client/)
41
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
42
+
43
+ Cliente HTTP avançado em Python com suporte a TLS/SSL customizado, fingerprinting de navegadores e rotação automática de proxies. Construído sobre a biblioteca `tls-client` com funcionalidades adicionais para web scraping e automação resiliente.
44
+
45
+ ## 🚀 Características Principais
46
+
47
+ - **Fingerprinting TLS Avançado**: Emula múltiplos navegadores (Chrome, Firefox, Safari, Edge, Mobile)
48
+ - **Rotação Automática**: Proxies e client identifiers com políticas configuráveis
49
+ - **Recuperação Automática**: Reconexão inteligente em erros e respostas proibidas
50
+ - **Thread-Safe**: Uso seguro em ambientes multi-threaded
51
+ - **Configuração Modular**: Sistema de configuração baseado em objetos reutilizáveis
52
+ - **Presets Prontos**: Configurações pré-definidas para casos de uso comuns
53
+ - **HTTP/3 Support**: Suporte opcional a QUIC/HTTP3
54
+
55
+ ## 📦 Instalação
56
+
57
+ ```bash
58
+ pip install notify-tls-client
59
+ ```
60
+
61
+ ### Requisitos
62
+
63
+ - Python >= 3.12
64
+ - Sistema operacional: Windows, macOS, Linux (x86_64, ARM64)
65
+
66
+ ## 🎯 Quick Start
67
+
68
+ ### Uso Básico
69
+
70
+ ```python
71
+ from notify_tls_client import NotifyTLSClient
72
+
73
+ # Cliente com configuração padrão
74
+ client = NotifyTLSClient()
75
+
76
+ # Fazer requisição
77
+ response = client.get("https://api.example.com/data")
78
+ print(response.status_code)
79
+ print(response.json())
80
+ ```
81
+
82
+ ### Usando Presets (Recomendado)
83
+
84
+ ```python
85
+ from notify_tls_client import NotifyTLSClient
86
+ from notify_tls_client.config import ClientConfiguration
87
+ from notify_tls_client.core.proxiesmanager import ProxiesManagerLoader
88
+
89
+ # Carregar proxies
90
+ proxies = ProxiesManagerLoader().from_txt("proxies.txt")
91
+
92
+ # Preset para scraping agressivo
93
+ config = ClientConfiguration.aggressive(proxies)
94
+ client = NotifyTLSClient(config)
95
+
96
+ # Fazer múltiplas requisições
97
+ for i in range(100):
98
+ response = client.get("https://example.com/api/endpoint")
99
+ print(f"Request {i}: {response.status_code}")
100
+ ```
101
+
102
+ ### Configuração Customizada
103
+
104
+ ```python
105
+ from notify_tls_client import NotifyTLSClient
106
+ from notify_tls_client.config import (
107
+ ClientConfiguration,
108
+ RotationConfig,
109
+ RecoveryConfig,
110
+ ClientConfig
111
+ )
112
+
113
+ config = ClientConfiguration(
114
+ proxies_manager=proxies,
115
+ rotation=RotationConfig(
116
+ requests_limit_same_proxy=50,
117
+ requests_limit_same_client_identifier=200,
118
+ random_tls_extension_order=True
119
+ ),
120
+ recovery=RecoveryConfig(
121
+ instantiate_new_client_on_forbidden_response=True,
122
+ instantiate_new_client_on_exception=True,
123
+ change_client_identifier_on_forbidden_response=True,
124
+ status_codes_to_forbidden_response_handle=[403, 429, 503]
125
+ ),
126
+ client=ClientConfig(
127
+ client_identifiers=["chrome_133", "firefox_120", "safari_17_0"],
128
+ disable_http3=False,
129
+ debug_mode=False
130
+ )
131
+ )
132
+
133
+ client = NotifyTLSClient(config)
134
+ ```
135
+
136
+ ## 📚 Presets Disponíveis
137
+
138
+ ### Simple
139
+ Uso básico com rotação de proxies padrão.
140
+ ```python
141
+ config = ClientConfiguration.simple(proxies)
142
+ ```
143
+
144
+ ### Aggressive
145
+ Para scraping intensivo com recuperação automática completa.
146
+ ```python
147
+ config = ClientConfiguration.aggressive(proxies)
148
+ ```
149
+ - Troca proxy a cada 10 requisições
150
+ - Troca client identifier a cada 50 requisições
151
+ - Recuperação automática em erros e 403/429/503
152
+ - Múltiplos client identifiers
153
+
154
+ ### Stealth
155
+ Foco em evitar detecção através de diversidade.
156
+ ```python
157
+ config = ClientConfiguration.stealth(proxies)
158
+ ```
159
+ - 4 client identifiers diferentes
160
+ - Ordem de extensões TLS randomizada
161
+ - Rotação moderada (100 req/proxy)
162
+
163
+ ### Mobile
164
+ Simula dispositivos móveis.
165
+ ```python
166
+ # Android
167
+ config = ClientConfiguration.mobile(proxies, platform="android")
168
+
169
+ # iOS
170
+ config = ClientConfiguration.mobile(proxies, platform="ios")
171
+ ```
172
+
173
+ ## 🔧 Funcionalidades Avançadas
174
+
175
+ ### Rotação de Proxies
176
+
177
+ ```python
178
+ from notify_tls_client.core.proxiesmanager import ProxiesManagerLoader
179
+
180
+ # Carregar de arquivo
181
+ proxies = ProxiesManagerLoader().from_txt("proxies.txt")
182
+
183
+ # Formato do arquivo (um por linha):
184
+ # host:port
185
+ # host:port:username:password
186
+ # http://username:password@host:port
187
+ ```
188
+
189
+ ### Client Identifiers Suportados
190
+
191
+ **Desktop:**
192
+ - Chrome: `chrome_133`, `chrome_131`, `chrome_120`, etc.
193
+ - Firefox: `firefox_120`, `firefox_117`, `firefox_110`, etc.
194
+ - Safari: `safari_17_0`, `safari_16_0`, etc.
195
+ - Edge, Opera
196
+
197
+ **Mobile:**
198
+ - Android: `okhttp4_android_13`, `okhttp4_android_12`, etc.
199
+ - iOS: `safari_ios_16_0`, `safari_ios_15_6`, etc.
200
+
201
+ ### Recuperação Automática
202
+
203
+ ```python
204
+ config = ClientConfiguration(
205
+ recovery=RecoveryConfig(
206
+ # Criar nova sessão em respostas proibidas
207
+ instantiate_new_client_on_forbidden_response=True,
208
+
209
+ # Criar nova sessão em exceções
210
+ instantiate_new_client_on_exception=True,
211
+
212
+ # Trocar identifier em respostas proibidas
213
+ change_client_identifier_on_forbidden_response=True,
214
+
215
+ # Status codes que acionam recuperação
216
+ status_codes_to_forbidden_response_handle=[403, 429, 503]
217
+ )
218
+ )
219
+ ```
220
+
221
+ ### Headers Customizados
222
+
223
+ ```python
224
+ config = ClientConfiguration(
225
+ client=ClientConfig(
226
+ default_headers={
227
+ "User-Agent": "Mozilla/5.0...",
228
+ "Accept-Language": "pt-BR,pt;q=0.9",
229
+ "Custom-Header": "value"
230
+ }
231
+ )
232
+ )
233
+
234
+ # Ou por requisição
235
+ response = client.get(
236
+ "https://example.com",
237
+ headers={"Authorization": "Bearer token"}
238
+ )
239
+ ```
240
+
241
+ ### Cookies
242
+
243
+ ```python
244
+ # Obter todos os cookies
245
+ cookies = client.get_cookies()
246
+
247
+ # Obter cookie específico
248
+ value = client.get_cookie_by_name("session_id")
249
+
250
+ # Definir cookie
251
+ client.set_cookie("name", "value")
252
+ ```
253
+
254
+ ## 🔒 Thread Safety
255
+
256
+ A biblioteca é thread-safe e pode ser usada em ambientes multi-threaded:
257
+
258
+ ```python
259
+ import concurrent.futures
260
+
261
+ client = NotifyTLSClient(ClientConfiguration.aggressive(proxies))
262
+
263
+ def make_request(url):
264
+ return client.get(url)
265
+
266
+ with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
267
+ urls = ["https://example.com"] * 100
268
+ results = list(executor.map(make_request, urls))
269
+ ```
270
+
271
+ ## 📊 Logging
272
+
273
+ ```python
274
+ import logging
275
+
276
+ # Habilitar logs de debug
277
+ logging.basicConfig(level=logging.DEBUG)
278
+
279
+ # Ou configurar apenas para notify_tls_client
280
+ logger = logging.getLogger("notify_tls_client")
281
+ logger.setLevel(logging.DEBUG)
282
+ ```
283
+
284
+ ## 🛠️ Métodos HTTP Suportados
285
+
286
+ ```python
287
+ # GET
288
+ response = client.get(url, params={"key": "value"})
289
+
290
+ # POST
291
+ response = client.post(url, json={"data": "value"})
292
+ response = client.post(url, data="form data")
293
+
294
+ # PUT
295
+ response = client.put(url, json={"data": "value"})
296
+
297
+ # PATCH
298
+ response = client.patch(url, json={"data": "value"})
299
+
300
+ # DELETE
301
+ response = client.delete(url)
302
+ ```
303
+
304
+ ## 📖 Documentação Completa
305
+
306
+ Para documentação detalhada sobre arquitetura, componentes internos e exemplos avançados, consulte:
307
+ - [CLAUDE.md](CLAUDE.md) - Guia completo de desenvolvimento
308
+ - [examples/](examples/) - Exemplos de código
309
+
310
+ ## 🤝 Contribuindo
311
+
312
+ Contribuições são bem-vindas! Por favor, leia [CONTRIBUTING.md](CONTRIBUTING.md) para detalhes sobre nosso código de conduta e processo de submissão de pull requests.
313
+
314
+ ## 📝 Changelog
315
+
316
+ Veja [CHANGELOG.md](CHANGELOG.md) para histórico de versões e mudanças.
317
+
318
+ ## 📄 Licença
319
+
320
+ Este projeto está licenciado sob a Licença MIT - veja o arquivo [LICENSE](LICENSE) para detalhes.
321
+
322
+ ## ⚠️ Aviso Legal
323
+
324
+ Esta biblioteca é fornecida apenas para fins educacionais e de pesquisa. O uso desta ferramenta para violar termos de serviço de websites, realizar scraping não autorizado ou qualquer atividade ilegal é de sua responsabilidade. Os desenvolvedores não se responsabilizam pelo uso indevido desta biblioteca.
325
+
326
+ ## 🙏 Agradecimentos
327
+
328
+ - [tls-client](https://github.com/bogdanfinn/tls-client) - Biblioteca Go subjacente para TLS fingerprinting
329
+ - Comunidade Python por ferramentas e bibliotecas incríveis
330
+
331
+ ## 📞 Suporte
332
+
333
+ - **Issues**: [GitHub Issues](https://github.com/jefersonAlbara/notify-tls-client/issues)
334
+ - **Discussões**: [GitHub Discussions](https://github.com/jefersonAlbara/notify-tls-client/discussions)
335
+
336
+ ---
337
+
338
+ **Desenvolvido com ❤️ para a comunidade Python**
@@ -2,22 +2,22 @@ notify_tls_client/__init__.py,sha256=APA8wxvkGYZiVMMbTWGo7prB3iKE-OzUajd0bfc8PwE
2
2
  notify_tls_client/config/__init__.py,sha256=2xsw7M2E8-ncpIDySYcgH500xAnYyO3qy3PRXkP2inQ,495
3
3
  notify_tls_client/config/client_config.py,sha256=Fwg6LS1zP8XFRPbTxNj2svCqeWh2GJcqrq7hnpQtYRQ,2837
4
4
  notify_tls_client/config/client_configuration.py,sha256=Zl71lxZSKU7oVJwnHPSYV9uufk2IgFtHW3u9deqo5HU,9103
5
- notify_tls_client/config/recovery_config.py,sha256=L5a_jMUfdUMdFBXeLPz9RAU0oXz-Ma4ZuzG7B-h7hDs,2876
5
+ notify_tls_client/config/recovery_config.py,sha256=zKBjSdCHJ4iF0PXUawPh3EktOxGdn-8bzpjl7LOIoa4,3202
6
6
  notify_tls_client/config/rotation_config.py,sha256=Av_K6BzgPknFYZXxe9WmDra8VGI9JEpDJSm0dDs8QqM,2089
7
7
  notify_tls_client/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- notify_tls_client/core/client_identifiers_manager.py,sha256=ko4Y5IVMxNTRgk4e6jiJF_kcMjzej9rRt7BJtX-OMyg,1346
9
- notify_tls_client/core/notifytlsclient.py,sha256=Mj6myXtzc_M52oOj_-cj4NcSx2WOuDIfg396CtOLmDo,12598
8
+ notify_tls_client/core/client_identifiers_manager.py,sha256=D8xJ89aaxZ_8Pssx9VqEH05G8cp3bMez14-KrTMtJiU,1646
9
+ notify_tls_client/core/notifytlsclient.py,sha256=JZSQ0frcYTuoLeiaWt7rwJh8IqgFtxZ6QLj1HG4MaD8,12650
10
10
  notify_tls_client/core/client/__init__.py,sha256=VKjpq02hC-r9ER6mbfkwG6W2ybv_jND9d9bidte0CjU,51
11
- notify_tls_client/core/client/decorators.py,sha256=GjGUl5eE5KZGB7Bc6XRFgmJ1Xjz6gNBXxOH8jldCAl8,8554
11
+ notify_tls_client/core/client/decorators.py,sha256=oCmB_9vSyW3C0GEv1AiMIj_rJOwsZ2bHDVRD_QgJmQs,9693
12
12
  notify_tls_client/core/proxiesmanager/__init__.py,sha256=emF4vnZvSfb9zlHkt9dDdTcGwkfs1DADi7XVw_DxsWs,105
13
- notify_tls_client/core/proxiesmanager/proxiesmanager.py,sha256=V-X5dWskGHUjrX-hpl9E4L6pv53LBg1M0giEbWmG6JE,2286
13
+ notify_tls_client/core/proxiesmanager/proxiesmanager.py,sha256=hcSw27wbt6UerJ5F8hfLjrIS8H1K-XwgZEa60lvGhXg,2902
14
14
  notify_tls_client/core/proxiesmanager/proxiesmanagerloader.py,sha256=7xr3SVdRnr95KWOdk15iehOCXG2huA-rY1j9VIe30YQ,1179
15
15
  notify_tls_client/tls_client/__init__.py,sha256=sThiIAzA650rfBlqZ_xalTjgTysUsjKua5ODnqyvhUE,669
16
16
  notify_tls_client/tls_client/__version__.py,sha256=32ZZ-ufGC9Yo6oPk5a1xig8YKJ2ZkRXnXoVqiqO0ptg,395
17
17
  notify_tls_client/tls_client/cffi.py,sha256=pedwBcQOwJvI66yp5GpyNU6zoqrQhTv3ocM1-1PtUm0,1291
18
18
  notify_tls_client/tls_client/cookies.py,sha256=1fIOnFDMWMeXuAjQybSrUJXnyjhP-_jJ68AxBUZYgYU,15609
19
19
  notify_tls_client/tls_client/exceptions.py,sha256=xIoFb5H3Suk7XssQ-yw3I1DBkPLqnDXsiAe2MMp1qNQ,80
20
- notify_tls_client/tls_client/response.py,sha256=7j4iJa59Hcdw5ZWPvaxgLTvC_AWrch9hwMbrK4HNJjo,2618
20
+ notify_tls_client/tls_client/response.py,sha256=oMXdnbyppX5B1pYsk8h1UqZG01qHVOQCcnYrMG79ThI,2722
21
21
  notify_tls_client/tls_client/sessions.py,sha256=1xeUDR9H42wS900mCzkpu4At7Lx1O07QGoDuThbLG0M,19233
22
22
  notify_tls_client/tls_client/settings.py,sha256=x_2Vrph-QebbCjkxmnX8UPd5oYYU4ClqPOpfoqelno4,1485
23
23
  notify_tls_client/tls_client/structures.py,sha256=md-tJmo8X5bad0KrMUTVN8jxUIvui7NiBxaf10bLULU,2517
@@ -26,7 +26,7 @@ notify_tls_client/tls_client/dependencies/tls-client-darwin-amd64-1.12.0.dylib,s
26
26
  notify_tls_client/tls_client/dependencies/tls-client-linux-arm64-1.12.0.so,sha256=fQvdtCiRRS228WrFUE_ucq4OPC4Z7QU4_KI4B3Gf97Y,14404088
27
27
  notify_tls_client/tls_client/dependencies/tls-client-linux-ubuntu-amd64-1.12.0.so,sha256=UTvtZa93fWLWaSBINC_Cu8mNoLwsVdcQbQZsdQnZrJM,15210112
28
28
  notify_tls_client/tls_client/dependencies/tls-client-windows-64-1.12.0.dll,sha256=uk80UEGW8WepYMglh1Yo6VSrBSNDwon-OyFqE_1bWmM,24849278
29
- notify_tls_client-2.0.0.dist-info/METADATA,sha256=O_m_lTWjraTbcqLAHr1GxwtNwOzHWnb6T1InhT5qiUA,1941
30
- notify_tls_client-2.0.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
31
- notify_tls_client-2.0.0.dist-info/top_level.txt,sha256=fq9YA0cFdpCuUO7cdMFN7oxm1zDfZm_m1KPXehUqA5o,18
32
- notify_tls_client-2.0.0.dist-info/RECORD,,
29
+ notify_tls_client-2.0.2.dist-info/METADATA,sha256=gf8TM2izyYQ_8Cs7BMPJvTHZlKLDmM1mPWwC-MuuQFI,10565
30
+ notify_tls_client-2.0.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
31
+ notify_tls_client-2.0.2.dist-info/top_level.txt,sha256=fq9YA0cFdpCuUO7cdMFN7oxm1zDfZm_m1KPXehUqA5o,18
32
+ notify_tls_client-2.0.2.dist-info/RECORD,,
@@ -1,38 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: notify-tls-client
3
- Version: 2.0.0
4
- Summary: Cliente HTTP avançado com TLS fingerprinting, rotação de proxies e recuperação automática para web scraping resiliente
5
- Author-email: Jeferson Albara <jeferson.albara@example.com>
6
- Maintainer-email: Jeferson Albara <jeferson.albara@example.com>
7
- License: MIT
8
- Project-URL: Homepage, https://github.com/jefersonAlbara/notify-tls-client
9
- Project-URL: Documentation, https://github.com/jefersonAlbara/notify-tls-client#readme
10
- Project-URL: Repository, https://github.com/jefersonAlbara/notify-tls-client
11
- Project-URL: Issues, https://github.com/jefersonAlbara/notify-tls-client/issues
12
- Project-URL: Changelog, https://github.com/jefersonAlbara/notify-tls-client/blob/main/CHANGELOG.md
13
- Keywords: tls-client,http-client,web-scraping,proxy-rotation,tls-fingerprinting,browser-emulation,http2,http3,requests,automation
14
- Classifier: Development Status :: 4 - Beta
15
- Classifier: Intended Audience :: Developers
16
- Classifier: License :: OSI Approved :: MIT License
17
- Classifier: Programming Language :: Python :: 3
18
- Classifier: Programming Language :: Python :: 3.12
19
- Classifier: Programming Language :: Python :: 3.13
20
- Classifier: Topic :: Internet :: WWW/HTTP
21
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
- Classifier: Topic :: Internet :: Proxy Servers
23
- Classifier: Operating System :: OS Independent
24
- Classifier: Typing :: Typed
25
- Requires-Python: >=3.12
26
- Description-Content-Type: text/markdown
27
- Requires-Dist: dataclasses-json>=0.6.0
28
- Requires-Dist: typing-extensions>=4.8.0
29
- Requires-Dist: orjson>=3.9.0
30
- Provides-Extra: dev
31
- Requires-Dist: pytest>=7.4.0; extra == "dev"
32
- Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
33
- Requires-Dist: black>=23.0.0; extra == "dev"
34
- Requires-Dist: mypy>=1.5.0; extra == "dev"
35
- Requires-Dist: ruff>=0.1.0; extra == "dev"
36
-
37
- # MY TLS Client
38
- Pacote python privado com modificações na classe 'tls client'