Skip to main content

Scraping-friendly HTTP, string parsing, JSON helpers, and AI parsing.

Project description

Respondo - Web scraping, text extraction & AI parsing for Python

PyPI version Python License Downloads Discord

Zero dependencies · Type hints · 10 AI providers · Structured outputs

Installation · Quick Start · Documentation · AI Parsing


Installation

pip install respondo

Quick Start

from respondo import between, extract_emails, parse_ai, Response

# Extract text between delimiters
between("<title>Hello World</title>", "<title>", "</title>")
# => "Hello World"

# Find all emails in text
extract_emails("Contact us at hello@example.com or support@example.com")
# => ["hello@example.com", "support@example.com"]

# AI-powered extraction (10 providers supported)
parse_ai("Extract the price", "The item costs $29.99", provider="openai")
# => "$29.99"

Documentation

Text Extraction

from respondo import between, betweens, regex_first, regex_all

# Extract between delimiters
between("Hello [World]!", "[", "]")           # => "World"
betweens("[a][b][c]", "[", "]")               # => ["a", "b", "c"]

# Regex extraction (returns capture group if present)
regex_first("Price: $42.99", r"\$([\d.]+)")   # => "42.99"
regex_all("<id>1</id><id>2</id>", r"<id>(\d+)</id>")  # => ["1", "2"]

Extract Emails, URLs & Numbers

from respondo import extract_emails, extract_urls, extract_numbers

text = "Contact john@example.com or visit https://example.com. Price: $99.99"

extract_emails(text)   # => ["john@example.com"]
extract_urls(text)     # => ["https://example.com"]
extract_numbers(text)  # => ["$99.99"]

Validation

from respondo import is_valid_email, is_valid_url, is_valid_json

is_valid_email("test@example.com")  # => True
is_valid_url("https://example.com") # => True
is_valid_json('{"key": "value"}')   # => True

Text Utilities

from respondo import normalize_space, clean_text, strip_tags, unescape_html

normalize_space("  hello   world  ")          # => "hello world"
clean_text("Cafe - Recipe's")                 # => "Cafe - Recipe's" (normalized)
strip_tags("<p>Hello <b>World</b></p>")       # => "Hello World"
unescape_html("&lt;div&gt;")                  # => "<div>"

HTML Parsing

from respondo import get_text, extract_links, extract_meta, extract_images, html_to_markdown

html = """
<html>
  <head>
    <title>My Page</title>
    <meta name="description" content="A sample page">
    <meta property="og:image" content="https://example.com/image.jpg">
  </head>
  <body>
    <h1>Welcome</h1>
    <p>Visit our <a href="/about">about page</a></p>
    <img src="/logo.png" alt="Logo">
  </body>
</html>
"""

# Extract visible text
get_text(html)  # => "My Page Welcome Visit our about page"

# Extract all links
extract_links(html, base="https://example.com")
# => ["https://example.com/about", "https://example.com/logo.png"]

# Extract meta tags (title, description, og:*, twitter:*)
extract_meta(html)
# => {"title": "My Page", "description": "A sample page", "og:image": "https://example.com/image.jpg"}

# Extract images with attributes
extract_images(html, base="https://example.com")
# => [{"src": "https://example.com/logo.png", "alt": "Logo", ...}]

# Convert HTML to Markdown
html_to_markdown("<h1>Title</h1><p>Hello <strong>world</strong></p>")
# => "# Title\n\nHello **world**"

Forms & Tables

from respondo import extract_forms, extract_tables

# Extract forms with all fields
html = '<form action="/login"><input name="user"><input name="pass" type="password"></form>'
extract_forms(html, base="https://example.com")
# => [{"action": "https://example.com/login", "method": "get", "fields": {"user": "", "pass": ""}}]

# Extract tables as structured data
html = "<table><tr><th>Name</th><th>Age</th></tr><tr><td>Alice</td><td>30</td></tr></table>"
extract_tables(html)
# => [{"headers": ["Name", "Age"], "rows": [{"Name": "Alice", "Age": "30"}]}]

JSON Utilities

from respondo import find_first_json, find_all_json, json_get

# Find JSON embedded in text
find_first_json('callback({"user": "alice", "id": 42})')
# => {"user": "alice", "id": 42}

# Safe nested access (never throws)
data = {"user": {"profile": {"name": "Alice"}}}
json_get(data, "user", "profile", "name")     # => "Alice"
json_get(data, "user", "missing", "key")      # => None

# Works with arrays too
json_get([{"id": 1}, {"id": 2}], 0, "id")     # => 1

Response Handling

from respondo import Response

resp = Response(
    status=200,
    headers={"Content-Type": "application/json"},
    body=b'{"success": true}'
)

# Status checks
resp.is_success()        # => True (200-299)
resp.is_redirect()       # => False (300-399)
resp.is_client_error()   # => False (400-499)

# Body access
resp.text                # => '{"success": true}'
resp.json()              # => {"success": True}

# Headers (case-insensitive)
resp.header("content-type")       # => "application/json"
resp.content_type()               # => ("application/json", "")

# Cookie parsing
resp.cookies()
# => [{"name": "session", "value": "abc", "attrs": {"path": "/", "httponly": ""}}]

Encoding Utilities

from respondo import url_encode, url_decode, b64_encode, b64_decode

# URL encoding
url_encode({"q": "hello world", "page": 1})   # => "q=hello+world&page=1"
url_decode("a=1&b=2&b=3")                     # => {"a": ["1"], "b": ["2", "3"]}

# Base64
b64_encode("hello")                           # => "aGVsbG8="
b64_decode("aGVsbG8=")                        # => b"hello"

Social Media Extraction

from respondo import (
    extract_discord_invites, extract_telegram_links, extract_twitter_links,
    extract_youtube_links, extract_instagram_links, extract_tiktok_links,
    extract_reddit_links, extract_social_links
)

# Extract individual platforms
extract_discord_invites("Join discord.gg/abc123")     # => ["abc123"]
extract_telegram_links("Follow t.me/channel")         # => ["channel"]
extract_twitter_links("Check twitter.com/elonmusk")   # => ["https://twitter.com/elonmusk"]
extract_youtube_links("Watch https://youtu.be/xyz")   # => ["https://youtu.be/xyz"]

# Extract all social links at once
extract_social_links("discord.gg/test t.me/channel twitter.com/user")
# => {"discord": ["test"], "telegram": ["channel"], "twitter": ["https://twitter.com/user"], ...}

Crypto/Web3 Extraction

from respondo import (
    extract_eth_addresses, extract_btc_addresses, extract_sol_addresses,
    extract_ens_names, extract_crypto_addresses
)

# Ethereum
extract_eth_addresses("Send to 0x742d35Cc6634C0532925a3b844Bc9e7595f1dE2B")
# => ["0x742d35Cc6634C0532925a3b844Bc9e7595f1dE2B"]

# Bitcoin (legacy and SegWit)
extract_btc_addresses("BTC: 1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2")
# => ["1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2"]

# ENS names
extract_ens_names("Contact vitalik.eth")  # => ["vitalik.eth"]

# All crypto at once
extract_crypto_addresses(text)  # => {"eth": [...], "btc": [...], "sol": [...], "ens": [...]}

Security Token Extraction

from respondo import extract_api_keys, extract_jwts, decode_jwt, extract_bearer_tokens

# Detect exposed API keys (OpenAI, AWS, Stripe, GitHub, Google, etc.)
extract_api_keys("OPENAI_API_KEY=sk-abc123...")
# => [{"type": "openai", "key": "sk-abc123..."}]

# Extract and decode JWTs
tokens = extract_jwts("token=eyJhbGciOiJIUzI1NiIs...")
decode_jwt(tokens[0])  # => {"header": {"alg": "HS256"}, "payload": {"sub": "123"}}

# Bearer tokens
extract_bearer_tokens("Authorization: Bearer abc123")  # => ["abc123"]

Contact Info Extraction

from respondo import extract_phone_numbers, extract_dates

extract_phone_numbers("Call +1 (555) 123-4567 or +44 20 7946 0958")
# => ["+1 (555) 123-4567", "+44 20 7946 0958"]

extract_dates("Date: 2024-01-15 and January 15, 2024")
# => ["2024-01-15", "January 15, 2024"]

Captcha Extraction & Detection

from respondo import (
    # Extraction
    extract_recaptcha_sitekey, extract_turnstile_sitekey, extract_hcaptcha_sitekey,
    extract_captcha_params,
    # Detection
    contains_recaptcha, contains_turnstile, contains_hcaptcha
)

html = '<div class="g-recaptcha" data-sitekey="6Lc..."></div>'

# Extract site keys for captcha solving services
extract_recaptcha_sitekey(html)   # => ["6Lc..."]
extract_turnstile_sitekey(html)   # => ["0x4AAA..."]
extract_hcaptcha_sitekey(html)    # => ["uuid-format-key"]

# Check what captcha is present
contains_recaptcha(html)          # => True
contains_turnstile(html)          # => False
contains_hcaptcha(html)           # => False

# Get all captcha params at once
extract_captcha_params(html)
# => {"recaptcha": [...], "turnstile": [...], "hcaptcha": [...]}

Network/Identifier Extraction

from respondo import (
    extract_ipv4, extract_ipv6, extract_ips, extract_domains,
    extract_uuids, extract_mac_addresses
)

extract_ipv4("Server: 192.168.1.1")                  # => ["192.168.1.1"]
extract_domains("Visit example.com or api.test.org") # => ["example.com", "api.test.org"]
extract_uuids("ID: 550e8400-e29b-41d4-a716-...")     # => ["550e8400-..."]
extract_mac_addresses("MAC: 00:1A:2B:3C:4D:5E")      # => ["00:1A:2B:3C:4D:5E"]

API/Endpoint Extraction

from respondo import extract_api_endpoints, extract_graphql_endpoints, extract_websocket_urls

extract_api_endpoints(js_code)      # => ["/api/v1/users", "https://api.example.com/v2/data"]
extract_graphql_endpoints(html)     # => ["/graphql", "/api/gql"]
extract_websocket_urls(html)        # => ["wss://example.com/socket"]

Media URL Extraction

from respondo import extract_video_urls, extract_audio_urls, extract_stream_urls

extract_video_urls(html)   # => ["https://cdn.com/video.mp4", "https://stream.com/playlist.m3u8"]
extract_audio_urls(html)   # => ["https://cdn.com/song.mp3"]
extract_stream_urls(html)  # => ["https://cdn.com/playlist.m3u8", "https://cdn.com/manifest.mpd"]

E-commerce Extraction

from respondo import extract_prices, extract_skus

extract_prices("Price: $19.99 and EUR 29.99")
# => [{"raw": "$19.99", "value": 19.99, "currency": "USD"},
#     {"raw": "EUR 29.99", "value": 29.99, "currency": "EUR"}]

extract_skus("SKU: ABC-12345")  # => ["ABC-12345"]

Structured Data Extraction

from respondo import (
    extract_canonical_url, extract_og_tags, extract_twitter_cards,
    extract_schema_org, extract_structured_data
)

# Individual extractions
extract_canonical_url(html)   # => "https://example.com/page"
extract_og_tags(html)         # => {"title": "My Page", "image": "https://..."}
extract_twitter_cards(html)   # => {"card": "summary", "site": "@example"}
extract_schema_org(html)      # => [{"@type": "Product", "name": "Widget"}]

# All structured data at once
extract_structured_data(html)
# => {"canonical": "...", "og": {...}, "twitter": {...}, "schema_org": [...]}

AI Parsing

Parse text using LLM APIs. 10 providers supported with structured output.

from respondo import parse_ai, parse_ai_json, list_providers

# See all providers
list_providers()
# => {"openai": "gpt-4o-mini", "anthropic": "claude-3-5-haiku-latest", ...}

# Basic extraction
parse_ai("Extract all prices", "$29.99 and $49.99", provider="openai")
# => "$29.99, $49.99"

# Custom model
parse_ai("Summarize", text, provider="anthropic", model="claude-3-5-sonnet-latest")

# JSON response
parse_ai_json("Extract name and age", "John is 30", provider="openai")
# => {"name": "John", "age": 30}

# Structured output with schema (enforced by provider)
schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "age": {"type": "integer"}
    },
    "required": ["name", "age"],
    "additionalProperties": False
}
parse_ai_json("Extract person", text, provider="openai", schema=schema)

Supported Providers

Provider Environment Variable Default Model
openai OPENAI_API_KEY gpt-4o-mini
anthropic ANTHROPIC_API_KEY claude-3-5-haiku-latest
gemini GEMINI_API_KEY gemini-2.0-flash
grok GROK_API_KEY grok-2-latest
mistral MISTRAL_API_KEY mistral-small-latest
groq GROQ_API_KEY llama-3.3-70b-versatile
cohere COHERE_API_KEY command-r
together TOGETHER_API_KEY Llama-3.3-70B-Instruct-Turbo
deepseek DEEPSEEK_API_KEY deepseek-chat
perplexity PERPLEXITY_API_KEY sonar

Features Overview

Features

Error Handling

All functions return empty values instead of raising exceptions - ideal for scraping workflows where missing data is expected.

Return Type On Failure
str ""
list []
dict {}
Any (JSON) None
between("no match", "<", ">")      # => ""
find_first_json("not json")        # => None
is_valid_email("invalid")          # => False
extract_emails("no emails here")   # => []
parse_ai("prompt", "text")         # => "" (if no API key)

MIT License - Made for web scrapers

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

respondo-0.4.0.tar.gz (31.9 kB view details)

Uploaded Source

Built Distribution

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

respondo-0.4.0-py3-none-any.whl (23.9 kB view details)

Uploaded Python 3

File details

Details for the file respondo-0.4.0.tar.gz.

File metadata

  • Download URL: respondo-0.4.0.tar.gz
  • Upload date:
  • Size: 31.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for respondo-0.4.0.tar.gz
Algorithm Hash digest
SHA256 e12b228a478780cec7840c8f0733f59acfde65ff7502ec03a4de58593ea62982
MD5 175dc3baa09bc928e523ffdf9251a69e
BLAKE2b-256 11f4371816c86cd57816428574846973648f6778bb2091ed0d7a1784c1271582

See more details on using hashes here.

File details

Details for the file respondo-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: respondo-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 23.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for respondo-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e1675e61c8825eeb9329888ff7d28e6d9d17382b5937ca1bb780b52f090b5418
MD5 3ecdb69c9b5672e022b71413c8514014
BLAKE2b-256 c7cc4431f6a6ee5e25a6ed854c9ab82ddc1d6731246d6b18226351b13ad03fb6

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