completcha 1.0.0__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.
- completcha-1.0.0/LICENSE +21 -0
- completcha-1.0.0/PKG-INFO +192 -0
- completcha-1.0.0/README.md +168 -0
- completcha-1.0.0/completcha/__init__.py +143 -0
- completcha-1.0.0/completcha/exceptions.py +22 -0
- completcha-1.0.0/completcha/logger_print/__init__.py +35 -0
- completcha-1.0.0/completcha.egg-info/PKG-INFO +192 -0
- completcha-1.0.0/completcha.egg-info/SOURCES.txt +11 -0
- completcha-1.0.0/completcha.egg-info/dependency_links.txt +1 -0
- completcha-1.0.0/completcha.egg-info/requires.txt +2 -0
- completcha-1.0.0/completcha.egg-info/top_level.txt +2 -0
- completcha-1.0.0/pyproject.toml +28 -0
- completcha-1.0.0/setup.cfg +4 -0
completcha-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Completcha
|
|
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,192 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: completcha
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Captcha Solver
|
|
5
|
+
Author: Completcha
|
|
6
|
+
Author-email: support@completcha.com
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://completcha.com
|
|
9
|
+
Project-URL: Repository, https://github.com/completcha/completcha-python
|
|
10
|
+
Keywords: completcha,captcha,solver,api,token,captcha solver,funcaptcha,arkose,funcaptcha solver,arkose solver,x,twitter,twitter captcha,x captcha,arkose token,funcaptcha token
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Natural Language :: English
|
|
16
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Requires-Python: >=3.12.1
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: requests
|
|
22
|
+
Requires-Dist: colorama
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
# 🚀 Completcha
|
|
26
|
+
|
|
27
|
+
Python library for solving **Arkose Labs / FunCaptcha** challenges, built to deliver **high success rates, speed, and real-world reliability in production**.
|
|
28
|
+
|
|
29
|
+
### [Free trial for new users on completcha.com](https://completcha.com)
|
|
30
|
+
|
|
31
|
+
Unlike traditional approaches, **Completcha** was designed to solve the most common problems faced when dealing with captchas:
|
|
32
|
+
|
|
33
|
+
- ❌ Challenges that never get solved
|
|
34
|
+
- ⏳ Long waiting times for responses
|
|
35
|
+
- 🔁 Constant need to generate new captcha URLs
|
|
36
|
+
- 🚫 Limited attempts per challenge
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 💡 Key Advantages
|
|
41
|
+
|
|
42
|
+
### 🚀 Bypass Resolution (Main Advantage)
|
|
43
|
+
|
|
44
|
+
The biggest advantage of Completcha is its **full Arkose bypass capability**.
|
|
45
|
+
|
|
46
|
+
- Most challenges are solved **without requiring image solving**
|
|
47
|
+
- The system accurately replicates real browser behavior
|
|
48
|
+
- This results in:
|
|
49
|
+
- ⚡ Much faster responses
|
|
50
|
+
- 🎯 Extremely high success rates
|
|
51
|
+
- 🔄 Reduced need to generate new challenges
|
|
52
|
+
|
|
53
|
+
👉 In practice, this eliminates the most frustrating issue: waiting for a captcha that often never gets solved.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
### 🖼️ Image Solving with Smart Retries
|
|
58
|
+
|
|
59
|
+
When bypass is not possible (e.g., using rotating proxies), Completcha still stands out:
|
|
60
|
+
|
|
61
|
+
- 🔁 Performs **all necessary retries automatically**
|
|
62
|
+
- 🧠 Designed to handle harder image challenges
|
|
63
|
+
- 📉 Significantly reduces failure rates
|
|
64
|
+
- ♻️ Avoids the need to generate new captcha URLs
|
|
65
|
+
|
|
66
|
+
Additionally:
|
|
67
|
+
|
|
68
|
+
- Full integration with Arkose's original flow ensures:
|
|
69
|
+
- Fewer images are generated
|
|
70
|
+
- Behavior closely matches a real browser
|
|
71
|
+
|
|
72
|
+
👉 Result: **one of the highest solving success rates on the market**, even in difficult scenarios.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 📦 Installation
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install completcha
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 🔐 Solving Methods
|
|
85
|
+
|
|
86
|
+
**Completcha** provides two main methods for solving Arkose challenges:
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
### 🚀 1. Bypass (Recommended)
|
|
91
|
+
|
|
92
|
+
The fastest and most reliable method.
|
|
93
|
+
|
|
94
|
+
**How it works:**
|
|
95
|
+
- The Arkose challenge URL must be requested using a **fixed proxy**
|
|
96
|
+
- The solution is executed on the **same IP as the request**
|
|
97
|
+
- No images need to be solved
|
|
98
|
+
|
|
99
|
+
**Advantages:**
|
|
100
|
+
- ⚡ High speed
|
|
101
|
+
- 🎯 Maximum reliability
|
|
102
|
+
- 🧠 No image solving required
|
|
103
|
+
|
|
104
|
+
⚠️ **Important:**
|
|
105
|
+
- Use **fixed (dedicated) proxies**
|
|
106
|
+
- **Do NOT use sticky proxies**
|
|
107
|
+
|
|
108
|
+
> ❗ Sticky proxies will change IP addresses because they depend on the same source IP address to remain static since your source IP address is different from ours in the resolution side.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
### 🖼️ 2. Image Solving
|
|
113
|
+
|
|
114
|
+
Used when bypass is not possible.
|
|
115
|
+
|
|
116
|
+
**When it happens:**
|
|
117
|
+
- When using **rotating proxies**
|
|
118
|
+
- The request IP differs from the solving IP
|
|
119
|
+
|
|
120
|
+
**Features:**
|
|
121
|
+
- 🧩 Automatically solves any image challenge
|
|
122
|
+
- 📊 Real-time logs for tracking progress
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## ⚙️ Best Practices
|
|
127
|
+
|
|
128
|
+
- ✅ Use the **same User-Agent** from the original request
|
|
129
|
+
- ♻️ Reuse the same API instance (avoids rate limiting)
|
|
130
|
+
- 🔒 Prefer fixed proxies for best performance
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 💻 Example Usage
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from completcha import SolverApi
|
|
138
|
+
|
|
139
|
+
# Instantiate only once to maintain same completcha session to avoid rate limit
|
|
140
|
+
completcha_session = SolverApi(
|
|
141
|
+
api_key='xxx-xxxx-xxx-xxx-xxxx-xxx',
|
|
142
|
+
show_logs=True
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
arkose_data = 'Q9xL2mVtF8yZk/rW.JpG4aH6uSnoqLDEBvCwR5Xf3sYt0ZlN8Peu/jK3qTz7rVbA1MHi9UdWcE2Ox+gFJYnKsL0QpR4t6BvXy7zN5hMeCq8GjAfD3uWPlZrT1n/SoIkVxYcE2mH7F9QaUpbXgRZK5V3nTtLj8wQh4Gv0p2fMsYkJ6CDeaI1Xo7r8s9NwBtU5lE3ZcHyPgQfO2uV1dKjSxA7mW9bL0FvRzJq6YH3XcD8tUpnK5wIeM4aG2ZQh7sVb9C0fYkT1xP8LrNwD3mE6uJgS2AqXv5oFz+HyR8c7LkW9p0VJtN3ZbGdE6xF2aQs8UoYhP1rM4iTnK7wC5vLzX9qD2jH0BfE3R6gPZs1yN4t8uAqI5WcKXoM7dVhFzYJ2bL9xC6rT3gUpvSnQ0='
|
|
146
|
+
proxy = 'proxyusername:proxypassword@proxyhost:proxyport'
|
|
147
|
+
site_key = '2CB16598-CB82-4CF7-B332-5990DB66F3AB'
|
|
148
|
+
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36'
|
|
149
|
+
|
|
150
|
+
solved_token_arkose = completcha_session.arkose(
|
|
151
|
+
arkose_data,
|
|
152
|
+
proxy,
|
|
153
|
+
site_key,
|
|
154
|
+
user_agent
|
|
155
|
+
)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Return Solved Token
|
|
159
|
+
```
|
|
160
|
+
70103a5dafe122e18.1833610001|r=us-east-1|meta=3|meta_width=558|meta_height=523|metabgclr=transparent|metaiconclr=%23555555|guitextcolor=%23000000|pk=2CB16598-CB82-4CF7-B332-5990DB66F3AB|at=30|ag=201|cdn_url=https%3A%2F%2Fclient-api.arkoselabs.com%2Fcdn%2Ffc|surl=https%3A%2F%2Fclient-api.arkoselabs.com|smurl=https%3A%2F%2Fclient-api.arkoselabs.com%2Fcdn%2Ffc%2Fassets%2Fstyle-manager
|
|
161
|
+
```
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## ⭐ Method Comparison
|
|
165
|
+
|
|
166
|
+
| Method | Speed | Reliability |
|
|
167
|
+
|--------------------|----------|------------|
|
|
168
|
+
| 🚀 Bypass | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
|
|
169
|
+
| 🖼️ Image Solving | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 🏆 Final Recommendation
|
|
174
|
+
|
|
175
|
+
- 🚀 **Bypass** → ⭐⭐⭐⭐⭐ (Best overall choice)
|
|
176
|
+
- 🖼️ **Image** → ⭐⭐⭐⭐
|
|
177
|
+
|
|
178
|
+
✔ Always prefer **bypass with fixed proxies** for optimal performance.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 💬 Community & Support
|
|
183
|
+
|
|
184
|
+
<p align="center">
|
|
185
|
+
<a href="https://discord.gg/cdgHgF2ySG">
|
|
186
|
+
<img src="https://img.shields.io/badge/Join%20our%20Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white" alt="Discord">
|
|
187
|
+
</a>
|
|
188
|
+
</p>
|
|
189
|
+
|
|
190
|
+
<p align="center">
|
|
191
|
+
Join the community for support, updates, and discussions 🚀
|
|
192
|
+
</p>
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# 🚀 Completcha
|
|
2
|
+
|
|
3
|
+
Python library for solving **Arkose Labs / FunCaptcha** challenges, built to deliver **high success rates, speed, and real-world reliability in production**.
|
|
4
|
+
|
|
5
|
+
### [Free trial for new users on completcha.com](https://completcha.com)
|
|
6
|
+
|
|
7
|
+
Unlike traditional approaches, **Completcha** was designed to solve the most common problems faced when dealing with captchas:
|
|
8
|
+
|
|
9
|
+
- ❌ Challenges that never get solved
|
|
10
|
+
- ⏳ Long waiting times for responses
|
|
11
|
+
- 🔁 Constant need to generate new captcha URLs
|
|
12
|
+
- 🚫 Limited attempts per challenge
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 💡 Key Advantages
|
|
17
|
+
|
|
18
|
+
### 🚀 Bypass Resolution (Main Advantage)
|
|
19
|
+
|
|
20
|
+
The biggest advantage of Completcha is its **full Arkose bypass capability**.
|
|
21
|
+
|
|
22
|
+
- Most challenges are solved **without requiring image solving**
|
|
23
|
+
- The system accurately replicates real browser behavior
|
|
24
|
+
- This results in:
|
|
25
|
+
- ⚡ Much faster responses
|
|
26
|
+
- 🎯 Extremely high success rates
|
|
27
|
+
- 🔄 Reduced need to generate new challenges
|
|
28
|
+
|
|
29
|
+
👉 In practice, this eliminates the most frustrating issue: waiting for a captcha that often never gets solved.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
### 🖼️ Image Solving with Smart Retries
|
|
34
|
+
|
|
35
|
+
When bypass is not possible (e.g., using rotating proxies), Completcha still stands out:
|
|
36
|
+
|
|
37
|
+
- 🔁 Performs **all necessary retries automatically**
|
|
38
|
+
- 🧠 Designed to handle harder image challenges
|
|
39
|
+
- 📉 Significantly reduces failure rates
|
|
40
|
+
- ♻️ Avoids the need to generate new captcha URLs
|
|
41
|
+
|
|
42
|
+
Additionally:
|
|
43
|
+
|
|
44
|
+
- Full integration with Arkose's original flow ensures:
|
|
45
|
+
- Fewer images are generated
|
|
46
|
+
- Behavior closely matches a real browser
|
|
47
|
+
|
|
48
|
+
👉 Result: **one of the highest solving success rates on the market**, even in difficult scenarios.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 📦 Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install completcha
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 🔐 Solving Methods
|
|
61
|
+
|
|
62
|
+
**Completcha** provides two main methods for solving Arkose challenges:
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
### 🚀 1. Bypass (Recommended)
|
|
67
|
+
|
|
68
|
+
The fastest and most reliable method.
|
|
69
|
+
|
|
70
|
+
**How it works:**
|
|
71
|
+
- The Arkose challenge URL must be requested using a **fixed proxy**
|
|
72
|
+
- The solution is executed on the **same IP as the request**
|
|
73
|
+
- No images need to be solved
|
|
74
|
+
|
|
75
|
+
**Advantages:**
|
|
76
|
+
- ⚡ High speed
|
|
77
|
+
- 🎯 Maximum reliability
|
|
78
|
+
- 🧠 No image solving required
|
|
79
|
+
|
|
80
|
+
⚠️ **Important:**
|
|
81
|
+
- Use **fixed (dedicated) proxies**
|
|
82
|
+
- **Do NOT use sticky proxies**
|
|
83
|
+
|
|
84
|
+
> ❗ Sticky proxies will change IP addresses because they depend on the same source IP address to remain static since your source IP address is different from ours in the resolution side.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
### 🖼️ 2. Image Solving
|
|
89
|
+
|
|
90
|
+
Used when bypass is not possible.
|
|
91
|
+
|
|
92
|
+
**When it happens:**
|
|
93
|
+
- When using **rotating proxies**
|
|
94
|
+
- The request IP differs from the solving IP
|
|
95
|
+
|
|
96
|
+
**Features:**
|
|
97
|
+
- 🧩 Automatically solves any image challenge
|
|
98
|
+
- 📊 Real-time logs for tracking progress
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## ⚙️ Best Practices
|
|
103
|
+
|
|
104
|
+
- ✅ Use the **same User-Agent** from the original request
|
|
105
|
+
- ♻️ Reuse the same API instance (avoids rate limiting)
|
|
106
|
+
- 🔒 Prefer fixed proxies for best performance
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 💻 Example Usage
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from completcha import SolverApi
|
|
114
|
+
|
|
115
|
+
# Instantiate only once to maintain same completcha session to avoid rate limit
|
|
116
|
+
completcha_session = SolverApi(
|
|
117
|
+
api_key='xxx-xxxx-xxx-xxx-xxxx-xxx',
|
|
118
|
+
show_logs=True
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
arkose_data = 'Q9xL2mVtF8yZk/rW.JpG4aH6uSnoqLDEBvCwR5Xf3sYt0ZlN8Peu/jK3qTz7rVbA1MHi9UdWcE2Ox+gFJYnKsL0QpR4t6BvXy7zN5hMeCq8GjAfD3uWPlZrT1n/SoIkVxYcE2mH7F9QaUpbXgRZK5V3nTtLj8wQh4Gv0p2fMsYkJ6CDeaI1Xo7r8s9NwBtU5lE3ZcHyPgQfO2uV1dKjSxA7mW9bL0FvRzJq6YH3XcD8tUpnK5wIeM4aG2ZQh7sVb9C0fYkT1xP8LrNwD3mE6uJgS2AqXv5oFz+HyR8c7LkW9p0VJtN3ZbGdE6xF2aQs8UoYhP1rM4iTnK7wC5vLzX9qD2jH0BfE3R6gPZs1yN4t8uAqI5WcKXoM7dVhFzYJ2bL9xC6rT3gUpvSnQ0='
|
|
122
|
+
proxy = 'proxyusername:proxypassword@proxyhost:proxyport'
|
|
123
|
+
site_key = '2CB16598-CB82-4CF7-B332-5990DB66F3AB'
|
|
124
|
+
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36'
|
|
125
|
+
|
|
126
|
+
solved_token_arkose = completcha_session.arkose(
|
|
127
|
+
arkose_data,
|
|
128
|
+
proxy,
|
|
129
|
+
site_key,
|
|
130
|
+
user_agent
|
|
131
|
+
)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Return Solved Token
|
|
135
|
+
```
|
|
136
|
+
70103a5dafe122e18.1833610001|r=us-east-1|meta=3|meta_width=558|meta_height=523|metabgclr=transparent|metaiconclr=%23555555|guitextcolor=%23000000|pk=2CB16598-CB82-4CF7-B332-5990DB66F3AB|at=30|ag=201|cdn_url=https%3A%2F%2Fclient-api.arkoselabs.com%2Fcdn%2Ffc|surl=https%3A%2F%2Fclient-api.arkoselabs.com|smurl=https%3A%2F%2Fclient-api.arkoselabs.com%2Fcdn%2Ffc%2Fassets%2Fstyle-manager
|
|
137
|
+
```
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## ⭐ Method Comparison
|
|
141
|
+
|
|
142
|
+
| Method | Speed | Reliability |
|
|
143
|
+
|--------------------|----------|------------|
|
|
144
|
+
| 🚀 Bypass | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
|
|
145
|
+
| 🖼️ Image Solving | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## 🏆 Final Recommendation
|
|
150
|
+
|
|
151
|
+
- 🚀 **Bypass** → ⭐⭐⭐⭐⭐ (Best overall choice)
|
|
152
|
+
- 🖼️ **Image** → ⭐⭐⭐⭐
|
|
153
|
+
|
|
154
|
+
✔ Always prefer **bypass with fixed proxies** for optimal performance.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## 💬 Community & Support
|
|
159
|
+
|
|
160
|
+
<p align="center">
|
|
161
|
+
<a href="https://discord.gg/cdgHgF2ySG">
|
|
162
|
+
<img src="https://img.shields.io/badge/Join%20our%20Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white" alt="Discord">
|
|
163
|
+
</a>
|
|
164
|
+
</p>
|
|
165
|
+
|
|
166
|
+
<p align="center">
|
|
167
|
+
Join the community for support, updates, and discussions 🚀
|
|
168
|
+
</p>
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from requests.exceptions import HTTPError, ConnectTimeout
|
|
3
|
+
import time
|
|
4
|
+
import random
|
|
5
|
+
from completcha.logger_print import SimpleLogger
|
|
6
|
+
from completcha.exceptions import *
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SolverApi:
|
|
10
|
+
def __init__(self, api_key: str, show_logs: bool = False):
|
|
11
|
+
self._show_log: bool = show_logs
|
|
12
|
+
self._apikeycompletcha: str = api_key
|
|
13
|
+
if self._show_log:
|
|
14
|
+
self._log = SimpleLogger(level=SimpleLogger.DEBUG, name='COMPLETCHA')
|
|
15
|
+
else:
|
|
16
|
+
self._log = SimpleLogger(level=SimpleLogger.DISABLED)
|
|
17
|
+
self.session = requests.session()
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def _verify_new_update(json_response):
|
|
21
|
+
detail = json_response.get('detail') or []
|
|
22
|
+
if (
|
|
23
|
+
isinstance(detail, list) and
|
|
24
|
+
len(detail) > 0 and
|
|
25
|
+
isinstance(detail[0], dict) and
|
|
26
|
+
detail[0].get("type") == "missing" and
|
|
27
|
+
isinstance(detail[0].get("loc"), list) and
|
|
28
|
+
len(detail[0]["loc"]) > 0 and
|
|
29
|
+
detail[0]["loc"][0] == "body"
|
|
30
|
+
):
|
|
31
|
+
|
|
32
|
+
raise DeprecatedLibrary(f"New parameter \033[31;4m{detail[0]["loc"][1]}\033[0m required in the payload. Update to the latest version of the completcha library.")
|
|
33
|
+
|
|
34
|
+
def _request_with_retry(self, func, max_retries=5, base_delay=1):
|
|
35
|
+
for attempt in range(1, max_retries + 1):
|
|
36
|
+
try:
|
|
37
|
+
return func()
|
|
38
|
+
|
|
39
|
+
except ConnectTimeout as err:
|
|
40
|
+
delay = base_delay * (2 ** (attempt - 1))
|
|
41
|
+
jitter = random.uniform(0, 0.5)
|
|
42
|
+
final_delay = delay + jitter
|
|
43
|
+
|
|
44
|
+
self._log.warning(
|
|
45
|
+
f"Attempt {attempt}/{max_retries} to connect to the server failed: {err} | waiting {final_delay:.2f}s"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
time.sleep(final_delay)
|
|
49
|
+
|
|
50
|
+
raise MaxRetriesServerExceeded("Maximum number of attempts to connect to the server reached")
|
|
51
|
+
|
|
52
|
+
def arkose(self, arkose_data_blob: str, proxy: str, public_key: str, user_agent: str | None = None) -> str:
|
|
53
|
+
"""
|
|
54
|
+
Creates an Arkose resolution task and returns the resolved token.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
arkose_data_blob (str): Parameter data blob.
|
|
58
|
+
proxy (str): Proxy in the format username:password@host:port.
|
|
59
|
+
public_key (str): The public key.
|
|
60
|
+
user_agent (str, optional): The User-Agent to be used. Defaults to None.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
str: The resolved challenge token.
|
|
64
|
+
"""
|
|
65
|
+
if not self._apikeycompletcha or not isinstance(self._apikeycompletcha, str):
|
|
66
|
+
raise MissingApiKey(
|
|
67
|
+
"Invalid configuration: 'SolverApi()._apikeycompletcha' must be set to a valid string API key before calling SolverApi methods.")
|
|
68
|
+
|
|
69
|
+
root_path = 'demoarkose'
|
|
70
|
+
payload_create_task = {"datablob": arkose_data_blob, "user_agent": user_agent, "proxy": proxy,
|
|
71
|
+
"public_key": public_key}
|
|
72
|
+
|
|
73
|
+
create_task_url = f'https://api.completcha.com/{root_path}/task/create'
|
|
74
|
+
get_status_url = f'https://api.completcha.com/{root_path}/task/status/'
|
|
75
|
+
|
|
76
|
+
headers_solver = {'x-api-key': self._apikeycompletcha}
|
|
77
|
+
|
|
78
|
+
def post_request(url, payload):
|
|
79
|
+
return self._request_with_retry(lambda: self.session.post(
|
|
80
|
+
url,
|
|
81
|
+
headers=headers_solver,
|
|
82
|
+
json=payload
|
|
83
|
+
))
|
|
84
|
+
|
|
85
|
+
def get_request(url: str, task_id_passed: str):
|
|
86
|
+
return self._request_with_retry(lambda: self.session.get(
|
|
87
|
+
url + task_id_passed,
|
|
88
|
+
headers=headers_solver
|
|
89
|
+
))
|
|
90
|
+
|
|
91
|
+
# Criar Tarefa
|
|
92
|
+
name_show = 'Arkose'
|
|
93
|
+
print(f"Requesting {name_show} Token in Completcha Solver ...")
|
|
94
|
+
response_create_task = post_request(create_task_url, payload_create_task)
|
|
95
|
+
status_response_create_task = response_create_task.status_code
|
|
96
|
+
text_response_create_task = response_create_task.text
|
|
97
|
+
self._log.debug(f"Status: {status_response_create_task}, Text: {text_response_create_task} ...")
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
response_create_task.raise_for_status()
|
|
101
|
+
except HTTPError as e:
|
|
102
|
+
if e.response.status_code == 422:
|
|
103
|
+
if "application/json" in e.response.headers.get("Content-Type", ""):
|
|
104
|
+
json_error_res = e.response.json()
|
|
105
|
+
self._verify_new_update(json_error_res)
|
|
106
|
+
raise ServerError(
|
|
107
|
+
f'Error when trying to create a task >>\nStatus Code Error: {e.response.status_code}, Response: {e.response.text}')
|
|
108
|
+
|
|
109
|
+
json_response_create_task = response_create_task.json()
|
|
110
|
+
task_id = json_response_create_task["task_id"]
|
|
111
|
+
|
|
112
|
+
print_result = None
|
|
113
|
+
# Aguardar Resolução
|
|
114
|
+
while True:
|
|
115
|
+
response_status_resolution = get_request(get_status_url, task_id)
|
|
116
|
+
text_response_status_resolution = response_status_resolution.text
|
|
117
|
+
|
|
118
|
+
if not print_result == text_response_status_resolution:
|
|
119
|
+
print_result = text_response_status_resolution
|
|
120
|
+
self._log.debug(f"{print_result} ...")
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
response_status_resolution.raise_for_status()
|
|
124
|
+
except HTTPError as e:
|
|
125
|
+
raise ServerError(
|
|
126
|
+
f'Error when trying to get the task response >>\nStatus Code Error: {e.response.status_code}, Response: {e.response.text}')
|
|
127
|
+
|
|
128
|
+
json_response_status_resolution = response_status_resolution.json()
|
|
129
|
+
if json_response_status_resolution['status'] == 'completed':
|
|
130
|
+
token_solved = json_response_status_resolution['result']
|
|
131
|
+
print(f"{name_show} challenge completed", token_solved)
|
|
132
|
+
return token_solved
|
|
133
|
+
elif json_response_status_resolution['status'] == 'failed':
|
|
134
|
+
raise SolverApiError(f"Error in {name_show} challenge solution: {json_response_status_resolution['result']}")
|
|
135
|
+
elif json_response_status_resolution['status'] in ('in resolution', 'pending'):
|
|
136
|
+
time.sleep(1.2)
|
|
137
|
+
else:
|
|
138
|
+
raise ProgrammerError(
|
|
139
|
+
f"The response status does not match any programmed criteria: {json_response_status_resolution}")
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
if __name__ == '__main__':
|
|
143
|
+
breakpoint()
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class SolverApiError(Exception):
|
|
2
|
+
pass
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class MissingApiKey(Exception):
|
|
6
|
+
pass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ProgrammerError(Exception):
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ServerError(Exception):
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MaxRetriesServerExceeded(Exception):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DeprecatedLibrary(Exception):
|
|
22
|
+
pass
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from colorama import Fore, Style, init
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class SimpleLogger:
|
|
6
|
+
DEBUG = 10
|
|
7
|
+
INFO = 20
|
|
8
|
+
WARNING = 30
|
|
9
|
+
DISABLED = 100
|
|
10
|
+
|
|
11
|
+
def __init__(self, level=INFO, name: str | None = None):
|
|
12
|
+
self.level = level
|
|
13
|
+
self.name = name
|
|
14
|
+
init()
|
|
15
|
+
|
|
16
|
+
def set_level(self, level):
|
|
17
|
+
self.level = level
|
|
18
|
+
|
|
19
|
+
def _display(self, label, message, color):
|
|
20
|
+
timestamp = datetime.now().strftime("%H:%M:%S.%f")[:-3]
|
|
21
|
+
if self.name:
|
|
22
|
+
label = self.name + "] [" + label
|
|
23
|
+
print(f"{color}[{timestamp}] [{label}] {message}{Style.RESET_ALL}", flush=True)
|
|
24
|
+
|
|
25
|
+
def debug(self, message):
|
|
26
|
+
if self.level <= self.DEBUG:
|
|
27
|
+
self._display("DEBUG", message, Fore.LIGHTGREEN_EX)
|
|
28
|
+
|
|
29
|
+
def info(self, message):
|
|
30
|
+
if self.level <= self.INFO:
|
|
31
|
+
self._display("INFO", message, Fore.LIGHTBLUE_EX)
|
|
32
|
+
|
|
33
|
+
def warning(self, message):
|
|
34
|
+
if self.level <= self.WARNING:
|
|
35
|
+
self._display("WARNING", message, Fore.LIGHTRED_EX)
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: completcha
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Captcha Solver
|
|
5
|
+
Author: Completcha
|
|
6
|
+
Author-email: support@completcha.com
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://completcha.com
|
|
9
|
+
Project-URL: Repository, https://github.com/completcha/completcha-python
|
|
10
|
+
Keywords: completcha,captcha,solver,api,token,captcha solver,funcaptcha,arkose,funcaptcha solver,arkose solver,x,twitter,twitter captcha,x captcha,arkose token,funcaptcha token
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Natural Language :: English
|
|
16
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Requires-Python: >=3.12.1
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: requests
|
|
22
|
+
Requires-Dist: colorama
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
# 🚀 Completcha
|
|
26
|
+
|
|
27
|
+
Python library for solving **Arkose Labs / FunCaptcha** challenges, built to deliver **high success rates, speed, and real-world reliability in production**.
|
|
28
|
+
|
|
29
|
+
### [Free trial for new users on completcha.com](https://completcha.com)
|
|
30
|
+
|
|
31
|
+
Unlike traditional approaches, **Completcha** was designed to solve the most common problems faced when dealing with captchas:
|
|
32
|
+
|
|
33
|
+
- ❌ Challenges that never get solved
|
|
34
|
+
- ⏳ Long waiting times for responses
|
|
35
|
+
- 🔁 Constant need to generate new captcha URLs
|
|
36
|
+
- 🚫 Limited attempts per challenge
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 💡 Key Advantages
|
|
41
|
+
|
|
42
|
+
### 🚀 Bypass Resolution (Main Advantage)
|
|
43
|
+
|
|
44
|
+
The biggest advantage of Completcha is its **full Arkose bypass capability**.
|
|
45
|
+
|
|
46
|
+
- Most challenges are solved **without requiring image solving**
|
|
47
|
+
- The system accurately replicates real browser behavior
|
|
48
|
+
- This results in:
|
|
49
|
+
- ⚡ Much faster responses
|
|
50
|
+
- 🎯 Extremely high success rates
|
|
51
|
+
- 🔄 Reduced need to generate new challenges
|
|
52
|
+
|
|
53
|
+
👉 In practice, this eliminates the most frustrating issue: waiting for a captcha that often never gets solved.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
### 🖼️ Image Solving with Smart Retries
|
|
58
|
+
|
|
59
|
+
When bypass is not possible (e.g., using rotating proxies), Completcha still stands out:
|
|
60
|
+
|
|
61
|
+
- 🔁 Performs **all necessary retries automatically**
|
|
62
|
+
- 🧠 Designed to handle harder image challenges
|
|
63
|
+
- 📉 Significantly reduces failure rates
|
|
64
|
+
- ♻️ Avoids the need to generate new captcha URLs
|
|
65
|
+
|
|
66
|
+
Additionally:
|
|
67
|
+
|
|
68
|
+
- Full integration with Arkose's original flow ensures:
|
|
69
|
+
- Fewer images are generated
|
|
70
|
+
- Behavior closely matches a real browser
|
|
71
|
+
|
|
72
|
+
👉 Result: **one of the highest solving success rates on the market**, even in difficult scenarios.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 📦 Installation
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install completcha
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 🔐 Solving Methods
|
|
85
|
+
|
|
86
|
+
**Completcha** provides two main methods for solving Arkose challenges:
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
### 🚀 1. Bypass (Recommended)
|
|
91
|
+
|
|
92
|
+
The fastest and most reliable method.
|
|
93
|
+
|
|
94
|
+
**How it works:**
|
|
95
|
+
- The Arkose challenge URL must be requested using a **fixed proxy**
|
|
96
|
+
- The solution is executed on the **same IP as the request**
|
|
97
|
+
- No images need to be solved
|
|
98
|
+
|
|
99
|
+
**Advantages:**
|
|
100
|
+
- ⚡ High speed
|
|
101
|
+
- 🎯 Maximum reliability
|
|
102
|
+
- 🧠 No image solving required
|
|
103
|
+
|
|
104
|
+
⚠️ **Important:**
|
|
105
|
+
- Use **fixed (dedicated) proxies**
|
|
106
|
+
- **Do NOT use sticky proxies**
|
|
107
|
+
|
|
108
|
+
> ❗ Sticky proxies will change IP addresses because they depend on the same source IP address to remain static since your source IP address is different from ours in the resolution side.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
### 🖼️ 2. Image Solving
|
|
113
|
+
|
|
114
|
+
Used when bypass is not possible.
|
|
115
|
+
|
|
116
|
+
**When it happens:**
|
|
117
|
+
- When using **rotating proxies**
|
|
118
|
+
- The request IP differs from the solving IP
|
|
119
|
+
|
|
120
|
+
**Features:**
|
|
121
|
+
- 🧩 Automatically solves any image challenge
|
|
122
|
+
- 📊 Real-time logs for tracking progress
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## ⚙️ Best Practices
|
|
127
|
+
|
|
128
|
+
- ✅ Use the **same User-Agent** from the original request
|
|
129
|
+
- ♻️ Reuse the same API instance (avoids rate limiting)
|
|
130
|
+
- 🔒 Prefer fixed proxies for best performance
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 💻 Example Usage
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from completcha import SolverApi
|
|
138
|
+
|
|
139
|
+
# Instantiate only once to maintain same completcha session to avoid rate limit
|
|
140
|
+
completcha_session = SolverApi(
|
|
141
|
+
api_key='xxx-xxxx-xxx-xxx-xxxx-xxx',
|
|
142
|
+
show_logs=True
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
arkose_data = 'Q9xL2mVtF8yZk/rW.JpG4aH6uSnoqLDEBvCwR5Xf3sYt0ZlN8Peu/jK3qTz7rVbA1MHi9UdWcE2Ox+gFJYnKsL0QpR4t6BvXy7zN5hMeCq8GjAfD3uWPlZrT1n/SoIkVxYcE2mH7F9QaUpbXgRZK5V3nTtLj8wQh4Gv0p2fMsYkJ6CDeaI1Xo7r8s9NwBtU5lE3ZcHyPgQfO2uV1dKjSxA7mW9bL0FvRzJq6YH3XcD8tUpnK5wIeM4aG2ZQh7sVb9C0fYkT1xP8LrNwD3mE6uJgS2AqXv5oFz+HyR8c7LkW9p0VJtN3ZbGdE6xF2aQs8UoYhP1rM4iTnK7wC5vLzX9qD2jH0BfE3R6gPZs1yN4t8uAqI5WcKXoM7dVhFzYJ2bL9xC6rT3gUpvSnQ0='
|
|
146
|
+
proxy = 'proxyusername:proxypassword@proxyhost:proxyport'
|
|
147
|
+
site_key = '2CB16598-CB82-4CF7-B332-5990DB66F3AB'
|
|
148
|
+
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36'
|
|
149
|
+
|
|
150
|
+
solved_token_arkose = completcha_session.arkose(
|
|
151
|
+
arkose_data,
|
|
152
|
+
proxy,
|
|
153
|
+
site_key,
|
|
154
|
+
user_agent
|
|
155
|
+
)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Return Solved Token
|
|
159
|
+
```
|
|
160
|
+
70103a5dafe122e18.1833610001|r=us-east-1|meta=3|meta_width=558|meta_height=523|metabgclr=transparent|metaiconclr=%23555555|guitextcolor=%23000000|pk=2CB16598-CB82-4CF7-B332-5990DB66F3AB|at=30|ag=201|cdn_url=https%3A%2F%2Fclient-api.arkoselabs.com%2Fcdn%2Ffc|surl=https%3A%2F%2Fclient-api.arkoselabs.com|smurl=https%3A%2F%2Fclient-api.arkoselabs.com%2Fcdn%2Ffc%2Fassets%2Fstyle-manager
|
|
161
|
+
```
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## ⭐ Method Comparison
|
|
165
|
+
|
|
166
|
+
| Method | Speed | Reliability |
|
|
167
|
+
|--------------------|----------|------------|
|
|
168
|
+
| 🚀 Bypass | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
|
|
169
|
+
| 🖼️ Image Solving | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 🏆 Final Recommendation
|
|
174
|
+
|
|
175
|
+
- 🚀 **Bypass** → ⭐⭐⭐⭐⭐ (Best overall choice)
|
|
176
|
+
- 🖼️ **Image** → ⭐⭐⭐⭐
|
|
177
|
+
|
|
178
|
+
✔ Always prefer **bypass with fixed proxies** for optimal performance.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 💬 Community & Support
|
|
183
|
+
|
|
184
|
+
<p align="center">
|
|
185
|
+
<a href="https://discord.gg/cdgHgF2ySG">
|
|
186
|
+
<img src="https://img.shields.io/badge/Join%20our%20Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white" alt="Discord">
|
|
187
|
+
</a>
|
|
188
|
+
</p>
|
|
189
|
+
|
|
190
|
+
<p align="center">
|
|
191
|
+
Join the community for support, updates, and discussions 🚀
|
|
192
|
+
</p>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
completcha/__init__.py
|
|
5
|
+
completcha/exceptions.py
|
|
6
|
+
completcha.egg-info/PKG-INFO
|
|
7
|
+
completcha.egg-info/SOURCES.txt
|
|
8
|
+
completcha.egg-info/dependency_links.txt
|
|
9
|
+
completcha.egg-info/requires.txt
|
|
10
|
+
completcha.egg-info/top_level.txt
|
|
11
|
+
completcha/logger_print/__init__.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "completcha"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
keywords = ["completcha", "captcha", "solver", "api", "token", "captcha solver", "funcaptcha", "arkose", "funcaptcha solver", "arkose solver", "x", "twitter", "twitter captcha", "x captcha", "arkose token", "funcaptcha token"]
|
|
9
|
+
description = "Captcha Solver"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
authors = [{ name = "Completcha" }, { email = "support@completcha.com" }]
|
|
12
|
+
license = "MIT"
|
|
13
|
+
license-files = ["LICENSE"]
|
|
14
|
+
urls = { "Homepage" = "https://completcha.com" , "Repository" = "https://github.com/completcha/completcha-python" }
|
|
15
|
+
dependencies = ['requests', 'colorama']
|
|
16
|
+
requires-python = ">=3.12.1"
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Programming Language :: Python :: 3.12",
|
|
19
|
+
"Programming Language :: Python :: 3.13",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Development Status :: 4 - Beta",
|
|
22
|
+
"Natural Language :: English",
|
|
23
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
24
|
+
"Topic :: Software Development :: Libraries :: Python Modules"
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[tool.setuptools.packages.find]
|
|
28
|
+
where = ["."]
|