Skip to main content

Sela Network Python SDK - P2P client for browser automation agents

Project description

Sela Network Python SDK

Python bindings for the Sela Network client SDK. Browse any website and get back structured data through distributed browser agents — no CAPTCHAs, no bot detection.

Installation

pip install sela-browse-sdk

Quick Start

import asyncio
import json
from sela_browse_sdk import SelaClient, BrowseOptions

async def main():
    # 1. Create client with your API key (get one at https://app.selanet.ai)
    client = await SelaClient.with_api_key("sk_live_xxx")

    # 2. Browse a URL
    result = await client.browse(
        url="https://x.com/search?q=ai&f=live",
        options=BrowseOptions(parse_only=True),
    )

    # 3. Extract structured data
    for item in result.page.content:
        fields = json.loads(item.fields_json)
        print(fields["text"])
        print(fields["author_username"], "—", fields.get("like_count"), "likes")

    await client.shutdown()

asyncio.run(main())

Example response:

{
  "page": {
    "page_type": "x_com::search",
    "content": [
      {
        "content_type": "tweet",
        "fields": {
          "text": "AI is transforming how we build software...",
          "author_username": "johndoe",
          "like_count": 142,
          "retweet_count": 38
        }
      }
    ]
  }
}

Note: fields_json and collection_stats are JSON strings in Python. Always use json.loads() to parse them.


Examples

All examples below assume you've created a client as shown in Quick Start:

client = await SelaClient.with_api_key("sk_live_xxx")

Browse Any Website (Markdown Extraction)

For general websites (not X or Xiaohongshu), use extract_format='markdown' to get readable content:

result = await client.browse(
    url="https://en.wikipedia.org/wiki/Python_(programming_language)",
    options=BrowseOptions(parse_only=True, extract_format="markdown"),
)

print(result.extracted_content)  # Clean markdown text

Important: extract_format='schema' (default) only works for supported platforms (X, Xiaohongshu). For all other sites, you must use 'markdown' or 'html' — otherwise you'll get an empty response.

Collect More Items (Infinite Scroll)

Use count to collect multiple items by scrolling the page:

import json

# Collect 50 tweets by scrolling
result = await client.browse(
    url="https://x.com/search?q=python&f=live",
    options=BrowseOptions(parse_only=True, count=50),
)

for item in result.page.content:
    fields = json.loads(item.fields_json)
    print(fields["text"][:80])

# Check collection stats
if result.collection_stats:
    stats = json.loads(result.collection_stats)
    print(f"Collected: {stats}")

Xiaohongshu (RedNote)

Search Posts

When using platform params (xiaohongshu_params, x_params), pass url=None — the URL is determined by the params.

import json
from sela_browse_sdk import BrowseOptions, XiaohongshuParams

# Search and collect 30 posts
result = await client.browse(
    url=None,
    options=BrowseOptions(
        xiaohongshu_params=XiaohongshuParams(
            type="search",
            query="맛집 추천",
        ),
        count=30,
        parse_only=True,
    ),
)

for item in result.page.content:
    fields = json.loads(item.fields_json)
    print(fields.get("title", ""), "—", fields.get("like_count", ""))

Browse a Note by URL

Use type="note" with a url to browse a note directly by URL:

result = await client.browse(
    url=None,
    options=BrowseOptions(
        xiaohongshu_params=XiaohongshuParams(
            type="note",
            url="https://www.xiaohongshu.com/explore/682e7c72000000000b03a68a",
        ),
        parse_only=True,
    ),
)

Browse a Note by ID

Use type="note" with a note_id to browse a specific note:

result = await client.browse(
    url=None,
    options=BrowseOptions(
        xiaohongshu_params=XiaohongshuParams(
            type="note",
            note_id="682e7c72000000000b03a68a",
        ),
        parse_only=True,
    ),
)

XiaohongshuParams Types

Type Required Fields Description
"search" query Search posts by keyword
"note" note_id or url Browse a specific note by ID or URL
"profile" user_id Browse a user profile
"url" url Browse any Xiaohongshu URL directly

X (Twitter)

Search Tweets

from sela_browse_sdk import BrowseOptions, XParams

result = await client.browse(
    url=None,
    options=BrowseOptions(
        x_params=XParams(
            type="search",
            query="sela network",
            min_likes=100,
        ),
        count=30,
        parse_only=True,
    ),
)

Browse a Profile

from sela_browse_sdk import BrowseOptions, XParams

result = await client.browse(
    url=None,
    options=BrowseOptions(
        x_params=XParams(type="profile", username="elonmusk", tab="media"),
        parse_only=True,
    ),
)

XParams Types

Type Required Fields Description
"search" query Advanced search with filters
"profile" username User profile (optional tab: posts/replies/media/likes)
"post" username, tweet_id Single tweet

Browse Multiple URLs in Parallel

browse_parallel_collect() distributes URLs across agents for concurrent browsing:

import asyncio
from sela_browse_sdk import (
    SelaClient, BrowseOptions,
    XiaohongshuParams, ParallelBrowseItem,
)

NOTE_URLS = [
    "https://www.xiaohongshu.com/explore/682e7c72000000000b03a68a",
    "https://www.xiaohongshu.com/explore/682e0a26000000000d007040",
    "https://www.xiaohongshu.com/explore/682e5f1d000000001203ae3e",
    "https://www.xiaohongshu.com/explore/682dd62f000000000c037bfc",
    "https://www.xiaohongshu.com/explore/682e4e43000000000b03a04e",
]

async def main():
    client = await SelaClient.with_api_key("sk_live_xxx")

    # Build parallel items
    items = [
        ParallelBrowseItem(
            url=None,
            options=BrowseOptions(
                xiaohongshu_params=XiaohongshuParams(type="note", url=note_url),
                parse_only=True,
            ),
        )
        for note_url in NOTE_URLS
    ]

    # Browse all concurrently (max 5 per agent)
    results = await client.browse_parallel_collect(items, max_concurrent_per_agent=5)

    for r in results:
        if r.error:
            print(f"[{r.index}] FAIL: {r.error}")
        else:
            title = r.response.page.metadata.title or "N/A"
            print(f"[{r.index}] {title[:40]} ({r.elapsed_ms}ms)")

    await client.shutdown()

asyncio.run(main())

Batching Large Requests

For many URLs, batch them to avoid overwhelming the network:

batch_size = 5
for i in range(0, len(all_urls), batch_size):
    batch = all_urls[i : i + batch_size]
    items = [
        ParallelBrowseItem(
            url=None,
            options=BrowseOptions(
                xiaohongshu_params=XiaohongshuParams(type="note", url=url),
                parse_only=True,
            ),
        )
        for url in batch
    ]
    results = await client.browse_parallel_collect(items, max_concurrent_per_agent=5)
    # process results...

ParallelBrowseResult fields:

Field Type Description
index int Original position in the input list
url str The URL that was browsed
response SemanticResponse? Result (None if error)
error str? Error message (None if success)
agent_peer_id str Which agent handled this URL
elapsed_ms int Time taken in milliseconds

API Reference

SelaClient

Creating a Client

from sela_browse_sdk import SelaClient

# Recommended — just pass your API key
client = await SelaClient.with_api_key("sk_live_xxx")

Methods

Method Description
browse(url, options?) Browse a URL and get semantic content
browse_parallel_collect(items, max_concurrent?) Browse multiple URLs in parallel
search(query, target_url?, options?) Search on a platform
shutdown(timeout_ms?) Gracefully shutdown the client
state() Get current client state

Configuration

BrowseOptions

BrowseOptions(
    parse_only=True,            # Always recommended — skip AI planning, extract only
    count=None,                 # Items to collect (enables infinite scroll)
    extract_format=None,        # "schema" (default), "markdown", "html"
    session_id=None,            # Reuse existing browser session
    timeout_ms=None,            # Request timeout in ms
    x_params=None,              # X (Twitter) search/profile/post params
    xiaohongshu_params=None,    # Xiaohongshu search/note/profile/url params
    agent_id=None,              # Target a specific agent by peer ID
    query=None,                 # Hint for semantic extraction
    include_html=None,          # Return raw HTML in response
    api_key=None,               # Override API key per-request
)

Important: extract_format='schema' only works for supported platforms (X, Xiaohongshu). For all other sites, you must use 'markdown' or 'html'.

Advanced: SelaClientConfig

For fine-grained control, create a client with SelaClientConfig:

from sela_browse_sdk import SelaClient, SelaClientConfig

config = SelaClientConfig(
    bootstrap_nodes=[],
    api_key="sk_live_xxx",               # Required — your API key
    api_server_url=None,                 # Default: https://api.selanet.ai
    connection_timeout_secs=30,
    request_timeout_secs=120,
)
client = await SelaClient.create(config)

Response Types

SemanticResponse

result = await client.browse(url, options)

result.session_id           # Browser session ID
result.page                 # SemanticPage
result.page.page_type       # e.g., "x_com::search", "generic"
result.page.content         # list[SemanticContent]
result.page.metadata.title  # Page title
result.collection_stats     # JSON string (when count is used) — use json.loads()
result.extracted_content    # Markdown/HTML text (when extract_format is set)
result.extract_format       # "schema", "html", or "markdown"
result.agent_version        # Agent node version (e.g., "0.2.6")
result.agent_id             # Agent peer ID that processed the request

SemanticContent

for item in result.page.content:
    item.content_type       # e.g., "tweet", "note", "user"
    item.content_id         # Unique ID (if available)
    item.fields_json        # JSON string — use json.loads()
    item.actions            # list[AvailableAction]

Error Handling

from sela_browse_sdk import SelaError

try:
    result = await client.browse(url, options)
except SelaError.ConfigurationError as e:
    print(f"Bad config: {e}")
except SelaError.TimeoutError as e:
    print(f"Request timed out: {e}")
except SelaError.BrowseError as e:
    print(f"Browse failed: {e}")
except SelaError as e:
    print(f"Error: {e}")
Error When
ConfigurationError Invalid config (bad API key format, missing fields)
TimeoutError Request timed out
BrowseError Browse operation failed on agent
InternalError Unexpected internal error

Development

Building from Source

Requires: Rust 1.70+, Python 3.9+, maturin

pip install maturin

cd client-sdk/crates/sela-py
maturin develop --release   # Install in dev mode
maturin build --release     # Build wheel

Running the Example

cd client-sdk
python examples/browse_example.py

Running Tests

cargo test -p sela-py

License

MIT License - see LICENSE for details.

Project details


Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

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

sela_browse_sdk-1.0.13-py3-none-macosx_11_0_arm64.whl (4.0 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

File details

Details for the file sela_browse_sdk-1.0.13-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for sela_browse_sdk-1.0.13-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 227cd618e851bb5be7b3998345adc16b2e34b0047e3850c786e1067737160bef
MD5 46b39f1b60bdb989ff31bebde8ff74e4
BLAKE2b-256 47b746130ce3d30695881d86114ff2efbb9674a19870d7e71bc1e947ffce05b4

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