bas-http 1.0.0__tar.gz → 1.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.
- bas_http-1.0.2/PKG-INFO +532 -0
- bas_http-1.0.2/bas/README.md +507 -0
- {bas_http-1.0.0 → bas_http-1.0.2}/bas/__init__.py +1 -1
- bas_http-1.0.2/bas_http.egg-info/PKG-INFO +532 -0
- {bas_http-1.0.0 → bas_http-1.0.2}/pyproject.toml +8 -9
- bas_http-1.0.0/PKG-INFO +0 -25
- bas_http-1.0.0/bas/README.md +0 -244
- bas_http-1.0.0/bas_http.egg-info/PKG-INFO +0 -25
- {bas_http-1.0.0 → bas_http-1.0.2}/bas/_curl.py +0 -0
- {bas_http-1.0.0 → bas_http-1.0.2}/bas/async_session.py +0 -0
- {bas_http-1.0.0 → bas_http-1.0.2}/bas/cookies.py +0 -0
- {bas_http-1.0.0 → bas_http-1.0.2}/bas/curl_parser.py +0 -0
- {bas_http-1.0.0 → bas_http-1.0.2}/bas/impersonate.py +0 -0
- {bas_http-1.0.0 → bas_http-1.0.2}/bas/models.py +0 -0
- {bas_http-1.0.0 → bas_http-1.0.2}/bas/session.py +0 -0
- {bas_http-1.0.0 → bas_http-1.0.2}/bas/simple_session.py +0 -0
- {bas_http-1.0.0 → bas_http-1.0.2}/bas/tests/__init__.py +0 -0
- {bas_http-1.0.0 → bas_http-1.0.2}/bas/tests/test_cookies.py +0 -0
- {bas_http-1.0.0 → bas_http-1.0.2}/bas/tests/test_curl_parser.py +0 -0
- {bas_http-1.0.0 → bas_http-1.0.2}/bas/tests/test_real_request.py +0 -0
- {bas_http-1.0.0 → bas_http-1.0.2}/bas/tests/test_spaceshooter.py +0 -0
- {bas_http-1.0.0 → bas_http-1.0.2}/bas_http.egg-info/SOURCES.txt +0 -0
- {bas_http-1.0.0 → bas_http-1.0.2}/bas_http.egg-info/dependency_links.txt +0 -0
- {bas_http-1.0.0 → bas_http-1.0.2}/bas_http.egg-info/top_level.txt +0 -0
- {bas_http-1.0.0 → bas_http-1.0.2}/setup.cfg +0 -0
bas_http-1.0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bas-http
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: Copy-paste your browser's request, bas handles the rest. No impersonation needed. Zero dependencies.
|
|
5
|
+
Author: bas
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://pypi.org/project/bas-http/
|
|
8
|
+
Project-URL: Repository, https://pypi.org/project/bas-http/
|
|
9
|
+
Project-URL: Issues, https://pypi.org/project/bas-http/
|
|
10
|
+
Keywords: http,curl,cookie,scraping,browser,devtools,requests
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Requires-Python: >=3.8
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# bas
|
|
27
|
+
|
|
28
|
+
Copy-paste your browser's request, bas handles the rest.
|
|
29
|
+
|
|
30
|
+
No impersonation needed. No fingerprint chasing. No broken cookies. Just grab your headers + cookies from DevTools and go.
|
|
31
|
+
|
|
32
|
+
## Why bas?
|
|
33
|
+
|
|
34
|
+
| Problem | curlcffi | bas |
|
|
35
|
+
|---------|----------|-----|
|
|
36
|
+
| Cookies lost during redirects | **BUG** | **Fixed** |
|
|
37
|
+
| Cookies not accumulating across requests | **BUG** | **Fixed** |
|
|
38
|
+
| Manual Cookie header construction | Yes | **Auto-injected** |
|
|
39
|
+
| Requires curl-impersonate | Yes | **No — pure Python** |
|
|
40
|
+
| Browser fingerprint updates | Constant chase | **None — bring your own headers** |
|
|
41
|
+
| External dependencies | Yes | **Zero** |
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install bas-http
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
### Method 1: Paste a curl command from DevTools (Recommended)
|
|
52
|
+
|
|
53
|
+
This is the fastest way. Copy a curl command from your browser and bas does the rest.
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
1. Open browser DevTools (F12) → Network tab
|
|
57
|
+
2. Make a request on the website
|
|
58
|
+
3. Right-click the request → "Copy as cURL"
|
|
59
|
+
4. Paste into Python
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
import bas
|
|
64
|
+
|
|
65
|
+
# Paste your curl command (use r'' raw string to preserve backslashes)
|
|
66
|
+
s = bas.from_curl(r'''curl "https://example.com/page" ^
|
|
67
|
+
-H "accept: text/html,application/xhtml+xml" ^
|
|
68
|
+
-H "accept-language: en-US,en;q=0.9" ^
|
|
69
|
+
-H "user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" ^
|
|
70
|
+
-b "cf_clearance=abc123; session_id=xyz; token=def456"''')
|
|
71
|
+
|
|
72
|
+
# Now make requests — all headers and cookies are auto-injected
|
|
73
|
+
r = s.get("https://example.com/page")
|
|
74
|
+
print(r.status_code)
|
|
75
|
+
print(r.text)
|
|
76
|
+
|
|
77
|
+
# Follow-up requests keep the same headers and cookies
|
|
78
|
+
r2 = s.get("https://example.com/dashboard")
|
|
79
|
+
print(r2.status_code)
|
|
80
|
+
|
|
81
|
+
# Add more cookies manually if needed
|
|
82
|
+
s.set_cookie("new_cookie", "value", domain="example.com")
|
|
83
|
+
r3 = s.get("https://example.com/api/data")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Method 2: Build headers manually
|
|
87
|
+
|
|
88
|
+
If you have headers copied from DevTools (not as a curl command):
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
import bas
|
|
92
|
+
|
|
93
|
+
s = bas.Session()
|
|
94
|
+
|
|
95
|
+
# Paste your headers from DevTools → Network → Headers tab
|
|
96
|
+
s.headers = {
|
|
97
|
+
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
|
|
98
|
+
"accept-language": "en-US,en;q=0.9",
|
|
99
|
+
"cache-control": "max-age=0",
|
|
100
|
+
"sec-ch-ua": '"Chromium";v="137", "Not/A)Brand";v="24"',
|
|
101
|
+
"sec-ch-ua-mobile": "?0",
|
|
102
|
+
"sec-ch-ua-platform": '"Windows"',
|
|
103
|
+
"sec-fetch-dest": "document",
|
|
104
|
+
"sec-fetch-mode": "navigate",
|
|
105
|
+
"sec-fetch-site": "none",
|
|
106
|
+
"sec-fetch-user": "?1",
|
|
107
|
+
"upgrade-insecure-requests": "1",
|
|
108
|
+
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Add your cookies from DevTools → Application → Cookies
|
|
112
|
+
s.set_cookie("cf_clearance", "abc123", domain="example.com")
|
|
113
|
+
s.set_cookie("session_id", "xyz", domain="example.com")
|
|
114
|
+
s.set_cookie("csrf_token", "def456", domain="example.com")
|
|
115
|
+
|
|
116
|
+
# Go!
|
|
117
|
+
r = s.get("https://example.com/page")
|
|
118
|
+
print(r.status_code, len(r.text))
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Method 3: Headers + cookies in one call
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
import bas
|
|
125
|
+
|
|
126
|
+
s = bas.from_headers(
|
|
127
|
+
url="https://example.com",
|
|
128
|
+
headers={
|
|
129
|
+
"user-agent": "Mozilla/5.0 ...",
|
|
130
|
+
"accept": "text/html,...",
|
|
131
|
+
},
|
|
132
|
+
cookies={
|
|
133
|
+
"cf_clearance": "abc123",
|
|
134
|
+
"session": "xyz",
|
|
135
|
+
},
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
r = s.get("https://example.com/page")
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## HTTP Methods
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
import bas
|
|
145
|
+
|
|
146
|
+
s = bas.from_curl(r'''curl "https://example.com" -b "session=abc"''')
|
|
147
|
+
|
|
148
|
+
# GET
|
|
149
|
+
r = s.get("https://example.com/page")
|
|
150
|
+
|
|
151
|
+
# POST with form data
|
|
152
|
+
r = s.post("https://example.com/login", data={"username": "user", "password": "pass"})
|
|
153
|
+
|
|
154
|
+
# POST with JSON
|
|
155
|
+
r = s.post("https://example.com/api", json={"key": "value"})
|
|
156
|
+
|
|
157
|
+
# PUT
|
|
158
|
+
r = s.put("https://example.com/api/123", json={"name": "updated"})
|
|
159
|
+
|
|
160
|
+
# DELETE
|
|
161
|
+
r = s.delete("https://example.com/api/123")
|
|
162
|
+
|
|
163
|
+
# PATCH
|
|
164
|
+
r = s.patch("https://example.com/api/123", json={"name": "patched"})
|
|
165
|
+
|
|
166
|
+
# HEAD
|
|
167
|
+
r = s.head("https://example.com/page")
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Response Object
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
r = s.get("https://example.com/page")
|
|
174
|
+
|
|
175
|
+
# Status code
|
|
176
|
+
print(r.status_code) # 200
|
|
177
|
+
print(r.ok) # True (status < 400)
|
|
178
|
+
print(r.reason_phrase) # "OK"
|
|
179
|
+
|
|
180
|
+
# Content
|
|
181
|
+
print(r.text) # Decoded text
|
|
182
|
+
print(r.body) # Raw bytes
|
|
183
|
+
print(r.json) # Parsed JSON
|
|
184
|
+
print(r.content_type) # "text/html; charset=utf-8"
|
|
185
|
+
|
|
186
|
+
# Headers
|
|
187
|
+
print(r.headers) # Case-insensitive headers dict
|
|
188
|
+
print(r.headers["content-type"])
|
|
189
|
+
|
|
190
|
+
# URL info
|
|
191
|
+
print(r.url) # Final URL (after redirects)
|
|
192
|
+
print(r.ip) # Server IP
|
|
193
|
+
print(r.http_version) # "1.1" or "2.0"
|
|
194
|
+
print(r.elapsed) # Response time in seconds
|
|
195
|
+
|
|
196
|
+
# Redirect history
|
|
197
|
+
for resp in r.history:
|
|
198
|
+
print(resp.status_code, resp.url)
|
|
199
|
+
|
|
200
|
+
# Raise exception on error
|
|
201
|
+
r.raise_for_status() # Raises HTTPError if status >= 400
|
|
202
|
+
|
|
203
|
+
# Iterate over content
|
|
204
|
+
for chunk in r.iter_content(chunk_size=8192):
|
|
205
|
+
process(chunk)
|
|
206
|
+
|
|
207
|
+
for line in r.iter_lines():
|
|
208
|
+
print(line)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Cookie Management
|
|
212
|
+
|
|
213
|
+
### Auto-injection
|
|
214
|
+
|
|
215
|
+
bas automatically injects cookies into every request. No manual header construction needed.
|
|
216
|
+
|
|
217
|
+
```python
|
|
218
|
+
import bas
|
|
219
|
+
|
|
220
|
+
s = bas.from_curl(r'''curl "https://example.com" -b "session=abc123; token=xyz"''')
|
|
221
|
+
|
|
222
|
+
# This request automatically has Cookie: session=abc123; token=xyz
|
|
223
|
+
r = s.get("https://example.com/page")
|
|
224
|
+
|
|
225
|
+
# See what cookies were sent
|
|
226
|
+
print(r.request.headers.get("Cookie"))
|
|
227
|
+
# "session=abc123; token=xyz"
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Set cookies manually
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
s = bas.Session()
|
|
234
|
+
s.set_cookie("name", "value", domain="example.com", path="/")
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Get cookies for a URL
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
cookies = s.get_cookies("https://example.com/page")
|
|
241
|
+
print(cookies) # {"session": "abc123", "token": "xyz"}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Clear all cookies
|
|
245
|
+
|
|
246
|
+
```python
|
|
247
|
+
s.clear_cookies()
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Save cookies to file
|
|
251
|
+
|
|
252
|
+
```python
|
|
253
|
+
# JSON format
|
|
254
|
+
s.save_cookies("cookies.json")
|
|
255
|
+
|
|
256
|
+
# Netscape format (compatible with curl/wget)
|
|
257
|
+
s.save_cookies("cookies.txt", format="netscape")
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Load cookies from file
|
|
261
|
+
|
|
262
|
+
```python
|
|
263
|
+
s.load_cookies("cookies.json")
|
|
264
|
+
s.load_cookies("cookies.txt", format="netscape")
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Cookie accumulation across requests
|
|
268
|
+
|
|
269
|
+
When the server sends Set-Cookie headers, bas automatically stores them:
|
|
270
|
+
|
|
271
|
+
```python
|
|
272
|
+
s = bas.Session()
|
|
273
|
+
|
|
274
|
+
# Server sets cookies in this response
|
|
275
|
+
r1 = s.get("https://example.com/login")
|
|
276
|
+
# Set-Cookie: session_id=abc123; Path=/
|
|
277
|
+
# Set-Cookie: user=john; Path=/
|
|
278
|
+
|
|
279
|
+
# These cookies are automatically sent with the next request
|
|
280
|
+
r2 = s.get("https://example.com/dashboard")
|
|
281
|
+
# Cookie: session_id=abc123; user=john
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Cookies survive redirects
|
|
285
|
+
|
|
286
|
+
```python
|
|
287
|
+
# Server redirects and sets more cookies
|
|
288
|
+
r = s.get("https://example.com/page")
|
|
289
|
+
# 302 → https://example.com/dashboard
|
|
290
|
+
# Set-Cookie: tracking=xyz; Path=/
|
|
291
|
+
|
|
292
|
+
# ALL cookies are preserved through redirects
|
|
293
|
+
# No cookies lost (unlike curlcffi!)
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## Session Persistence
|
|
297
|
+
|
|
298
|
+
Keep a session alive across multiple script runs:
|
|
299
|
+
|
|
300
|
+
```python
|
|
301
|
+
import bas
|
|
302
|
+
|
|
303
|
+
s = bas.Session()
|
|
304
|
+
|
|
305
|
+
# Try to load previous session
|
|
306
|
+
try:
|
|
307
|
+
s.load_cookies("my_session.json")
|
|
308
|
+
except FileNotFoundError:
|
|
309
|
+
pass
|
|
310
|
+
|
|
311
|
+
# Make requests
|
|
312
|
+
r = s.get("https://example.com/page")
|
|
313
|
+
|
|
314
|
+
# Save session for next run
|
|
315
|
+
s.save_cookies("my_session.json")
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Parse curl commands
|
|
319
|
+
|
|
320
|
+
```python
|
|
321
|
+
from bas.curl_parser import parse_curl, print_curl_summary
|
|
322
|
+
|
|
323
|
+
# See what's in a curl command
|
|
324
|
+
print_curl_summary(r'''curl "https://example.com" -H "User-Agent: ..." -b "cookie=value"''')
|
|
325
|
+
|
|
326
|
+
# Or get it as a dict
|
|
327
|
+
parsed = parse_curl(r'''curl "https://example.com" -H "User-Agent: ..." -b "cookie=value"''')
|
|
328
|
+
print(parsed["method"]) # "GET"
|
|
329
|
+
print(parsed["url"]) # "https://example.com"
|
|
330
|
+
print(parsed["headers"]) # {"User-Agent": "..."}
|
|
331
|
+
print(parsed["cookies"]) # {"cookie": "value"}
|
|
332
|
+
print(parsed["user_agent"]) # "Mozilla/5.0 ..."
|
|
333
|
+
print(parsed["referer"]) # "..."
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## SSL Verification
|
|
337
|
+
|
|
338
|
+
```python
|
|
339
|
+
# Disable SSL verification (default is enabled)
|
|
340
|
+
s = bas.Session(verify=False)
|
|
341
|
+
|
|
342
|
+
# Or per-request
|
|
343
|
+
r = s.get("https://self-signed.example.com", verify=False)
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## Timeouts
|
|
347
|
+
|
|
348
|
+
```python
|
|
349
|
+
# Set default timeout (seconds)
|
|
350
|
+
s = bas.Session(timeout=60)
|
|
351
|
+
|
|
352
|
+
# Or per-request
|
|
353
|
+
r = s.get("https://slow.example.com", timeout=120)
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
## Redirects
|
|
357
|
+
|
|
358
|
+
```python
|
|
359
|
+
# Follow redirects (default: True)
|
|
360
|
+
r = s.get("https://example.com/page")
|
|
361
|
+
|
|
362
|
+
# Don't follow redirects
|
|
363
|
+
r = s.get("https://example.com/page", allow_redirects=False)
|
|
364
|
+
print(r.status_code) # 302
|
|
365
|
+
print(r.location) # "https://example.com/dashboard"
|
|
366
|
+
|
|
367
|
+
# Set max redirects
|
|
368
|
+
s = bas.Session(max_redirects=5)
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
## Proxy Support
|
|
372
|
+
|
|
373
|
+
```python
|
|
374
|
+
# TODO: Proxy support coming in v1.1
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
## Real-World Example: Web Scraping
|
|
378
|
+
|
|
379
|
+
```python
|
|
380
|
+
import bas
|
|
381
|
+
|
|
382
|
+
# Step 1: Copy curl from DevTools
|
|
383
|
+
s = bas.from_curl(r'''curl "https://spaceshooter.net/faucet/ltc" ^
|
|
384
|
+
-H "accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" ^
|
|
385
|
+
-H "accept-language: en-US,en;q=0.9" ^
|
|
386
|
+
-H "sec-ch-ua: \"Chromium\";v=\"137\", \"Not/A)Brand\";v=\"24\"" ^
|
|
387
|
+
-H "sec-ch-ua-mobile: ?0" ^
|
|
388
|
+
-H "sec-ch-ua-platform: \"Windows\"" ^
|
|
389
|
+
-H "sec-fetch-dest: document" ^
|
|
390
|
+
-H "sec-fetch-mode: navigate" ^
|
|
391
|
+
-H "sec-fetch-site: none" ^
|
|
392
|
+
-H "upgrade-insecure-requests: 1" ^
|
|
393
|
+
-H "user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" ^
|
|
394
|
+
-b "captcha=rscaptcha; cf_clearance=abc123; ci_session=xyz123; uf=def456"''')
|
|
395
|
+
|
|
396
|
+
# Step 2: Make the request
|
|
397
|
+
r = s.get("https://spaceshooter.net/faucet/ltc")
|
|
398
|
+
|
|
399
|
+
# Step 3: Parse the response
|
|
400
|
+
if r.ok:
|
|
401
|
+
print("Success!")
|
|
402
|
+
print(f"Status: {r.status_code}")
|
|
403
|
+
print(f"Content length: {len(r.text)}")
|
|
404
|
+
print(f"Cookies after request: {s.get_cookies('https://spaceshooter.net')}")
|
|
405
|
+
else:
|
|
406
|
+
print(f"Failed: {r.status_code}")
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
## Real-World Example: Form Submission
|
|
410
|
+
|
|
411
|
+
```python
|
|
412
|
+
import bas
|
|
413
|
+
|
|
414
|
+
# Copy the POST request curl from DevTools
|
|
415
|
+
s = bas.from_curl(r'''curl "https://example.com/login" ^
|
|
416
|
+
-H "content-type: application/x-www-form-urlencoded" ^
|
|
417
|
+
-H "user-agent: Mozilla/5.0 ..." ^
|
|
418
|
+
-H "referer: https://example.com/login" ^
|
|
419
|
+
-b "csrf_token=abc123" ^
|
|
420
|
+
--data-raw "username=myuser&password=mypass"''')
|
|
421
|
+
|
|
422
|
+
r = s.post("https://example.com/login", data={
|
|
423
|
+
"username": "myuser",
|
|
424
|
+
"password": "mypass",
|
|
425
|
+
})
|
|
426
|
+
|
|
427
|
+
print(r.status_code)
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
## Comparison with curlcffi
|
|
431
|
+
|
|
432
|
+
### curlcffi (BROKEN)
|
|
433
|
+
|
|
434
|
+
```python
|
|
435
|
+
from curl_cffi.requests import Session
|
|
436
|
+
|
|
437
|
+
s = Session(impersonate="chrome131")
|
|
438
|
+
|
|
439
|
+
# Cookies lost during redirects!
|
|
440
|
+
r1 = s.get("https://example.com/page") # 302 redirect
|
|
441
|
+
# r1 is missing cookies from Set-Cookie headers!
|
|
442
|
+
|
|
443
|
+
# Cookies not accumulating!
|
|
444
|
+
r2 = s.get("https://example.com/page")
|
|
445
|
+
# r2 has LOST cookies from r1!
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### bas (FIXED)
|
|
449
|
+
|
|
450
|
+
```python
|
|
451
|
+
import bas
|
|
452
|
+
|
|
453
|
+
s = bas.from_curl(r'''curl "https://example.com" -b "session=abc"''')
|
|
454
|
+
|
|
455
|
+
# Cookies survive redirects!
|
|
456
|
+
r1 = s.get("https://example.com/page") # 302 redirect
|
|
457
|
+
# ALL cookies preserved through redirect
|
|
458
|
+
|
|
459
|
+
# Cookies accumulate!
|
|
460
|
+
r2 = s.get("https://example.com/dashboard")
|
|
461
|
+
# r2 has ALL cookies from r1 + new ones
|
|
462
|
+
|
|
463
|
+
# No manual Cookie header needed!
|
|
464
|
+
# bas auto-injects cookies from the jar
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
## API Reference
|
|
468
|
+
|
|
469
|
+
### `bas.from_curl(curl_cmd, **kwargs)` → Session
|
|
470
|
+
|
|
471
|
+
Create a Session from a curl command. Main entry point.
|
|
472
|
+
|
|
473
|
+
### `bas.from_headers(url, headers, cookies, **kwargs)` → Session
|
|
474
|
+
|
|
475
|
+
Create a Session from raw headers and cookies.
|
|
476
|
+
|
|
477
|
+
### `bas.Session(headers, cookies, verify, timeout, allow_redirects, max_redirects)`
|
|
478
|
+
|
|
479
|
+
Pure Python HTTP session. Zero external dependencies.
|
|
480
|
+
|
|
481
|
+
**Methods:**
|
|
482
|
+
- `get(url, **kwargs)` → Response
|
|
483
|
+
- `post(url, **kwargs)` → Response
|
|
484
|
+
- `put(url, **kwargs)` → Response
|
|
485
|
+
- `delete(url, **kwargs)` → Response
|
|
486
|
+
- `patch(url, **kwargs)` → Response
|
|
487
|
+
- `head(url, **kwargs)` → Response
|
|
488
|
+
- `set_cookie(name, value, domain, path)` → None
|
|
489
|
+
- `get_cookies(url)` → dict
|
|
490
|
+
- `clear_cookies()` → None
|
|
491
|
+
- `save_cookies(filepath, format)` → None
|
|
492
|
+
- `load_cookies(filepath, format)` → None
|
|
493
|
+
|
|
494
|
+
### `bas.Cookie(name, value, domain, path, expires, max_age, secure, http_only, same_site)`
|
|
495
|
+
|
|
496
|
+
Individual cookie object with RFC 6265 compliance.
|
|
497
|
+
|
|
498
|
+
### `bas.CookieJar`
|
|
499
|
+
|
|
500
|
+
Thread-safe cookie container. Full RFC 6265 domain/path matching.
|
|
501
|
+
|
|
502
|
+
**Methods:**
|
|
503
|
+
- `add(cookie)` → None
|
|
504
|
+
- `remove(cookie)` → None
|
|
505
|
+
- `get(name, domain, path)` → Cookie | None
|
|
506
|
+
- `match(url)` → list[Cookie]
|
|
507
|
+
- `to_header(url)` → str
|
|
508
|
+
- `parse_set_cookie(header, url)` → Cookie
|
|
509
|
+
- `save_json(filepath)` → None
|
|
510
|
+
- `load_json(filepath)` → None
|
|
511
|
+
- `save_netscape(filepath)` → None
|
|
512
|
+
- `load_netscape(filepath)` → None
|
|
513
|
+
|
|
514
|
+
### `bas.Response`
|
|
515
|
+
|
|
516
|
+
HTTP response object.
|
|
517
|
+
|
|
518
|
+
**Properties:**
|
|
519
|
+
- `status_code` (int): HTTP status code
|
|
520
|
+
- `ok` (bool): True if status < 400
|
|
521
|
+
- `text` (str): Decoded text content
|
|
522
|
+
- `body` (bytes): Raw bytes
|
|
523
|
+
- `json` (Any): Parsed JSON
|
|
524
|
+
- `headers` (Headers): Response headers
|
|
525
|
+
- `url` (str): Final URL
|
|
526
|
+
- `elapsed` (float): Response time
|
|
527
|
+
- `history` (list): Redirect history
|
|
528
|
+
- `cookies` (CookieJar): Cookie jar
|
|
529
|
+
|
|
530
|
+
## License
|
|
531
|
+
|
|
532
|
+
MIT
|