Skip to main content

bas

Copy-paste your browser's request, bas handles the rest.

No impersonation needed. No fingerprint chasing. No broken cookies. Just grab your headers + cookies from DevTools and go.

Why bas?

Problem bas bas
Cookies lost during redirects BUG Fixed
Cookies not accumulating across requests BUG Fixed
Manual Cookie header construction Yes Auto-injected
Requires curl-impersonate Yes No — pure Python
Browser fingerprint updates Constant chase None — bring your own headers
External dependencies Yes Zero

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 bas

bas (BROKEN)

from curl_cffi.requests import Session

s = Session(impersonate="chrome131")

# Cookies lost during redirects!
r1 = s.get("https://example.com/page")  # 302 redirect
# r1 is missing cookies from Set-Cookie headers!

# Cookies not accumulating!
r2 = s.get("https://example.com/page")
# r2 has LOST cookies from r1!

bas (FIXED)

import bas

s = bas.from_curl(r'''curl "https://example.com" -b "session=abc"''')

# Cookies survive redirects!
r1 = s.get("https://example.com/page")  # 302 redirect
# ALL cookies preserved through redirect

# Cookies accumulate!
r2 = s.get("https://example.com/dashboard")
# r2 has ALL cookies from r1 + new ones

# No manual Cookie header needed!
# bas auto-injects cookies from the jar

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) → Response
  • post(url, **kwargs) → Response
  • put(url, **kwargs) → Response
  • delete(url, **kwargs) → Response
  • patch(url, **kwargs) → Response
  • head(url, **kwargs) → Response
  • set_cookie(name, value, domain, path) → None
  • get_cookies(url) → dict
  • clear_cookies() → None
  • save_cookies(filepath, format) → None
  • load_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) → None
  • remove(cookie) → None
  • get(name, domain, path) → Cookie | None
  • match(url) → list[Cookie]
  • to_header(url) → str
  • parse_set_cookie(header, url) → Cookie
  • save_json(filepath) → None
  • load_json(filepath) → None
  • save_netscape(filepath) → None
  • load_netscape(filepath) → None

bas.Response

HTTP response object.

Properties:

  • status_code (int): HTTP status code
  • ok (bool): True if status < 400
  • text (str): Decoded text content
  • body (bytes): Raw bytes
  • json (Any): Parsed JSON
  • headers (Headers): Response headers
  • url (str): Final URL
  • elapsed (float): Response time
  • history (list): Redirect history
  • cookies (CookieJar): Cookie jar

License

MIT

Release files for bas-http 1.0.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bas-http 1.0.3
File Size Uploaded
bas_http-1.0.3.tar.gz 46.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for bas-http 1.0.3
File Interpreter ABI Platform
bas_http-1.0.3-py3-none-any.whl Python 3 none any Details

Total release size: 100.2 kB

Release files / bas_http-1.0.3.tar.gz

Download URL bas_http-1.0.3.tar.gz
Size 46.9 kB
Tags Source
SHA-256 checksum
How to use checksums
feac9bcf2280a2ff2d4d75bd2264d93dda6aafc81dab9aedb72ad42400fce8ba
BLAKE2b-256 checksum
How to use checksums
f085cba3ca0d71c0a51f1c958d326d5db279c5309250035b86009710cf6248d4
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.3-py3-none-any.whl

Download URL bas_http-1.0.3-py3-none-any.whl
Size 53.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d04808c8b906e51400b446e9f10ecfa83552c5e0f68089db469001ac48d42ab4
BLAKE2b-256 checksum
How to use checksums
c3f95db71ed4262999285d49be366517eb95781aea450b962ffc775aedbc7f43
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Release history Release notifications | RSS feed

1.0.4

2 release files

This release

1.0.3 This release

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page