Skip to main content

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.

Python 3.11+ License: MIT Code style: ruff Typed

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_key with 0600 permissions
  • 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


Built for automating your own data access.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

graftpunk-1.2.0.tar.gz (271.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

graftpunk-1.2.0-py3-none-any.whl (95.3 kB view details)

Uploaded Python 3

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

Hashes for graftpunk-1.2.0.tar.gz
Algorithm Hash digest
SHA256 a23e75e91a37e5e7f4a494bd3e06fd8994ce4889f8d20613b87b63709a933240
MD5 fdc6db70e2c7e033c5e88460372ab7f5
BLAKE2b-256 4361678060ffbcf23869379b9f13d5639a26a4ef4aa141fa0d81d5ce6b2cb06c

See more details on using hashes here.

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

Hashes for graftpunk-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e11711653b1a768ab3081ef054269c5916fdd333db749d34a14d02e0eb7bc54c
MD5 c9577afedb967289b9224dba3169fb93
BLAKE2b-256 87fd5a4c06d026ac2bbd2d06728c9282571a781ad878fb67c1dcf6d5beabe9bc

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page