apikeyrotator 0.0.2__tar.gz

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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Prime Evolution
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,335 @@
1
+ Metadata-Version: 2.4
2
+ Name: apikeyrotator
3
+ Version: 0.0.2
4
+ Summary: Ultra simple API key rotation for bypassing rate limits
5
+ Author-email: Prime Evolution <develop@eclips-team.ru>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2024 Prime Evolution
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+ Project-URL: Homepage, https://github.com/PrimeevolutionZ/apikeyrotator
28
+ Project-URL: Repository, https://github.com/PrimeevolutionZ/apikeyrotator
29
+ Project-URL: Issues, https://github.com/PrimeevolutionZ/apikeyrotator/issues
30
+ Keywords: api,rotation,rate limit,requests
31
+ Classifier: Development Status :: 4 - Beta
32
+ Classifier: Intended Audience :: Developers
33
+ Classifier: License :: OSI Approved :: MIT License
34
+ Classifier: Programming Language :: Python :: 3
35
+ Classifier: Programming Language :: Python :: 3.7
36
+ Classifier: Programming Language :: Python :: 3.8
37
+ Classifier: Programming Language :: Python :: 3.9
38
+ Classifier: Programming Language :: Python :: 3.10
39
+ Classifier: Programming Language :: Python :: 3.11
40
+ Classifier: Programming Language :: Python :: 3.12
41
+ Description-Content-Type: text/markdown
42
+ License-File: LICENSE
43
+ Requires-Dist: requests>=2.25.0
44
+ Dynamic: license-file
45
+
46
+ # API Key Rotator πŸ”„
47
+
48
+ ΠŸΡ€ΠΎΡΡ‚Π°Ρ, Π½ΠΎ мощная Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° для автоматичСского вращСния API ΠΊΠ»ΡŽΡ‡Π΅ΠΉ. ΠžΠ±Ρ…ΠΎΠ΄ΠΈΡ‚ Π»ΠΈΠΌΠΈΡ‚Ρ‹ запросов, ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ ошибки 429 ΠΈ Π΄Π΅Π»Π°Π΅Ρ‚ ваши запросы нСуязвимыми ΠΊ ограничСниям API.
49
+
50
+ ## ΠžΡΠΎΠ±Π΅Π½Π½ΠΎΡΡ‚ΠΈ ✨
51
+
52
+ - πŸ”„ **АвтоматичСскоС Π²Ρ€Π°Ρ‰Π΅Π½ΠΈΠ΅ ΠΊΠ»ΡŽΡ‡Π΅ΠΉ** - Round-robin Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ
53
+ - ⚑ **АвтодСтСкт Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ** - Π‘Π°ΠΌ опрСдСляСт Bearer/API-Key Ρ„ΠΎΡ€ΠΌΠ°Ρ‚
54
+ - πŸ” **Π£ΠΌΠ½Ρ‹Π΅ Ρ€Π΅Ρ‚Ρ€Π°ΠΈ** - Π­ΠΊΡΠΏΠΎΠ½Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½Π°Ρ Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠ° ΠΏΡ€ΠΈ ΠΎΡˆΠΈΠ±ΠΊΠ°Ρ…
55
+ - πŸ›‘οΈ **ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок** - 429, 500, 502, 503, 504 автоматичСски
56
+ - πŸ’» **Полная ΡΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒ** с Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΎΠΉ `requests`
57
+ - πŸ“ **ΠŸΠΎΠ½ΡΡ‚Π½Ρ‹Π΅ ошибки** - Подсказки ΠΊΠ°ΠΊ ΠΈΡΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹
58
+
59
+ ## Установка πŸ“¦
60
+
61
+ ```bash
62
+ pip install apikeyrotator
63
+ ```
64
+
65
+ Или ΠΈΠ· исходников:
66
+
67
+ ```bash
68
+ git clone https://github.com/PrimeevolutionZ/apikeyrotator.git
69
+ cd apikeyrotator
70
+ pip install -e .
71
+ ```
72
+
73
+ ## Быстрый старт πŸš€
74
+
75
+ ### Бпособ 1: ΠŸΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° ΠΊΠ»ΡŽΡ‡Π΅ΠΉ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ
76
+
77
+ ```python
78
+ from apikeyrotator import APIKeyRotator
79
+
80
+ # ΠŸΡ€ΠΎΡΡ‚ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°ΠΉΡ‚Π΅ ΠΊΠ»ΡŽΡ‡ΠΈ списком
81
+ rotator = APIKeyRotator(api_keys=["key1", "key2", "key3"])
82
+
83
+ # Или строкой Ρ‡Π΅Ρ€Π΅Π· Π·Π°ΠΏΡΡ‚ΡƒΡŽ
84
+ rotator = APIKeyRotator(api_keys="key1,key2,key3")
85
+
86
+ # Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ ΠΊΠ°ΠΊ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΉ requests!
87
+ response = rotator.get("https://api.example.com/data")
88
+ print(response.json())
89
+ ```
90
+
91
+ ### Бпособ 2: ИспользованиС ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… окруТСния
92
+
93
+ Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ Ρ„Π°ΠΉΠ» `.env` Π² ΠΊΠΎΡ€Π½Π΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°:
94
+ ```env
95
+ API_KEYS=your_key_1,your_key_2,your_key_3
96
+ ```
97
+
98
+ Или установитС ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ окруТСния:
99
+ ```bash
100
+ # Linux/Mac
101
+ export API_KEYS="your_key_1,your_key_2,your_key_3"
102
+
103
+ # Windows
104
+ set API_KEYS=your_key_1,your_key_2,your_key_3
105
+ ```
106
+
107
+ Π’Π΅ΠΏΠ΅Ρ€ΡŒ просто ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠΉΡ‚Π΅ Ρ€ΠΎΡ‚Π°Ρ‚ΠΎΡ€:
108
+ ```python
109
+ from apikeyrotator import APIKeyRotator
110
+
111
+ rotator = APIKeyRotator() # АвтоматичСски Π½Π°ΠΉΠ΄Π΅Ρ‚ API_KEYS
112
+
113
+ response = rotator.get("https://api.example.com/data")
114
+ ```
115
+
116
+ ## ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ использования πŸ“–
117
+
118
+ ### Π‘Π°Π·ΠΎΠ²Ρ‹Π΅ HTTP-запросы
119
+
120
+ ```python
121
+ from apikeyrotator import APIKeyRotator
122
+
123
+ rotator = APIKeyRotator(api_keys=["key1", "key2", "key3"])
124
+
125
+ # GET запрос
126
+ response = rotator.get("https://api.example.com/users")
127
+
128
+ # POST запрос с Π΄Π°Π½Π½Ρ‹ΠΌΠΈ
129
+ response = rotator.post(
130
+ "https://api.example.com/users",
131
+ json={"name": "John", "email": "john@example.com"}
132
+ )
133
+
134
+ # PUT запрос
135
+ response = rotator.put(
136
+ "https://api.example.com/users/1",
137
+ json={"name": "John Updated"}
138
+ )
139
+
140
+ # DELETE запрос
141
+ response = rotator.delete("https://api.example.com/users/1")
142
+ ```
143
+
144
+ ### ΠšΠ°ΡΡ‚ΠΎΠΌΠ½Ρ‹Π΅ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΈ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ
145
+
146
+ ```python
147
+ from apikeyrotator import APIKeyRotator
148
+
149
+ rotator = APIKeyRotator(api_keys=["key1", "key2"])
150
+
151
+ # ΠšΠ°ΡΡ‚ΠΎΠΌΠ½Ρ‹ΠΉ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ
152
+ response = rotator.get(
153
+ "https://api.example.com/data",
154
+ headers={"X-Custom-Auth": "custom_value"}
155
+ )
156
+
157
+ # Или ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚Π΅ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΡŽ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ
158
+ response = rotator.get(
159
+ "https://api.example.com/data",
160
+ headers={"Authorization": "Custom your_token_here"}
161
+ )
162
+ ```
163
+
164
+ ### Π Π°Π±ΠΎΡ‚Π° с ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°ΠΌΠΈ запроса
165
+
166
+ ```python
167
+ from apikeyrotator import APIKeyRotator
168
+
169
+ rotator = APIKeyRotator(api_keys=["key1", "key2", "key3"])
170
+
171
+ # ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ запроса
172
+ response = rotator.get(
173
+ "https://api.example.com/search",
174
+ params={"query": "python", "limit": 10}
175
+ )
176
+
177
+ # JSON Π΄Π°Π½Π½Ρ‹Π΅
178
+ response = rotator.post(
179
+ "https://api.example.com/items",
180
+ json={"name": "New Item", "price": 99.99}
181
+ )
182
+
183
+ # Π’Π°ΠΉΠΌΠ°ΡƒΡ‚
184
+ response = rotator.get(
185
+ "https://api.example.com/data",
186
+ timeout=10
187
+ )
188
+ ```
189
+
190
+ ### ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок
191
+
192
+ ```python
193
+ from apikeyrotator import APIKeyRotator, AllKeysExhaustedError
194
+
195
+ rotator = APIKeyRotator(api_keys=["key1", "key2"], max_retries=5)
196
+
197
+ try:
198
+ response = rotator.get("https://api.example.com/limited")
199
+ print("УспСх!", response.json())
200
+ except AllKeysExhaustedError as e:
201
+ print("ВсС ΠΊΠ»ΡŽΡ‡ΠΈ исчСрпаны:", e)
202
+ except Exception as e:
203
+ print("Другая ошибка:", e)
204
+ ```
205
+
206
+ ## Π Π°ΡΡˆΠΈΡ€Π΅Π½Π½Ρ‹Π΅ настройки βš™οΈ
207
+
208
+ ### ΠšΠ°ΡΡ‚ΠΎΠΌΠΈΠ·Π°Ρ†ΠΈΡ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ²
209
+
210
+ ```python
211
+ from apikeyrotator import APIKeyRotator
212
+
213
+ # ВсС ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ настройки
214
+ rotator = APIKeyRotator(
215
+ api_keys=["key1", "key2", "key3"], # ΠšΠ»ΡŽΡ‡ΠΈ
216
+ env_var="CUSTOM_API_KEYS", # ΠšΠ°ΡΡ‚ΠΎΠΌΠ½Π°Ρ пСрСмСнная окруТСния
217
+ max_retries=5, # ΠœΠ°ΠΊΡΠΈΠΌΡƒΠΌ ΠΏΠΎΠΏΡ‹Ρ‚ΠΎΠΊ
218
+ base_delay=2.0 # Базовая Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠ° ΠΌΠ΅ΠΆΠ΄Ρƒ ΠΏΠΎΠΏΡ‹Ρ‚ΠΊΠ°ΠΌΠΈ
219
+ )
220
+
221
+ print(f"ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ ΠΊΠ»ΡŽΡ‡Π΅ΠΉ: {len(rotator)}")
222
+ print(f"ΠœΠ°ΠΊΡΠΈΠΌΡƒΠΌ ΠΏΠΎΠΏΡ‹Ρ‚ΠΎΠΊ: {rotator.max_retries}")
223
+ ```
224
+
225
+ ### Π˜Π½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΡ с ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΌ ΠΊΠΎΠ΄ΠΎΠΌ
226
+
227
+ ```python
228
+ from apikeyrotator import APIKeyRotator
229
+ import requests
230
+
231
+ # Π‘ΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ ΠΊΠΎΠ΄ с requests
232
+ response = requests.get("https://api.example.com/data")
233
+
234
+ # Π›Π΅Π³ΠΊΠΎ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚Π΅ Π½Π° APIKeyRotator
235
+ rotator = APIKeyRotator(api_keys=["key1", "key2", "key3"])
236
+ response = rotator.get("https://api.example.com/data") # Π’ΠΎΡ‚ ΠΆΠ΅ API!
237
+ ```
238
+
239
+ ## Best Practices βœ…
240
+
241
+ ### 1. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ окруТСния для бСзопасности
242
+
243
+ ```bash
244
+ # Никогда Π½Π΅ Ρ…Ρ€Π°Π½ΠΈΡ‚Π΅ ΠΊΠ»ΡŽΡ‡ΠΈ Π² ΠΊΠΎΠ΄Π΅!
245
+ # ВмСсто этого ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ .env Ρ„Π°ΠΉΠ» ΠΈΠ»ΠΈ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ окруТСния
246
+ export API_KEYS="your_production_key_1,your_production_key_2"
247
+ ```
248
+
249
+ ### 2. НастройтС Π°Π΄Π΅ΠΊΠ²Π°Ρ‚Π½ΠΎΠ΅ количСство ΠΏΠΎΠΏΡ‹Ρ‚ΠΎΠΊ
250
+
251
+ ```python
252
+ # Для 3 ΠΊΠ»ΡŽΡ‡Π΅ΠΉ ΠΈ 2 ΠΏΠΎΠΏΡ‹Ρ‚ΠΎΠΊ Π½Π° ΠΊΠ»ΡŽΡ‡ = 6 всСго ΠΏΠΎΠΏΡ‹Ρ‚ΠΎΠΊ
253
+ rotator = APIKeyRotator(
254
+ api_keys=["key1", "key2", "key3"],
255
+ max_retries=6
256
+ )
257
+ ```
258
+
259
+ ### 3. ΠœΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΠ½Π³ использования ΠΊΠ»ΡŽΡ‡Π΅ΠΉ
260
+
261
+ ```python
262
+ rotator = APIKeyRotator(api_keys=["key1", "key2", "key3"])
263
+
264
+ # ПослС Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… запросов ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ статистику
265
+ for i in range(10):
266
+ rotator.get("https://api.example.com/test")
267
+
268
+ print("Π ΠΎΡ‚Π°Ρ‚ΠΎΡ€ ΠΎΡ‚Ρ€Π°Π±ΠΎΡ‚Π°Π»", len(rotator), "запросов")
269
+ ```
270
+
271
+ ## ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок ❌
272
+
273
+ Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° прСдоставляСт понятныС сообщСния ΠΎΠ± ΠΎΡˆΠΈΠ±ΠΊΠ°Ρ…:
274
+
275
+ ### Если ΠΊΠ»ΡŽΡ‡ΠΈ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Ρ‹
276
+
277
+ ```
278
+ ❌ No API keys found.
279
+ Please either:
280
+ 1. Pass keys directly: APIKeyRotator(api_keys=['key1', 'key2'])
281
+ 2. Set environment variable: export API_KEYS='key1,key2'
282
+ 3. Create .env file with: API_KEYS=key1,key2
283
+ ```
284
+
285
+ ### Если всС ΠΊΠ»ΡŽΡ‡ΠΈ исчСрпаны
286
+
287
+ ```python
288
+ try:
289
+ response = rotator.get("https://api.example.com/limited")
290
+ except AllKeysExhaustedError as e:
291
+ print(e) # "All 3 keys exhausted after 6 attempts"
292
+ ```
293
+
294
+ ## Π‘ΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒ πŸ”„
295
+
296
+ - **Python**: 3.7+
297
+ - **Зависимости**: Ρ‚ΠΎΠ»ΡŒΠΊΠΎ `requests>=2.25.0`
298
+
299
+ ## Π Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° πŸ› οΈ
300
+
301
+ ### Установка для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ
302
+
303
+ ```bash
304
+ git clone https://github.com/PrimeevolutionZ/apikeyrotator.git
305
+ cd apikeyrotator
306
+ python -m venv venv
307
+ source venv/bin/activate # Linux/Mac
308
+ # ΠΈΠ»ΠΈ
309
+ venv\Scripts\activate # Windows
310
+ pip install -e .[dev]
311
+ ```
312
+
313
+ ### Запуск тСстов
314
+
315
+ ```bash
316
+ pytest tests/
317
+ ```
318
+
319
+ ### Π‘Π±ΠΎΡ€ΠΊΠ° ΠΏΠ°ΠΊΠ΅Ρ‚Π°
320
+
321
+ ```bash
322
+ python setup.py sdist bdist_wheel
323
+ ```
324
+
325
+ ## ЛицСнзия πŸ“„
326
+
327
+ MIT License - смотритС Ρ„Π°ΠΉΠ» [LICENSE](LICENSE) для Π΄Π΅Ρ‚Π°Π»Π΅ΠΉ.
328
+
329
+ ## ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° 🀝
330
+
331
+ Нашли Π±Π°Π³ ΠΈΠ»ΠΈ Π΅ΡΡ‚ΡŒ прСдлоТСния? [Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ issue](https://github.com/yourusername/apikeyrotator/issues) Π½Π° GitHub!
332
+
333
+ ---
334
+
335
+ **API Key Rotator** - сдСлайтС ваши API запросы нСуязвимыми ΠΊ ограничСниям! πŸš€
@@ -0,0 +1,290 @@
1
+ # API Key Rotator πŸ”„
2
+
3
+ ΠŸΡ€ΠΎΡΡ‚Π°Ρ, Π½ΠΎ мощная Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° для автоматичСского вращСния API ΠΊΠ»ΡŽΡ‡Π΅ΠΉ. ΠžΠ±Ρ…ΠΎΠ΄ΠΈΡ‚ Π»ΠΈΠΌΠΈΡ‚Ρ‹ запросов, ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ ошибки 429 ΠΈ Π΄Π΅Π»Π°Π΅Ρ‚ ваши запросы нСуязвимыми ΠΊ ограничСниям API.
4
+
5
+ ## ΠžΡΠΎΠ±Π΅Π½Π½ΠΎΡΡ‚ΠΈ ✨
6
+
7
+ - πŸ”„ **АвтоматичСскоС Π²Ρ€Π°Ρ‰Π΅Π½ΠΈΠ΅ ΠΊΠ»ΡŽΡ‡Π΅ΠΉ** - Round-robin Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ
8
+ - ⚑ **АвтодСтСкт Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ** - Π‘Π°ΠΌ опрСдСляСт Bearer/API-Key Ρ„ΠΎΡ€ΠΌΠ°Ρ‚
9
+ - πŸ” **Π£ΠΌΠ½Ρ‹Π΅ Ρ€Π΅Ρ‚Ρ€Π°ΠΈ** - Π­ΠΊΡΠΏΠΎΠ½Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½Π°Ρ Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠ° ΠΏΡ€ΠΈ ΠΎΡˆΠΈΠ±ΠΊΠ°Ρ…
10
+ - πŸ›‘οΈ **ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок** - 429, 500, 502, 503, 504 автоматичСски
11
+ - πŸ’» **Полная ΡΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒ** с Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΎΠΉ `requests`
12
+ - πŸ“ **ΠŸΠΎΠ½ΡΡ‚Π½Ρ‹Π΅ ошибки** - Подсказки ΠΊΠ°ΠΊ ΠΈΡΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹
13
+
14
+ ## Установка πŸ“¦
15
+
16
+ ```bash
17
+ pip install apikeyrotator
18
+ ```
19
+
20
+ Или ΠΈΠ· исходников:
21
+
22
+ ```bash
23
+ git clone https://github.com/PrimeevolutionZ/apikeyrotator.git
24
+ cd apikeyrotator
25
+ pip install -e .
26
+ ```
27
+
28
+ ## Быстрый старт πŸš€
29
+
30
+ ### Бпособ 1: ΠŸΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° ΠΊΠ»ΡŽΡ‡Π΅ΠΉ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ
31
+
32
+ ```python
33
+ from apikeyrotator import APIKeyRotator
34
+
35
+ # ΠŸΡ€ΠΎΡΡ‚ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°ΠΉΡ‚Π΅ ΠΊΠ»ΡŽΡ‡ΠΈ списком
36
+ rotator = APIKeyRotator(api_keys=["key1", "key2", "key3"])
37
+
38
+ # Или строкой Ρ‡Π΅Ρ€Π΅Π· Π·Π°ΠΏΡΡ‚ΡƒΡŽ
39
+ rotator = APIKeyRotator(api_keys="key1,key2,key3")
40
+
41
+ # Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ ΠΊΠ°ΠΊ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΉ requests!
42
+ response = rotator.get("https://api.example.com/data")
43
+ print(response.json())
44
+ ```
45
+
46
+ ### Бпособ 2: ИспользованиС ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… окруТСния
47
+
48
+ Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ Ρ„Π°ΠΉΠ» `.env` Π² ΠΊΠΎΡ€Π½Π΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°:
49
+ ```env
50
+ API_KEYS=your_key_1,your_key_2,your_key_3
51
+ ```
52
+
53
+ Или установитС ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ окруТСния:
54
+ ```bash
55
+ # Linux/Mac
56
+ export API_KEYS="your_key_1,your_key_2,your_key_3"
57
+
58
+ # Windows
59
+ set API_KEYS=your_key_1,your_key_2,your_key_3
60
+ ```
61
+
62
+ Π’Π΅ΠΏΠ΅Ρ€ΡŒ просто ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠΉΡ‚Π΅ Ρ€ΠΎΡ‚Π°Ρ‚ΠΎΡ€:
63
+ ```python
64
+ from apikeyrotator import APIKeyRotator
65
+
66
+ rotator = APIKeyRotator() # АвтоматичСски Π½Π°ΠΉΠ΄Π΅Ρ‚ API_KEYS
67
+
68
+ response = rotator.get("https://api.example.com/data")
69
+ ```
70
+
71
+ ## ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ использования πŸ“–
72
+
73
+ ### Π‘Π°Π·ΠΎΠ²Ρ‹Π΅ HTTP-запросы
74
+
75
+ ```python
76
+ from apikeyrotator import APIKeyRotator
77
+
78
+ rotator = APIKeyRotator(api_keys=["key1", "key2", "key3"])
79
+
80
+ # GET запрос
81
+ response = rotator.get("https://api.example.com/users")
82
+
83
+ # POST запрос с Π΄Π°Π½Π½Ρ‹ΠΌΠΈ
84
+ response = rotator.post(
85
+ "https://api.example.com/users",
86
+ json={"name": "John", "email": "john@example.com"}
87
+ )
88
+
89
+ # PUT запрос
90
+ response = rotator.put(
91
+ "https://api.example.com/users/1",
92
+ json={"name": "John Updated"}
93
+ )
94
+
95
+ # DELETE запрос
96
+ response = rotator.delete("https://api.example.com/users/1")
97
+ ```
98
+
99
+ ### ΠšΠ°ΡΡ‚ΠΎΠΌΠ½Ρ‹Π΅ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΈ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ
100
+
101
+ ```python
102
+ from apikeyrotator import APIKeyRotator
103
+
104
+ rotator = APIKeyRotator(api_keys=["key1", "key2"])
105
+
106
+ # ΠšΠ°ΡΡ‚ΠΎΠΌΠ½Ρ‹ΠΉ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ
107
+ response = rotator.get(
108
+ "https://api.example.com/data",
109
+ headers={"X-Custom-Auth": "custom_value"}
110
+ )
111
+
112
+ # Или ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚Π΅ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΡŽ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ
113
+ response = rotator.get(
114
+ "https://api.example.com/data",
115
+ headers={"Authorization": "Custom your_token_here"}
116
+ )
117
+ ```
118
+
119
+ ### Π Π°Π±ΠΎΡ‚Π° с ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°ΠΌΠΈ запроса
120
+
121
+ ```python
122
+ from apikeyrotator import APIKeyRotator
123
+
124
+ rotator = APIKeyRotator(api_keys=["key1", "key2", "key3"])
125
+
126
+ # ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ запроса
127
+ response = rotator.get(
128
+ "https://api.example.com/search",
129
+ params={"query": "python", "limit": 10}
130
+ )
131
+
132
+ # JSON Π΄Π°Π½Π½Ρ‹Π΅
133
+ response = rotator.post(
134
+ "https://api.example.com/items",
135
+ json={"name": "New Item", "price": 99.99}
136
+ )
137
+
138
+ # Π’Π°ΠΉΠΌΠ°ΡƒΡ‚
139
+ response = rotator.get(
140
+ "https://api.example.com/data",
141
+ timeout=10
142
+ )
143
+ ```
144
+
145
+ ### ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок
146
+
147
+ ```python
148
+ from apikeyrotator import APIKeyRotator, AllKeysExhaustedError
149
+
150
+ rotator = APIKeyRotator(api_keys=["key1", "key2"], max_retries=5)
151
+
152
+ try:
153
+ response = rotator.get("https://api.example.com/limited")
154
+ print("УспСх!", response.json())
155
+ except AllKeysExhaustedError as e:
156
+ print("ВсС ΠΊΠ»ΡŽΡ‡ΠΈ исчСрпаны:", e)
157
+ except Exception as e:
158
+ print("Другая ошибка:", e)
159
+ ```
160
+
161
+ ## Π Π°ΡΡˆΠΈΡ€Π΅Π½Π½Ρ‹Π΅ настройки βš™οΈ
162
+
163
+ ### ΠšΠ°ΡΡ‚ΠΎΠΌΠΈΠ·Π°Ρ†ΠΈΡ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ²
164
+
165
+ ```python
166
+ from apikeyrotator import APIKeyRotator
167
+
168
+ # ВсС ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ настройки
169
+ rotator = APIKeyRotator(
170
+ api_keys=["key1", "key2", "key3"], # ΠšΠ»ΡŽΡ‡ΠΈ
171
+ env_var="CUSTOM_API_KEYS", # ΠšΠ°ΡΡ‚ΠΎΠΌΠ½Π°Ρ пСрСмСнная окруТСния
172
+ max_retries=5, # ΠœΠ°ΠΊΡΠΈΠΌΡƒΠΌ ΠΏΠΎΠΏΡ‹Ρ‚ΠΎΠΊ
173
+ base_delay=2.0 # Базовая Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠ° ΠΌΠ΅ΠΆΠ΄Ρƒ ΠΏΠΎΠΏΡ‹Ρ‚ΠΊΠ°ΠΌΠΈ
174
+ )
175
+
176
+ print(f"ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ ΠΊΠ»ΡŽΡ‡Π΅ΠΉ: {len(rotator)}")
177
+ print(f"ΠœΠ°ΠΊΡΠΈΠΌΡƒΠΌ ΠΏΠΎΠΏΡ‹Ρ‚ΠΎΠΊ: {rotator.max_retries}")
178
+ ```
179
+
180
+ ### Π˜Π½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΡ с ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΌ ΠΊΠΎΠ΄ΠΎΠΌ
181
+
182
+ ```python
183
+ from apikeyrotator import APIKeyRotator
184
+ import requests
185
+
186
+ # Π‘ΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ ΠΊΠΎΠ΄ с requests
187
+ response = requests.get("https://api.example.com/data")
188
+
189
+ # Π›Π΅Π³ΠΊΠΎ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚Π΅ Π½Π° APIKeyRotator
190
+ rotator = APIKeyRotator(api_keys=["key1", "key2", "key3"])
191
+ response = rotator.get("https://api.example.com/data") # Π’ΠΎΡ‚ ΠΆΠ΅ API!
192
+ ```
193
+
194
+ ## Best Practices βœ…
195
+
196
+ ### 1. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ окруТСния для бСзопасности
197
+
198
+ ```bash
199
+ # Никогда Π½Π΅ Ρ…Ρ€Π°Π½ΠΈΡ‚Π΅ ΠΊΠ»ΡŽΡ‡ΠΈ Π² ΠΊΠΎΠ΄Π΅!
200
+ # ВмСсто этого ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ .env Ρ„Π°ΠΉΠ» ΠΈΠ»ΠΈ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ окруТСния
201
+ export API_KEYS="your_production_key_1,your_production_key_2"
202
+ ```
203
+
204
+ ### 2. НастройтС Π°Π΄Π΅ΠΊΠ²Π°Ρ‚Π½ΠΎΠ΅ количСство ΠΏΠΎΠΏΡ‹Ρ‚ΠΎΠΊ
205
+
206
+ ```python
207
+ # Для 3 ΠΊΠ»ΡŽΡ‡Π΅ΠΉ ΠΈ 2 ΠΏΠΎΠΏΡ‹Ρ‚ΠΎΠΊ Π½Π° ΠΊΠ»ΡŽΡ‡ = 6 всСго ΠΏΠΎΠΏΡ‹Ρ‚ΠΎΠΊ
208
+ rotator = APIKeyRotator(
209
+ api_keys=["key1", "key2", "key3"],
210
+ max_retries=6
211
+ )
212
+ ```
213
+
214
+ ### 3. ΠœΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΠ½Π³ использования ΠΊΠ»ΡŽΡ‡Π΅ΠΉ
215
+
216
+ ```python
217
+ rotator = APIKeyRotator(api_keys=["key1", "key2", "key3"])
218
+
219
+ # ПослС Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… запросов ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ статистику
220
+ for i in range(10):
221
+ rotator.get("https://api.example.com/test")
222
+
223
+ print("Π ΠΎΡ‚Π°Ρ‚ΠΎΡ€ ΠΎΡ‚Ρ€Π°Π±ΠΎΡ‚Π°Π»", len(rotator), "запросов")
224
+ ```
225
+
226
+ ## ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок ❌
227
+
228
+ Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° прСдоставляСт понятныС сообщСния ΠΎΠ± ΠΎΡˆΠΈΠ±ΠΊΠ°Ρ…:
229
+
230
+ ### Если ΠΊΠ»ΡŽΡ‡ΠΈ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Ρ‹
231
+
232
+ ```
233
+ ❌ No API keys found.
234
+ Please either:
235
+ 1. Pass keys directly: APIKeyRotator(api_keys=['key1', 'key2'])
236
+ 2. Set environment variable: export API_KEYS='key1,key2'
237
+ 3. Create .env file with: API_KEYS=key1,key2
238
+ ```
239
+
240
+ ### Если всС ΠΊΠ»ΡŽΡ‡ΠΈ исчСрпаны
241
+
242
+ ```python
243
+ try:
244
+ response = rotator.get("https://api.example.com/limited")
245
+ except AllKeysExhaustedError as e:
246
+ print(e) # "All 3 keys exhausted after 6 attempts"
247
+ ```
248
+
249
+ ## Π‘ΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒ πŸ”„
250
+
251
+ - **Python**: 3.7+
252
+ - **Зависимости**: Ρ‚ΠΎΠ»ΡŒΠΊΠΎ `requests>=2.25.0`
253
+
254
+ ## Π Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° πŸ› οΈ
255
+
256
+ ### Установка для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ
257
+
258
+ ```bash
259
+ git clone https://github.com/PrimeevolutionZ/apikeyrotator.git
260
+ cd apikeyrotator
261
+ python -m venv venv
262
+ source venv/bin/activate # Linux/Mac
263
+ # ΠΈΠ»ΠΈ
264
+ venv\Scripts\activate # Windows
265
+ pip install -e .[dev]
266
+ ```
267
+
268
+ ### Запуск тСстов
269
+
270
+ ```bash
271
+ pytest tests/
272
+ ```
273
+
274
+ ### Π‘Π±ΠΎΡ€ΠΊΠ° ΠΏΠ°ΠΊΠ΅Ρ‚Π°
275
+
276
+ ```bash
277
+ python setup.py sdist bdist_wheel
278
+ ```
279
+
280
+ ## ЛицСнзия πŸ“„
281
+
282
+ MIT License - смотритС Ρ„Π°ΠΉΠ» [LICENSE](LICENSE) для Π΄Π΅Ρ‚Π°Π»Π΅ΠΉ.
283
+
284
+ ## ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° 🀝
285
+
286
+ Нашли Π±Π°Π³ ΠΈΠ»ΠΈ Π΅ΡΡ‚ΡŒ прСдлоТСния? [Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ issue](https://github.com/yourusername/apikeyrotator/issues) Π½Π° GitHub!
287
+
288
+ ---
289
+
290
+ **API Key Rotator** - сдСлайтС ваши API запросы нСуязвимыми ΠΊ ограничСниям! πŸš€
@@ -0,0 +1,13 @@
1
+ from .rotator import APIKeyRotator
2
+ from .exceptions import APIKeyError, NoAPIKeysError, AllKeysExhaustedError
3
+
4
+ __version__ = "0.0.2"
5
+ __author__ = "Prime Evolution"
6
+ __email__ = "develop@eclps-team.ru"
7
+
8
+ __all__ = [
9
+ 'APIKeyRotator',
10
+ 'APIKeyError',
11
+ 'NoAPIKeysError',
12
+ 'AllKeysExhaustedError'
13
+ ]
@@ -0,0 +1,11 @@
1
+ class APIKeyError(Exception):
2
+ """Π‘Π°Π·ΠΎΠ²ΠΎΠ΅ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ для ошибок API ΠΊΠ»ΡŽΡ‡Π΅ΠΉ"""
3
+ pass
4
+
5
+ class NoAPIKeysError(APIKeyError):
6
+ """НС Π½Π°ΠΉΠ΄Π΅Π½ΠΎ Π½ΠΈ ΠΎΠ΄Π½ΠΎΠ³ΠΎ API ΠΊΠ»ΡŽΡ‡Π°"""
7
+ pass
8
+
9
+ class AllKeysExhaustedError(APIKeyError):
10
+ """ВсС ΠΊΠ»ΡŽΡ‡ΠΈ исчСрпаны"""
11
+ pass
@@ -0,0 +1,162 @@
1
+ import os
2
+ import time
3
+ import requests
4
+ from typing import List, Optional, Dict, Union, Callable
5
+ from .exceptions import NoAPIKeysError, AllKeysExhaustedError
6
+
7
+
8
+ class APIKeyRotator:
9
+ """
10
+ Π‘ΡƒΠΏΠ΅Ρ€-простой Π² использовании, Π½ΠΎ ΠΌΠΎΡ‰Π½Ρ‹ΠΉ Ρ€ΠΎΡ‚Π°Ρ‚ΠΎΡ€ API ΠΊΠ»ΡŽΡ‡Π΅ΠΉ.
11
+ АвтоматичСски ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ Π»ΠΈΠΌΠΈΡ‚Ρ‹, ошибки ΠΈ Ρ€Π΅Ρ‚Ρ€Π°ΠΈ.
12
+ """
13
+
14
+ def __init__(
15
+ self,
16
+ api_keys: Optional[Union[List[str], str]] = None,
17
+ env_var: str = "API_KEYS",
18
+ max_retries: int = 3,
19
+ base_delay: float = 1.0
20
+ ):
21
+ """
22
+ ΠŸΡ€ΠΎΡΡ‚Π°Ρ инициализация - ΠΏΠ΅Ρ€Π΅Π΄Π°ΠΉ ΠΊΠ»ΡŽΡ‡ΠΈ ΠΈΠ»ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ окруТСния
23
+
24
+ :param api_keys: Бписок ΠΊΠ»ΡŽΡ‡Π΅ΠΉ ΠΈΠ»ΠΈ строка с ΠΊΠ»ΡŽΡ‡Π°ΠΌΠΈ Ρ‡Π΅Ρ€Π΅Π· Π·Π°ΠΏΡΡ‚ΡƒΡŽ
25
+ :param env_var: Имя ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ окруТСния
26
+ :param max_retries: МаксимальноС количСство ΠΏΠΎΠΏΡ‹Ρ‚ΠΎΠΊ
27
+ :param base_delay: Базовая Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠ° ΠΌΠ΅ΠΆΠ΄Ρƒ ΠΏΠΎΠΏΡ‹Ρ‚ΠΊΠ°ΠΌΠΈ
28
+ """
29
+ self.keys = self._parse_keys(api_keys, env_var)
30
+ self.max_retries = max_retries
31
+ self.base_delay = base_delay
32
+ self.current_index = 0
33
+ self.session = requests.Session()
34
+ print(f"βœ… APIKeyRotator ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½ с {len(self.keys)} ΠΊΠ»ΡŽΡ‡Π°ΠΌΠΈ")
35
+
36
+ def _parse_keys(self, api_keys, env_var) -> List[str]:
37
+ """Π£ΠΌΠ½Ρ‹ΠΉ парсинг ΠΊΠ»ΡŽΡ‡Π΅ΠΉ ΠΈΠ· Ρ€Π°Π·Π½Ρ‹Ρ… источников с понятными ошибками"""
38
+ # Если ΠΊΠ»ΡŽΡ‡ΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Ρ‹ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ
39
+ if api_keys is not None:
40
+ if isinstance(api_keys, str):
41
+ keys = [k.strip() for k in api_keys.split(",") if k.strip()]
42
+ elif isinstance(api_keys, list):
43
+ keys = api_keys
44
+ else:
45
+ raise NoAPIKeysError("❌ API keys must be a list or comma-separated string")
46
+
47
+ if not keys:
48
+ raise NoAPIKeysError("❌ No API keys provided in the api_keys parameter")
49
+
50
+ return keys
51
+
52
+ # Если ΠΊΠ»ΡŽΡ‡ΠΈ ΠΈΡ‰Π΅ΠΌ Π² ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… окруТСния
53
+ keys_str = os.getenv(env_var)
54
+
55
+ if keys_str is None:
56
+ raise NoAPIKeysError(
57
+ f"❌ No API keys found.\n"
58
+ f" Please either:\n"
59
+ f" 1. Pass keys directly: APIKeyRotator(api_keys=['key1', 'key2'])\n"
60
+ f" 2. Set environment variable: export {env_var}='key1,key2'\n"
61
+ f" 3. Create .env file with: {env_var}=key1,key2"
62
+ )
63
+
64
+ if not keys_str.strip():
65
+ raise NoAPIKeysError(
66
+ f"❌ Environment variable ${env_var} is empty.\n"
67
+ f" Please set it with: export {env_var}='your_key1,your_key2'"
68
+ )
69
+
70
+ keys = [k.strip() for k in keys_str.split(",") if k.strip()]
71
+
72
+ if not keys:
73
+ raise NoAPIKeysError(
74
+ f"❌ No valid API keys found in ${env_var}.\n"
75
+ f" Format should be: key1,key2,key3\n"
76
+ f" Current value: '{keys_str}'"
77
+ )
78
+
79
+ return keys
80
+
81
+ def get_next_key(self) -> str:
82
+ """ΠŸΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ ΠΊΠ»ΡŽΡ‡"""
83
+ key = self.keys[self.current_index]
84
+ self.current_index = (self.current_index + 1) % len(self.keys)
85
+ return key
86
+
87
+ def _should_retry(self, response: requests.Response) -> bool:
88
+ """ΠžΠΏΡ€Π΅Π΄Π΅Π»ΡΠ΅Ρ‚, Π½ΡƒΠΆΠ½ΠΎ Π»ΠΈ ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΡΡ‚ΡŒ запрос"""
89
+ return response.status_code in [429, 500, 502, 503, 504]
90
+
91
+ def _prepare_headers(self, key: str, custom_headers: dict) -> dict:
92
+ """ΠŸΠΎΠ΄Π³ΠΎΡ‚Π°Π²Π»ΠΈΠ²Π°Π΅Ρ‚ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΈ с Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠ΅ΠΉ"""
93
+ headers = custom_headers.copy() if custom_headers else {}
94
+
95
+ # АвтоматичСски опрСдСляСм Ρ‚ΠΈΠΏ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ
96
+ if "Authorization" not in headers:
97
+ if key.startswith("sk-") or key.startswith("pk-"): # OpenAI style
98
+ headers["Authorization"] = f"Bearer {key}"
99
+ elif len(key) == 32: # API key style
100
+ headers["X-API-Key"] = key
101
+ else: # Default
102
+ headers["Authorization"] = f"Key {key}"
103
+
104
+ return headers
105
+
106
+ def request(
107
+ self,
108
+ method: str,
109
+ url: str,
110
+ **kwargs
111
+ ) -> requests.Response:
112
+ """
113
+ ВыполняСт запрос. ΠŸΡ€ΠΎΡΡ‚ΠΎ ΠΊΠ°ΠΊ requests, Π½ΠΎ с Ρ€ΠΎΡ‚Π°Ρ†ΠΈΠ΅ΠΉ ΠΊΠ»ΡŽΡ‡Π΅ΠΉ!
114
+ """
115
+
116
+ for attempt in range(self.max_retries):
117
+ key = self.get_next_key()
118
+
119
+ # АвтоматичСски Π³ΠΎΡ‚ΠΎΠ²ΠΈΠΌ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΈ
120
+ kwargs['headers'] = self._prepare_headers(key, kwargs.get('headers', {}))
121
+
122
+ try:
123
+ response = self.session.request(method, url, **kwargs)
124
+
125
+ if not self._should_retry(response):
126
+ return response
127
+
128
+ print(f"↻ Attempt {attempt + 1}/{self.max_retries}. Key {key[:8]}... rate limited")
129
+
130
+ except requests.RequestException as e:
131
+ print(f"⚠️ Network error: {e}. Trying next key...")
132
+
133
+ # Π­ΠΊΡΠΏΠΎΠ½Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½Π°Ρ Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠ°
134
+ if attempt < self.max_retries - 1:
135
+ delay = self.base_delay * (2 ** attempt)
136
+ time.sleep(delay)
137
+
138
+ raise AllKeysExhaustedError(f"All {len(self.keys)} keys exhausted after {self.max_retries} attempts")
139
+
140
+ # ΠŸΡ€ΠΎΡΡ‚Π΅ΠΉΡˆΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹-ΠΎΠ±Π΅Ρ€Ρ‚ΠΊΠΈ
141
+ def get(self, url, **kwargs):
142
+ return self.request('GET', url, **kwargs)
143
+
144
+ def post(self, url, **kwargs):
145
+ return self.request('POST', url, **kwargs)
146
+
147
+ def put(self, url, **kwargs):
148
+ return self.request('PUT', url, **kwargs)
149
+
150
+ def delete(self, url, **kwargs):
151
+ return self.request('DELETE', url, **kwargs)
152
+
153
+ # Π£Π΄ΠΎΠ±Π½Ρ‹Π΅ свойства
154
+ @property
155
+ def key_count(self):
156
+ return len(self.keys)
157
+
158
+ def __len__(self):
159
+ return len(self.keys)
160
+
161
+ def __repr__(self):
162
+ return f"<APIKeyRotator keys={self.key_count} retries={self.max_retries}>"
@@ -0,0 +1,29 @@
1
+ import time
2
+ from typing import Callable, Any, Type
3
+ import requests
4
+
5
+
6
+ def retry_with_backoff(
7
+ func: Callable,
8
+ retries: int = 3,
9
+ backoff_factor: float = 0.5,
10
+ exceptions: Type[Exception] = Exception
11
+ ) -> Any:
12
+ """
13
+ Π£Π½ΠΈΠ²Π΅Ρ€ΡΠ°Π»ΡŒΠ½Π°Ρ функция для ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½Ρ‹Ρ… ΠΏΠΎΠΏΡ‹Ρ‚ΠΎΠΊ с ΡΠΊΡΠΏΠΎΠ½Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠΉ Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠΎΠΉ.
14
+
15
+ ΠŸΡ€ΠΈΠΌΠ΅Ρ€ использования:
16
+ response = retry_with_backoff(
17
+ lambda: requests.get('https://api.example.com'),
18
+ exceptions=requests.RequestException
19
+ )
20
+ """
21
+ for attempt in range(retries):
22
+ try:
23
+ return func()
24
+ except exceptions as e:
25
+ if attempt == retries - 1:
26
+ raise e
27
+ delay = backoff_factor * (2 ** attempt)
28
+ time.sleep(delay)
29
+ print(f"Retry {attempt + 1}/{retries} after {delay:.1f}s delay")
@@ -0,0 +1,335 @@
1
+ Metadata-Version: 2.4
2
+ Name: apikeyrotator
3
+ Version: 0.0.2
4
+ Summary: Ultra simple API key rotation for bypassing rate limits
5
+ Author-email: Prime Evolution <develop@eclips-team.ru>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2024 Prime Evolution
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+ Project-URL: Homepage, https://github.com/PrimeevolutionZ/apikeyrotator
28
+ Project-URL: Repository, https://github.com/PrimeevolutionZ/apikeyrotator
29
+ Project-URL: Issues, https://github.com/PrimeevolutionZ/apikeyrotator/issues
30
+ Keywords: api,rotation,rate limit,requests
31
+ Classifier: Development Status :: 4 - Beta
32
+ Classifier: Intended Audience :: Developers
33
+ Classifier: License :: OSI Approved :: MIT License
34
+ Classifier: Programming Language :: Python :: 3
35
+ Classifier: Programming Language :: Python :: 3.7
36
+ Classifier: Programming Language :: Python :: 3.8
37
+ Classifier: Programming Language :: Python :: 3.9
38
+ Classifier: Programming Language :: Python :: 3.10
39
+ Classifier: Programming Language :: Python :: 3.11
40
+ Classifier: Programming Language :: Python :: 3.12
41
+ Description-Content-Type: text/markdown
42
+ License-File: LICENSE
43
+ Requires-Dist: requests>=2.25.0
44
+ Dynamic: license-file
45
+
46
+ # API Key Rotator πŸ”„
47
+
48
+ ΠŸΡ€ΠΎΡΡ‚Π°Ρ, Π½ΠΎ мощная Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° для автоматичСского вращСния API ΠΊΠ»ΡŽΡ‡Π΅ΠΉ. ΠžΠ±Ρ…ΠΎΠ΄ΠΈΡ‚ Π»ΠΈΠΌΠΈΡ‚Ρ‹ запросов, ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ ошибки 429 ΠΈ Π΄Π΅Π»Π°Π΅Ρ‚ ваши запросы нСуязвимыми ΠΊ ограничСниям API.
49
+
50
+ ## ΠžΡΠΎΠ±Π΅Π½Π½ΠΎΡΡ‚ΠΈ ✨
51
+
52
+ - πŸ”„ **АвтоматичСскоС Π²Ρ€Π°Ρ‰Π΅Π½ΠΈΠ΅ ΠΊΠ»ΡŽΡ‡Π΅ΠΉ** - Round-robin Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ
53
+ - ⚑ **АвтодСтСкт Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ** - Π‘Π°ΠΌ опрСдСляСт Bearer/API-Key Ρ„ΠΎΡ€ΠΌΠ°Ρ‚
54
+ - πŸ” **Π£ΠΌΠ½Ρ‹Π΅ Ρ€Π΅Ρ‚Ρ€Π°ΠΈ** - Π­ΠΊΡΠΏΠΎΠ½Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½Π°Ρ Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠ° ΠΏΡ€ΠΈ ΠΎΡˆΠΈΠ±ΠΊΠ°Ρ…
55
+ - πŸ›‘οΈ **ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок** - 429, 500, 502, 503, 504 автоматичСски
56
+ - πŸ’» **Полная ΡΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒ** с Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΎΠΉ `requests`
57
+ - πŸ“ **ΠŸΠΎΠ½ΡΡ‚Π½Ρ‹Π΅ ошибки** - Подсказки ΠΊΠ°ΠΊ ΠΈΡΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹
58
+
59
+ ## Установка πŸ“¦
60
+
61
+ ```bash
62
+ pip install apikeyrotator
63
+ ```
64
+
65
+ Или ΠΈΠ· исходников:
66
+
67
+ ```bash
68
+ git clone https://github.com/PrimeevolutionZ/apikeyrotator.git
69
+ cd apikeyrotator
70
+ pip install -e .
71
+ ```
72
+
73
+ ## Быстрый старт πŸš€
74
+
75
+ ### Бпособ 1: ΠŸΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° ΠΊΠ»ΡŽΡ‡Π΅ΠΉ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ
76
+
77
+ ```python
78
+ from apikeyrotator import APIKeyRotator
79
+
80
+ # ΠŸΡ€ΠΎΡΡ‚ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°ΠΉΡ‚Π΅ ΠΊΠ»ΡŽΡ‡ΠΈ списком
81
+ rotator = APIKeyRotator(api_keys=["key1", "key2", "key3"])
82
+
83
+ # Или строкой Ρ‡Π΅Ρ€Π΅Π· Π·Π°ΠΏΡΡ‚ΡƒΡŽ
84
+ rotator = APIKeyRotator(api_keys="key1,key2,key3")
85
+
86
+ # Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ ΠΊΠ°ΠΊ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΉ requests!
87
+ response = rotator.get("https://api.example.com/data")
88
+ print(response.json())
89
+ ```
90
+
91
+ ### Бпособ 2: ИспользованиС ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… окруТСния
92
+
93
+ Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ Ρ„Π°ΠΉΠ» `.env` Π² ΠΊΠΎΡ€Π½Π΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°:
94
+ ```env
95
+ API_KEYS=your_key_1,your_key_2,your_key_3
96
+ ```
97
+
98
+ Или установитС ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ окруТСния:
99
+ ```bash
100
+ # Linux/Mac
101
+ export API_KEYS="your_key_1,your_key_2,your_key_3"
102
+
103
+ # Windows
104
+ set API_KEYS=your_key_1,your_key_2,your_key_3
105
+ ```
106
+
107
+ Π’Π΅ΠΏΠ΅Ρ€ΡŒ просто ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠΉΡ‚Π΅ Ρ€ΠΎΡ‚Π°Ρ‚ΠΎΡ€:
108
+ ```python
109
+ from apikeyrotator import APIKeyRotator
110
+
111
+ rotator = APIKeyRotator() # АвтоматичСски Π½Π°ΠΉΠ΄Π΅Ρ‚ API_KEYS
112
+
113
+ response = rotator.get("https://api.example.com/data")
114
+ ```
115
+
116
+ ## ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ использования πŸ“–
117
+
118
+ ### Π‘Π°Π·ΠΎΠ²Ρ‹Π΅ HTTP-запросы
119
+
120
+ ```python
121
+ from apikeyrotator import APIKeyRotator
122
+
123
+ rotator = APIKeyRotator(api_keys=["key1", "key2", "key3"])
124
+
125
+ # GET запрос
126
+ response = rotator.get("https://api.example.com/users")
127
+
128
+ # POST запрос с Π΄Π°Π½Π½Ρ‹ΠΌΠΈ
129
+ response = rotator.post(
130
+ "https://api.example.com/users",
131
+ json={"name": "John", "email": "john@example.com"}
132
+ )
133
+
134
+ # PUT запрос
135
+ response = rotator.put(
136
+ "https://api.example.com/users/1",
137
+ json={"name": "John Updated"}
138
+ )
139
+
140
+ # DELETE запрос
141
+ response = rotator.delete("https://api.example.com/users/1")
142
+ ```
143
+
144
+ ### ΠšΠ°ΡΡ‚ΠΎΠΌΠ½Ρ‹Π΅ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΈ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ
145
+
146
+ ```python
147
+ from apikeyrotator import APIKeyRotator
148
+
149
+ rotator = APIKeyRotator(api_keys=["key1", "key2"])
150
+
151
+ # ΠšΠ°ΡΡ‚ΠΎΠΌΠ½Ρ‹ΠΉ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ
152
+ response = rotator.get(
153
+ "https://api.example.com/data",
154
+ headers={"X-Custom-Auth": "custom_value"}
155
+ )
156
+
157
+ # Или ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚Π΅ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΡŽ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ
158
+ response = rotator.get(
159
+ "https://api.example.com/data",
160
+ headers={"Authorization": "Custom your_token_here"}
161
+ )
162
+ ```
163
+
164
+ ### Π Π°Π±ΠΎΡ‚Π° с ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°ΠΌΠΈ запроса
165
+
166
+ ```python
167
+ from apikeyrotator import APIKeyRotator
168
+
169
+ rotator = APIKeyRotator(api_keys=["key1", "key2", "key3"])
170
+
171
+ # ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ запроса
172
+ response = rotator.get(
173
+ "https://api.example.com/search",
174
+ params={"query": "python", "limit": 10}
175
+ )
176
+
177
+ # JSON Π΄Π°Π½Π½Ρ‹Π΅
178
+ response = rotator.post(
179
+ "https://api.example.com/items",
180
+ json={"name": "New Item", "price": 99.99}
181
+ )
182
+
183
+ # Π’Π°ΠΉΠΌΠ°ΡƒΡ‚
184
+ response = rotator.get(
185
+ "https://api.example.com/data",
186
+ timeout=10
187
+ )
188
+ ```
189
+
190
+ ### ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок
191
+
192
+ ```python
193
+ from apikeyrotator import APIKeyRotator, AllKeysExhaustedError
194
+
195
+ rotator = APIKeyRotator(api_keys=["key1", "key2"], max_retries=5)
196
+
197
+ try:
198
+ response = rotator.get("https://api.example.com/limited")
199
+ print("УспСх!", response.json())
200
+ except AllKeysExhaustedError as e:
201
+ print("ВсС ΠΊΠ»ΡŽΡ‡ΠΈ исчСрпаны:", e)
202
+ except Exception as e:
203
+ print("Другая ошибка:", e)
204
+ ```
205
+
206
+ ## Π Π°ΡΡˆΠΈΡ€Π΅Π½Π½Ρ‹Π΅ настройки βš™οΈ
207
+
208
+ ### ΠšΠ°ΡΡ‚ΠΎΠΌΠΈΠ·Π°Ρ†ΠΈΡ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ²
209
+
210
+ ```python
211
+ from apikeyrotator import APIKeyRotator
212
+
213
+ # ВсС ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ настройки
214
+ rotator = APIKeyRotator(
215
+ api_keys=["key1", "key2", "key3"], # ΠšΠ»ΡŽΡ‡ΠΈ
216
+ env_var="CUSTOM_API_KEYS", # ΠšΠ°ΡΡ‚ΠΎΠΌΠ½Π°Ρ пСрСмСнная окруТСния
217
+ max_retries=5, # ΠœΠ°ΠΊΡΠΈΠΌΡƒΠΌ ΠΏΠΎΠΏΡ‹Ρ‚ΠΎΠΊ
218
+ base_delay=2.0 # Базовая Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠ° ΠΌΠ΅ΠΆΠ΄Ρƒ ΠΏΠΎΠΏΡ‹Ρ‚ΠΊΠ°ΠΌΠΈ
219
+ )
220
+
221
+ print(f"ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ ΠΊΠ»ΡŽΡ‡Π΅ΠΉ: {len(rotator)}")
222
+ print(f"ΠœΠ°ΠΊΡΠΈΠΌΡƒΠΌ ΠΏΠΎΠΏΡ‹Ρ‚ΠΎΠΊ: {rotator.max_retries}")
223
+ ```
224
+
225
+ ### Π˜Π½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΡ с ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΌ ΠΊΠΎΠ΄ΠΎΠΌ
226
+
227
+ ```python
228
+ from apikeyrotator import APIKeyRotator
229
+ import requests
230
+
231
+ # Π‘ΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ ΠΊΠΎΠ΄ с requests
232
+ response = requests.get("https://api.example.com/data")
233
+
234
+ # Π›Π΅Π³ΠΊΠΎ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚Π΅ Π½Π° APIKeyRotator
235
+ rotator = APIKeyRotator(api_keys=["key1", "key2", "key3"])
236
+ response = rotator.get("https://api.example.com/data") # Π’ΠΎΡ‚ ΠΆΠ΅ API!
237
+ ```
238
+
239
+ ## Best Practices βœ…
240
+
241
+ ### 1. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ окруТСния для бСзопасности
242
+
243
+ ```bash
244
+ # Никогда Π½Π΅ Ρ…Ρ€Π°Π½ΠΈΡ‚Π΅ ΠΊΠ»ΡŽΡ‡ΠΈ Π² ΠΊΠΎΠ΄Π΅!
245
+ # ВмСсто этого ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ .env Ρ„Π°ΠΉΠ» ΠΈΠ»ΠΈ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ окруТСния
246
+ export API_KEYS="your_production_key_1,your_production_key_2"
247
+ ```
248
+
249
+ ### 2. НастройтС Π°Π΄Π΅ΠΊΠ²Π°Ρ‚Π½ΠΎΠ΅ количСство ΠΏΠΎΠΏΡ‹Ρ‚ΠΎΠΊ
250
+
251
+ ```python
252
+ # Для 3 ΠΊΠ»ΡŽΡ‡Π΅ΠΉ ΠΈ 2 ΠΏΠΎΠΏΡ‹Ρ‚ΠΎΠΊ Π½Π° ΠΊΠ»ΡŽΡ‡ = 6 всСго ΠΏΠΎΠΏΡ‹Ρ‚ΠΎΠΊ
253
+ rotator = APIKeyRotator(
254
+ api_keys=["key1", "key2", "key3"],
255
+ max_retries=6
256
+ )
257
+ ```
258
+
259
+ ### 3. ΠœΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΠ½Π³ использования ΠΊΠ»ΡŽΡ‡Π΅ΠΉ
260
+
261
+ ```python
262
+ rotator = APIKeyRotator(api_keys=["key1", "key2", "key3"])
263
+
264
+ # ПослС Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… запросов ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ статистику
265
+ for i in range(10):
266
+ rotator.get("https://api.example.com/test")
267
+
268
+ print("Π ΠΎΡ‚Π°Ρ‚ΠΎΡ€ ΠΎΡ‚Ρ€Π°Π±ΠΎΡ‚Π°Π»", len(rotator), "запросов")
269
+ ```
270
+
271
+ ## ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок ❌
272
+
273
+ Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° прСдоставляСт понятныС сообщСния ΠΎΠ± ΠΎΡˆΠΈΠ±ΠΊΠ°Ρ…:
274
+
275
+ ### Если ΠΊΠ»ΡŽΡ‡ΠΈ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Ρ‹
276
+
277
+ ```
278
+ ❌ No API keys found.
279
+ Please either:
280
+ 1. Pass keys directly: APIKeyRotator(api_keys=['key1', 'key2'])
281
+ 2. Set environment variable: export API_KEYS='key1,key2'
282
+ 3. Create .env file with: API_KEYS=key1,key2
283
+ ```
284
+
285
+ ### Если всС ΠΊΠ»ΡŽΡ‡ΠΈ исчСрпаны
286
+
287
+ ```python
288
+ try:
289
+ response = rotator.get("https://api.example.com/limited")
290
+ except AllKeysExhaustedError as e:
291
+ print(e) # "All 3 keys exhausted after 6 attempts"
292
+ ```
293
+
294
+ ## Π‘ΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒ πŸ”„
295
+
296
+ - **Python**: 3.7+
297
+ - **Зависимости**: Ρ‚ΠΎΠ»ΡŒΠΊΠΎ `requests>=2.25.0`
298
+
299
+ ## Π Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° πŸ› οΈ
300
+
301
+ ### Установка для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ
302
+
303
+ ```bash
304
+ git clone https://github.com/PrimeevolutionZ/apikeyrotator.git
305
+ cd apikeyrotator
306
+ python -m venv venv
307
+ source venv/bin/activate # Linux/Mac
308
+ # ΠΈΠ»ΠΈ
309
+ venv\Scripts\activate # Windows
310
+ pip install -e .[dev]
311
+ ```
312
+
313
+ ### Запуск тСстов
314
+
315
+ ```bash
316
+ pytest tests/
317
+ ```
318
+
319
+ ### Π‘Π±ΠΎΡ€ΠΊΠ° ΠΏΠ°ΠΊΠ΅Ρ‚Π°
320
+
321
+ ```bash
322
+ python setup.py sdist bdist_wheel
323
+ ```
324
+
325
+ ## ЛицСнзия πŸ“„
326
+
327
+ MIT License - смотритС Ρ„Π°ΠΉΠ» [LICENSE](LICENSE) для Π΄Π΅Ρ‚Π°Π»Π΅ΠΉ.
328
+
329
+ ## ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° 🀝
330
+
331
+ Нашли Π±Π°Π³ ΠΈΠ»ΠΈ Π΅ΡΡ‚ΡŒ прСдлоТСния? [Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ issue](https://github.com/yourusername/apikeyrotator/issues) Π½Π° GitHub!
332
+
333
+ ---
334
+
335
+ **API Key Rotator** - сдСлайтС ваши API запросы нСуязвимыми ΠΊ ограничСниям! πŸš€
@@ -0,0 +1,12 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ apikeyrotator/__init__.py
5
+ apikeyrotator/exceptions.py
6
+ apikeyrotator/rotator.py
7
+ apikeyrotator/utils.py
8
+ apikeyrotator.egg-info/PKG-INFO
9
+ apikeyrotator.egg-info/SOURCES.txt
10
+ apikeyrotator.egg-info/dependency_links.txt
11
+ apikeyrotator.egg-info/requires.txt
12
+ apikeyrotator.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ requests>=2.25.0
@@ -0,0 +1 @@
1
+ apikeyrotator
@@ -0,0 +1,32 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "apikeyrotator"
7
+ version = "0.0.2"
8
+ description = "Ultra simple API key rotation for bypassing rate limits"
9
+ readme = "README.md"
10
+ authors = [
11
+ { name = "Prime Evolution", email = "develop@eclips-team.ru" }
12
+ ]
13
+ license = { file = "LICENSE" }
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.7",
20
+ "Programming Language :: Python :: 3.8",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ ]
26
+ keywords = ["api", "rotation", "rate limit", "requests"]
27
+ dependencies = ["requests>=2.25.0"]
28
+
29
+ [project.urls]
30
+ Homepage = "https://github.com/PrimeevolutionZ/apikeyrotator"
31
+ Repository = "https://github.com/PrimeevolutionZ/apikeyrotator"
32
+ Issues = "https://github.com/PrimeevolutionZ/apikeyrotator/issues"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+