bas
Copy-paste your browser's request, bas handles the rest.
Zero dependencies. Pure Python. Just grab your headers + cookies from DevTools and go.
Why bas?
| Feature | bas | requests | pycurl | curl_cffi |
|---|---|---|---|---|
| Zero dependencies | ✅ | ❌ (urllib3) | ❌ (libcurl) | ❌ (curl-impersonate) |
| Paste curl from DevTools | ✅ | ❌ | ❌ | ❌ |
| Auto Cookie injection | ✅ | ✅ | ❌ | ⚠️ |
| Cookie jar (RFC 6265) | ✅ | ✅ | ❌ | ⚠️ |
| No compilation needed | ✅ | ✅ | ❌ | ❌ |
| Bring your own headers | ✅ | ❌ (generates) | ❌ | ❌ (impersonation) |
| Works on all platforms | ✅ | ✅ | ⚠️ | ⚠️ |
| Session persistence | ✅ | ✅ | ❌ | ✅ |
| Follow redirects | ✅ | ✅ | Manual | ✅ |
| JSON support | ✅ | ✅ | ❌ | ✅ |
Installation
pip install bas-http
Quick Start
Method 1: Paste a curl command from DevTools (Recommended)
This is the fastest way. Copy a curl command from your browser and bas does the rest.
1. Open browser DevTools (F12) → Network tab
2. Make a request on the website
3. Right-click the request → "Copy as cURL"
4. Paste into Python
import bas
# Paste your curl command (use r'' raw string to preserve backslashes)
s = bas.from_curl(r'''curl "https://example.com/page" ^
-H "accept: text/html,application/xhtml+xml" ^
-H "accept-language: en-US,en;q=0.9" ^
-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" ^
-b "cf_clearance=abc123; session_id=xyz; token=def456"''')
# Now make requests — all headers and cookies are auto-injected
r = s.get("https://example.com/page")
print(r.status_code)
print(r.text)
# Follow-up requests keep the same headers and cookies
r2 = s.get("https://example.com/dashboard")
print(r2.status_code)
# Add more cookies manually if needed
s.set_cookie("new_cookie", "value", domain="example.com")
r3 = s.get("https://example.com/api/data")
Method 2: Build headers manually
If you have headers copied from DevTools (not as a curl command):
import bas
s = bas.Session()
# Paste your headers from DevTools → Network → Headers tab
s.headers = {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
"accept-language": "en-US,en;q=0.9",
"cache-control": "max-age=0",
"sec-ch-ua": '"Chromium";v="137", "Not/A)Brand";v="24"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "none",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
"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",
}
# Add your cookies from DevTools → Application → Cookies
s.set_cookie("cf_clearance", "abc123", domain="example.com")
s.set_cookie("session_id", "xyz", domain="example.com")
s.set_cookie("csrf_token", "def456", domain="example.com")
# Go!
r = s.get("https://example.com/page")
print(r.status_code, len(r.text))
Method 3: Headers + cookies in one call
import bas
s = bas.from_headers(
url="https://example.com",
headers={
"user-agent": "Mozilla/5.0 ...",
"accept": "text/html,...",
},
cookies={
"cf_clearance": "abc123",
"session": "xyz",
},
)
r = s.get("https://example.com/page")
HTTP Methods
import bas
s = bas.from_curl(r'''curl "https://example.com" -b "session=abc"''')
# GET
r = s.get("https://example.com/page")
# POST with form data
r = s.post("https://example.com/login", data={"username": "user", "password": "pass"})
# POST with JSON
r = s.post("https://example.com/api", json={"key": "value"})
# PUT
r = s.put("https://example.com/api/123", json={"name": "updated"})
# DELETE
r = s.delete("https://example.com/api/123")
# PATCH
r = s.patch("https://example.com/api/123", json={"name": "patched"})
# HEAD
r = s.head("https://example.com/page")
Response Object
r = s.get("https://example.com/page")
# Status code
print(r.status_code) # 200
print(r.ok) # True (status < 400)
print(r.reason_phrase) # "OK"
# Content
print(r.text) # Decoded text
print(r.body) # Raw bytes
print(r.json) # Parsed JSON
print(r.content_type) # "text/html; charset=utf-8"
# Headers
print(r.headers) # Case-insensitive headers dict
print(r.headers["content-type"])
# URL info
print(r.url) # Final URL (after redirects)
print(r.ip) # Server IP
print(r.http_version) # "1.1" or "2.0"
print(r.elapsed) # Response time in seconds
# Redirect history
for resp in r.history:
print(resp.status_code, resp.url)
# Raise exception on error
r.raise_for_status() # Raises HTTPError if status >= 400
# Iterate over content
for chunk in r.iter_content(chunk_size=8192):
process(chunk)
for line in r.iter_lines():
print(line)
Cookie Management
Auto-injection
bas automatically injects cookies into every request. No manual header construction needed.
import bas
s = bas.from_curl(r'''curl "https://example.com" -b "session=abc123; token=xyz"''')
# This request automatically has Cookie: session=abc123; token=xyz
r = s.get("https://example.com/page")
# See what cookies were sent
print(r.request.headers.get("Cookie"))
# "session=abc123; token=xyz"
Set cookies manually
s = bas.Session()
s.set_cookie("name", "value", domain="example.com", path="/")
Get cookies for a URL
cookies = s.get_cookies("https://example.com/page")
print(cookies) # {"session": "abc123", "token": "xyz"}
Clear all cookies
s.clear_cookies()
Save cookies to file
# JSON format
s.save_cookies("cookies.json")
# Netscape format (compatible with curl/wget)
s.save_cookies("cookies.txt", format="netscape")
Load cookies from file
s.load_cookies("cookies.json")
s.load_cookies("cookies.txt", format="netscape")
Cookie accumulation across requests
When the server sends Set-Cookie headers, bas automatically stores them:
s = bas.Session()
# Server sets cookies in this response
r1 = s.get("https://example.com/login")
# Set-Cookie: session_id=abc123; Path=/
# Set-Cookie: user=john; Path=/
# These cookies are automatically sent with the next request
r2 = s.get("https://example.com/dashboard")
# Cookie: session_id=abc123; user=john
Cookies survive redirects
# Server redirects and sets more cookies
r = s.get("https://example.com/page")
# 302 → https://example.com/dashboard
# Set-Cookie: tracking=xyz; Path=/
# ALL cookies are preserved through redirects
# No cookies lost (unlike bas!)
Session Persistence
Keep a session alive across multiple script runs:
import bas
s = bas.Session()
# Try to load previous session
try:
s.load_cookies("my_session.json")
except FileNotFoundError:
pass
# Make requests
r = s.get("https://example.com/page")
# Save session for next run
s.save_cookies("my_session.json")
Parse curl commands
from bas.curl_parser import parse_curl, print_curl_summary
# See what's in a curl command
print_curl_summary(r'''curl "https://example.com" -H "User-Agent: ..." -b "cookie=value"''')
# Or get it as a dict
parsed = parse_curl(r'''curl "https://example.com" -H "User-Agent: ..." -b "cookie=value"''')
print(parsed["method"]) # "GET"
print(parsed["url"]) # "https://example.com"
print(parsed["headers"]) # {"User-Agent": "..."}
print(parsed["cookies"]) # {"cookie": "value"}
print(parsed["user_agent"]) # "Mozilla/5.0 ..."
print(parsed["referer"]) # "..."
SSL Verification
# Disable SSL verification (default is enabled)
s = bas.Session(verify=False)
# Or per-request
r = s.get("https://self-signed.example.com", verify=False)
Timeouts
# Set default timeout (seconds)
s = bas.Session(timeout=60)
# Or per-request
r = s.get("https://slow.example.com", timeout=120)
Redirects
# Follow redirects (default: True)
r = s.get("https://example.com/page")
# Don't follow redirects
r = s.get("https://example.com/page", allow_redirects=False)
print(r.status_code) # 302
print(r.location) # "https://example.com/dashboard"
# Set max redirects
s = bas.Session(max_redirects=5)
Proxy Support
# TODO: Proxy support coming in v1.1
Real-World Example: Web Scraping
import bas
# Step 1: Copy curl from DevTools
s = bas.from_curl(r'''curl "https://spaceshooter.net/faucet/ltc" ^
-H "accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" ^
-H "accept-language: en-US,en;q=0.9" ^
-H "sec-ch-ua: \"Chromium\";v=\"137\", \"Not/A)Brand\";v=\"24\"" ^
-H "sec-ch-ua-mobile: ?0" ^
-H "sec-ch-ua-platform: \"Windows\"" ^
-H "sec-fetch-dest: document" ^
-H "sec-fetch-mode: navigate" ^
-H "sec-fetch-site: none" ^
-H "upgrade-insecure-requests: 1" ^
-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" ^
-b "captcha=rscaptcha; cf_clearance=abc123; ci_session=xyz123; uf=def456"''')
# Step 2: Make the request
r = s.get("https://spaceshooter.net/faucet/ltc")
# Step 3: Parse the response
if r.ok:
print("Success!")
print(f"Status: {r.status_code}")
print(f"Content length: {len(r.text)}")
print(f"Cookies after request: {s.get_cookies('https://spaceshooter.net')}")
else:
print(f"Failed: {r.status_code}")
Real-World Example: Form Submission
import bas
# Copy the POST request curl from DevTools
s = bas.from_curl(r'''curl "https://example.com/login" ^
-H "content-type: application/x-www-form-urlencoded" ^
-H "user-agent: Mozilla/5.0 ..." ^
-H "referer: https://example.com/login" ^
-b "csrf_token=abc123" ^
--data-raw "username=myuser&password=mypass"''')
r = s.post("https://example.com/login", data={
"username": "myuser",
"password": "mypass",
})
print(r.status_code)
Comparison with Other Libraries
requests
import requests
# Manual header/cookie setup
s = requests.Session()
s.headers["User-Agent"] = "Mozilla/5.0 ..."
s.cookies.set("session", "abc", domain="example.com")
r = s.get("https://example.com")
# Works, but no curl copy-paste support
# Generates its own fingerprint (detectable)
pycurl
import pycurl
from io import BytesIO
# Low-level, verbose setup
c = pycurl.Curl()
c.setopt(c.URL, "https://example.com")
c.setopt(c.HTTPHEADER, ["User-Agent: Mozilla/5.0 ...", "Cookie: session=abc"])
buffer = BytesIO()
c.setopt(c.WRITEDATA, buffer)
c.perform()
c.close()
# No built-in cookie jar, no redirect handling
# Requires libcurl installed on the system
curl_cffi
from curl_cffi.requests import Session
# Requires curl-impersonate installed
s = Session(impersonate="chrome131")
r = s.get("https://example.com")
# Impersonation fingerprint can become outdated
# Cookie handling has known issues
bas
import bas
# Paste curl from DevTools — done
s = bas.from_curl(r'''curl "https://example.com" -b "session=abc"''')
r = s.get("https://example.com")
# All headers auto-applied
# Cookies auto-injected
# Zero setup, zero dependencies
API Reference
bas.from_curl(curl_cmd, **kwargs) → Session
Create a Session from a curl command. Main entry point.
bas.from_headers(url, headers, cookies, **kwargs) → Session
Create a Session from raw headers and cookies.
bas.Session(headers, cookies, verify, timeout, allow_redirects, max_redirects)
Pure Python HTTP session. Zero external dependencies.
Methods:
get(url, **kwargs)→ Responsepost(url, **kwargs)→ Responseput(url, **kwargs)→ Responsedelete(url, **kwargs)→ Responsepatch(url, **kwargs)→ Responsehead(url, **kwargs)→ Responseset_cookie(name, value, domain, path)→ Noneget_cookies(url)→ dictclear_cookies()→ Nonesave_cookies(filepath, format)→ Noneload_cookies(filepath, format)→ None
bas.Cookie(name, value, domain, path, expires, max_age, secure, http_only, same_site)
Individual cookie object with RFC 6265 compliance.
bas.CookieJar
Thread-safe cookie container. Full RFC 6265 domain/path matching.
Methods:
add(cookie)→ Noneremove(cookie)→ Noneget(name, domain, path)→ Cookie | Nonematch(url)→ list[Cookie]to_header(url)→ strparse_set_cookie(header, url)→ Cookiesave_json(filepath)→ Noneload_json(filepath)→ Nonesave_netscape(filepath)→ Noneload_netscape(filepath)→ None
bas.Response
HTTP response object.
Properties:
status_code(int): HTTP status codeok(bool): True if status < 400text(str): Decoded text contentbody(bytes): Raw bytesjson(Any): Parsed JSONheaders(Headers): Response headersurl(str): Final URLelapsed(float): Response timehistory(list): Redirect historycookies(CookieJar): Cookie jar
License
MIT
Release files for bas-http 1.0.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| bas_http-1.0.4.tar.gz | 47.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bas_http-1.0.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 101.4 kB
Release files / bas_http-1.0.4.tar.gz
| Download URL | bas_http-1.0.4.tar.gz |
|---|---|
| Size | 47.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
84dc4eea7827579c892bf0cdcf5add662e7d6629a45f9af0932eb78f591c4624
|
|
BLAKE2b-256 checksum How to use checksums |
11e58feba31a0b1bdc65ccfc1cf4fff7db22fff34c5371cfd6fda9b0e9feafd5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|
Release files / bas_http-1.0.4-py3-none-any.whl
| Download URL | bas_http-1.0.4-py3-none-any.whl |
|---|---|
| Size | 53.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
778468bb17cfabdbdb8f05061afc4d9fcdf4933726df24bc470019af4f2daf26
|
|
BLAKE2b-256 checksum How to use checksums |
a9ceb6d8efed52e1f084ff82e55c1e8826f07959b5cca346bf4caf21cf9287c6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|