Turn any website into an API. Graft scriptable access onto authenticated web services.
Project description
๐ graftpunk
Turn any website into an API.
Graft scriptable access onto authenticated web services.
Installation โข Quick Start โข CLI โข Roadmap โข Plugins
The Problem
That service has your dataโbut no API.
Your bank. Your 401k provider. Your insurance portal. Your HR system. They all have dashboards full of documents and data that belong to you, but no way to access them programmatically.
You're left with two options: click through the UI manually every time, or give up.
graftpunk gives you a third option.
The Solution
Log in once, script forever.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โ 1. LOG IN 2. CACHE 3. SCRIPT โ
โ โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โ
โ โ Browser โ โ Encrypted โ โ Python โ โ
โ โ Session โโโโโโโโโถ โ Storage โโโโโโโโโถ โ Script โ โ
โ โ โ โ โ โ โ โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โ
โ โ
โ Log in manually Session cached Use the session โ
โ or with a plugin with AES-128 to make requests โ
โ encryption like a real API โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Once your session is cached, you can:
- Make HTTP requests with your authenticated cookies
- Reverse-engineer XHR calls from browser dev tools
- Build CLI tools that feel like real APIs
- Automate downloads of documents and data
- Keep sessions alive with background daemons
What You Can Build
With graftpunk as your foundation, you can turn any authenticated website into a terminal-based interface:
# Download your latest bank statements
gp mybank statements --month january --output ./statements/
# Export transactions to CSV
gp mybank transactions --start 2024-01-01 --format csv > transactions.csv
# Check your 401k balance
gp my401k balance
# โ Total: $142,857.32 (+2.4% this month)
# Download insurance documents
gp insurance documents --type claims --year 2024
# โ Downloaded 12 documents to ./claims/
These aren't real APIsโthey're commands defined in graftpunk plugins that make the same XHR calls the website makes. To anyone watching, it looks like magic. To you, it's just automation.
Installation
pip install graftpunk
With cloud storage:
pip install graftpunk[supabase] # Supabase backend
pip install graftpunk[s3] # AWS S3 backend
pip install graftpunk[nodriver] # NoDriver backend (better anti-detection)
pip install graftpunk[standard] # Recommended: NoDriver + stealth
pip install graftpunk[all] # Everything
Quick Start
1. Cache a Session
from graftpunk import BrowserSession, cache_session
# Create a stealth browser (avoids bot detection)
# Options: backend="selenium" (default), "nodriver" (better anti-detection)
session = BrowserSession(headless=False, use_stealth=True)
# Navigate to login page
session.driver.get("https://app.example.com/login")
# Log in manually in the browser window...
# (or automate it with a plugin)
# Cache the authenticated session
cache_session(session, "example")
2. Use It Like an API
from graftpunk import load_session_for_api
# Load your cached session (no browser needed)
api = load_session_for_api("example")
# Make authenticated requests
response = api.get("https://app.example.com/api/internal/documents")
documents = response.json()
for doc in documents:
print(f"Downloading {doc['name']}...")
content = api.get(doc['download_url']).content
with open(doc['name'], 'wb') as f:
f.write(content)
3. Keep It Alive
Sessions expire. graftpunk can keep them alive in the background:
# Your keepalive handler pings the site periodically
# to prevent session timeout
Features
| Feature | Why It Matters | |
|---|---|---|
| ๐ฅท | Stealth Mode | Many sites block automation. graftpunk supports multiple backends: Selenium with undetected-chromedriver, or NoDriver for CDP-direct automation without WebDriver detection. |
| ๐ | Encrypted Storage | Sessions contain sensitive auth tokens. graftpunk encrypts everything with AES-128 (Fernet). |
| โ๏ธ | Cloud Storage | Access your sessions from anywhere. Store in Supabase or S3 for multi-machine workflows. |
| ๐ | Keepalive Daemon | Sessions expire. graftpunk can ping sites in the background to keep you logged in. |
| ๐ | Plugin System | Define commands for reverse-engineered APIs. Python for complex logic, YAML for simple calls. |
| ๐ ๏ธ | Beautiful CLI | Manage sessions from the terminal with rich, colorful output. |
CLI
$ gp --help
๐ graftpunk - turn any website into an API
Graft scriptable access onto authenticated web services.
Log in once, script forever.
Quick start:
gp list Show all cached sessions
gp show <name> View session details
gp clear <name> Remove a session
gp config Show current configuration
Commands:
list List all cached sessions with status and metadata.
show Show detailed information about a cached session.
clear Remove cached session(s).
export Export session cookies to HTTPie format.
import-har Import HAR file and generate a plugin.
config Show current graftpunk configuration.
plugins List discovered plugins.
version Show graftpunk version and installation info.
keepalive Manage the session keepalive daemon.
List Sessions
$ gp list
๐ Cached Sessions
โโโโโโโโโโโโโโโณโโโโโโโโโโโโโโโโโโโณโโโโโโโโโโโโโณโโโโโโโโโโณโโโโโโโโโโโโโโโโโโโ
โ Session โ Domain โ Status โ Cookies โ Last Modified โ
โกโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฉ
โ mybank โ secure.mybank.comโ โ active โ 18 โ 2024-01-15 09:30 โ
โ my401k โ participant.401k โ โ active โ 12 โ 2024-01-14 14:22 โ
โ insurance โ portal.ins.com โ โ expired โ 8 โ 2024-01-01 11:00 โ
โโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโดโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโ
3 session(s) cached
Export to HTTPie
$ gp export mybank
โ Exported to: ~/.config/httpie/sessions/secure.mybank.com/mybank.json
Usage:
http --session=mybank https://secure.mybank.com/api/accounts
Import from HAR
Generate plugins from browser dev tools network captures:
$ gp import-har auth-flow.har --name mybank
Parsing HAR file: auth-flow.har
Found 127 HTTP requests
Site: mybank (secure.mybank.com)
Auth Flow Detected (3 steps):
1. GET /login (form page)
2. POST /auth/login (credentials submitted)
3. GET /dashboard (authenticated, 2 cookies set)
Session Cookies: sessionId, authToken
API Endpoints (5 discovered):
GET /api/accounts
GET /api/transactions
POST /api/transfer
Generated plugin: ~/.config/graftpunk/plugins/mybank.py
Options:
--format python|yaml- Output format (default: python)--output PATH- Custom output path--dry-run- Preview without writing--no-discover-api- Skip API endpoint discovery
Configuration
| Variable | Default | Description |
|---|---|---|
GRAFTPUNK_STORAGE_BACKEND |
local |
Storage: local, supabase, or s3 |
GRAFTPUNK_CONFIG_DIR |
~/.config/graftpunk |
Config and encryption key location |
GRAFTPUNK_SESSION_TTL_HOURS |
720 |
Session lifetime (30 days) |
GRAFTPUNK_LOG_LEVEL |
INFO |
Logging verbosity |
Browser Backends
graftpunk supports multiple browser automation backends:
| Backend | Install | Best For |
|---|---|---|
selenium |
Default | Simple sites, backward compatibility |
nodriver |
pip install graftpunk[nodriver] |
Enterprise sites, better anti-detection |
from graftpunk import BrowserSession, get_backend, list_backends
# See available backends
print(list_backends()) # ['legacy', 'nodriver', 'selenium']
# Use BrowserSession with explicit backend
session = BrowserSession(backend="nodriver", headless=False)
# Or use backends directly
from graftpunk import get_backend
backend = get_backend("nodriver", headless=False)
with backend:
backend.navigate("https://example.com")
cookies = backend.get_cookies()
Why NoDriver? NoDriver uses Chrome DevTools Protocol (CDP) directly without the WebDriver binary, eliminating a common detection vector used by anti-bot systems.
Roadmap
graftpunk is actively developed. Here's what's coming:
๐ง Plugin Auto-Generation Wizard
Stop writing plugins by hand.
A built-in tool that watches you log in and generates the plugin code automatically:
$ gp wizard mybank
โ Opening browser to capture auth flow...
โ Log in normally (use dummy creds if you prefer)
โ Capturing cookies, headers, session validation...
โ Generated plugin: ~/.config/graftpunk/plugins/mybank.py
# Next time, login is automated:
$ gp login mybank
๐ Example Plugins
Templates and examples for common auth patterns (form login, OAuth, SSO).
Plugins
graftpunk is extensible via Python entry points or YAML configuration.
Python Plugin (Complex Logic)
# my_plugins/mybank.py
from graftpunk.plugins import SitePlugin, command
class MyBankPlugin(SitePlugin):
site_name = "mybank"
session_name = "mybank"
@command(help="List all accounts")
def accounts(self, session):
return session.get("https://mybank.com/api/accounts").json()
@command(help="Get statements for a month")
def statements(self, session, month: str, year: int = 2024):
url = f"https://mybank.com/api/statements/{year}/{month}"
return session.get(url).json()
Register in pyproject.toml:
[project.entry-points."graftpunk.cli_plugins"]
mybank = "my_plugins.mybank:MyBankPlugin"
YAML Plugin (Simple Calls)
For straightforward GET/POST calls, no Python needed:
# ~/.config/graftpunk/plugins/mybank.yaml
site_name: mybank
session_name: mybank
help: "Commands for MyBank"
commands:
accounts:
help: "List all accounts"
method: GET
url: "https://mybank.com/api/accounts"
statements:
help: "Get statements for a month"
method: GET
url: "https://mybank.com/api/statements/{year}/{month}"
params:
- name: month
required: true
help: "Month name"
- name: year
default: 2024
help: "Year"
Then use directly:
gp mybank accounts
gp mybank statements --month january --year 2024
Security
Your Data, Your Rules
graftpunk is for automating access to your own accounts. You're not scraping other people's dataโyou're building tools to access information that already belongs to you.
Some services may consider automation a ToS violation. Use your judgment.
Encryption
- Algorithm: Fernet (AES-128-CBC + HMAC-SHA256)
- Key storage:
~/.config/graftpunk/.session_keywith0600permissions - Integrity: SHA-256 checksum validated before deserializing
โ ๏ธ Pickle Warning
graftpunk uses Python's pickle for serialization. Only load sessions you created.
Best Practices
- Keep your encryption key secure
- Don't share session files
- Run graftpunk on trusted machines
- Use unique, strong passwords for automated accounts
Development
git clone https://github.com/stavxyz/graftpunk.git
cd graftpunk
just setup # Install deps with uv
just check # Run lint, typecheck, tests
just build # Build for PyPI
Requires uv for development.
License
MIT Licenseโsee LICENSE.
Acknowledgments
- requestium โ Selenium + Requests integration
- undetected-chromedriver โ Anti-detection ChromeDriver
- selenium-stealth โ Stealth patches
- cryptography โ Encryption primitives
- rich โ Beautiful terminal output
- typer โ CLI framework
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file graftpunk-1.2.0.tar.gz.
File metadata
- Download URL: graftpunk-1.2.0.tar.gz
- Upload date:
- Size: 271.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a23e75e91a37e5e7f4a494bd3e06fd8994ce4889f8d20613b87b63709a933240
|
|
| MD5 |
fdc6db70e2c7e033c5e88460372ab7f5
|
|
| BLAKE2b-256 |
4361678060ffbcf23869379b9f13d5639a26a4ef4aa141fa0d81d5ce6b2cb06c
|
File details
Details for the file graftpunk-1.2.0-py3-none-any.whl.
File metadata
- Download URL: graftpunk-1.2.0-py3-none-any.whl
- Upload date:
- Size: 95.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e11711653b1a768ab3081ef054269c5916fdd333db749d34a14d02e0eb7bc54c
|
|
| MD5 |
c9577afedb967289b9224dba3169fb93
|
|
| BLAKE2b-256 |
87fd5a4c06d026ac2bbd2d06728c9282571a781ad878fb67c1dcf6d5beabe9bc
|