From 1f399993c90ac3a78ea97581c22f864c8ac88806 Mon Sep 17 00:00:00 2001 From: zlei9 Date: Sun, 29 Mar 2026 13:13:43 +0800 Subject: [PATCH] Initial commit with translated description --- SKILL.md | 71 ++++++++++++++++++++++++ _meta.json | 6 ++ scripts/desearch.py | 131 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 SKILL.md create mode 100644 _meta.json create mode 100644 scripts/desearch.py diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..14ef621 --- /dev/null +++ b/SKILL.md @@ -0,0 +1,71 @@ +--- +name: desearch-web-search +description: "搜索网页并获取实时SERP样式结果。" +metadata: {"clawdbot":{"emoji":"🌐","homepage":"https://desearch.ai","requires":{"env":["DESEARCH_API_KEY"]}}} +--- + +# Web Search By Desearch + +Real-time web search returning structured SERP-style results with titles, links, and snippets. + +## Quick Start + +1. Get an API key from https://console.desearch.ai +2. Set environment variable: `export DESEARCH_API_KEY='your-key-here'` + +## Usage + +```bash +# Basic web search +desearch.py web "quantum computing" + +# Paginated results +desearch.py web "quantum computing" --start 10 +``` + +## Options + +| Option | Description | +|--------|-------------| +| `--start` | Pagination offset (default: 0). Use to get the next page of results. | + +## Response + +### Example +```bash +desearch.py web "best sights in Georgia" +``` + +```json +{ + "data": [ + { + "title": "Cool places and fun things to do in Georgia ? : r/solotravel", + "snippet": "I was in Georgia earlier this month. My favorite place was Mtirala National Park in Adjara. The mountains and forest were absolutely beautiful ...", + "link": "https://www.reddit.com/r/solotravel/comments/py4wls/cool_places_and_fun_things_to_do_in_georgia/", + }, + ] +} +``` + +### Notes +- Returns up to 10 results per page. Use `--start` to paginate. + +### Errors +Status 401, Unauthorized (e.g., missing/invalid API key) +```json +{ + "detail": "Invalid or missing API key" +} +``` + +Status 402, Payment Required (e.g., balance depleted) +```json +{ + "detail": "Insufficient balance, please add funds to your account to continue using the service." +} +``` + +## Resources +- [API Reference](https://desearch.ai/docs/api-reference/get-web) +- [Desearch Console](https://console.desearch.ai) \ No newline at end of file diff --git a/_meta.json b/_meta.json new file mode 100644 index 0000000..658ef96 --- /dev/null +++ b/_meta.json @@ -0,0 +1,6 @@ +{ + "ownerId": "kn70rkrynh1pbpb1nh8fztsbnx814573", + "slug": "desearch-web-search", + "version": "1.0.1", + "publishedAt": 1771578642605 +} \ No newline at end of file diff --git a/scripts/desearch.py b/scripts/desearch.py new file mode 100644 index 0000000..c0db47d --- /dev/null +++ b/scripts/desearch.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 +""" +Desearch Web Search CLI - Real-time SERP-style web search. + +Usage: + desearch web "" [options] + +Environment: + DESEARCH_API_KEY - Required API key from desearch.ai +""" + +import argparse +import json +import os +import sys +from urllib.error import HTTPError, URLError +from urllib.parse import urlencode +from urllib.request import Request, urlopen + +DESEARCH_BASE = "https://api.desearch.ai" + + +def get_api_key() -> str: + key = os.environ.get("DESEARCH_API_KEY") + if not key: + print("Error: DESEARCH_API_KEY environment variable not set", file=sys.stderr) + print("Get your key at https://console.desearch.ai", file=sys.stderr) + sys.exit(1) + return key + + +def api_request( + method: str, path: str, params: dict = None, body: dict = None +) -> dict | str: + api_key = get_api_key() + url = f"{DESEARCH_BASE}{path}" + + if method == "GET" and params: + filtered = {k: v for k, v in params.items() if v is not None} + if filtered: + url = f"{url}?{urlencode(filtered, doseq=True)}" + + headers = { + "Authorization": f"{api_key}", + "Content-Type": "application/json", + "User-Agent": "Desearch-Clawdbot/1.0", + } + + data = None + if method == "POST" and body: + data = json.dumps(body).encode() + + try: + req = Request(url, data=data, headers=headers, method=method) + with urlopen(req, timeout=60) as response: + raw = response.read().decode() + try: + return json.loads(raw) + except json.JSONDecodeError: + return raw + except HTTPError as e: + error_body = e.read().decode() if e.fp else "" + try: + return json.loads(error_body) + except (json.JSONDecodeError, Exception): + return {"error": f"HTTP {e.code}: {e.reason}", "details": error_body} + except URLError as e: + return {"error": f"Connection failed: {e.reason}"} + except Exception as e: + return {"error": str(e)} + + +def cmd_web(args): + params = { + "query": args.query, + "start": args.start, + } + return api_request("GET", "/web", params=params) + + +def format_web_results(data): + lines = [] + if isinstance(data, str): + return data + if isinstance(data, dict) and "error" in data: + return f"Error: {data['error']}" + + results = data.get("organic_results", data.get("results", [])) + if not isinstance(results, list): + results = [] + + lines.append("=== Web Results ===") + for i, r in enumerate(results[:10], 1): + lines.append(f"\n{i}. {r.get('title', 'No title')}") + lines.append(f" {r.get('link', r.get('url', ''))}") + snippet = r.get("snippet", r.get("description", "")) + if snippet: + lines.append(f" {snippet[:200]}") + + return "\n".join(lines) if lines else "No results found." + + +def main(): + parser = argparse.ArgumentParser( + description="Desearch Web Search CLI", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=__doc__, + ) + parser.add_argument( + "command", choices=["web"], help="Command to execute" + ) + parser.add_argument("query", help="Search query") + + parser.add_argument( + "--start", + type=int, + default=0, + help="Pagination offset (default: 0)", + ) + + args = parser.parse_args() + results = cmd_web(args) + + if isinstance(results, str): + print(results) + else: + print(json.dumps(results, indent=2)) + + +if __name__ == "__main__": + main()