# METADATA # { # "name": "duckduckgo", # # "display_name": { # "zh": "DuckDuckGo 搜索", # "en": "DuckDuckGo Search" # }, # "description": { "zh": "使用DuckDuckGo进行网络搜索和内容抓取。", "en": "Use DuckDuckGo for web search and content extraction." }, # "category": "Search", # "tools": [ # { # "name": "search", # "description": { "zh": "执行DuckDuckGo搜索并返回格式化的结果。", "en": "Run a DuckDuckGo search and return formatted results." }, # "parameters": [ # { # "name": "query", # "description": { "zh": "搜索查询字符串", "en": "Search query string." }, # "type": "string", # "required": true # }, # { # "name": "max_results", # "description": { "zh": "返回的最大结果数 (默认: 10)", "en": "Maximum number of results to return (default: 10)." }, # "type": "string", # "required": false # } # ] # }, # { # "name": "fetch_content", # "description": { "zh": "从网页URL抓取和解析内容。", "en": "Fetch and parse content from a webpage URL." }, # "parameters": [ # { # "name": "url", # "description": { "zh": "要抓取内容的网页URL", "en": "Webpage URL to fetch and parse." }, # "type": "string", # "required": true # } # ] # } # ] # } import re import time import asyncio import traceback from urllib.parse import unquote client = OkHttp.newClient() BASE_URL = "https://html.duckduckgo.com/html/" class RateLimiter: """A simple rate limiter to avoid sending too many requests.""" def __init__(self, requestsPerMinute=30): self.requestsPerMinute = requestsPerMinute self.requests = [] async def acquire(self): now = time.time() * 1000 # Remove requests older than 1 minute (60000 ms) self.requests = [reqTime for reqTime in self.requests if now - reqTime < 60000] if len(self.requests) >= self.requestsPerMinute: timeSinceFirstRequest = now - self.requests[0] waitTime = 60000 - timeSinceFirstRequest if waitTime > 0: await asyncio.sleep(waitTime / 1000) self.requests.append(time.time() * 1000) searchRateLimiter = RateLimiter(30) fetchRateLimiter = RateLimiter(20) def decodeHtmlEntities(text): """Decodes basic HTML entities.""" text = text.replace("&", "&") text = text.replace("<", "<") text = text.replace(">", ">") text = text.replace(""", '"') text = text.replace("'", "'") return text async def search(params): query = params.get("query") max_results = 10 if params.get("max_results"): try: parsedMaxResults = int(params["max_results"]) max_results = parsedMaxResults except (ValueError, TypeError): pass if not query: raise Exception("查询不能为空") await searchRateLimiter.acquire() console.log(f"正在从DuckDuckGo搜索: {query}") request = client.newRequest() request = request.url(BASE_URL) request = request.method("POST") request = request.body({"q": query, "b": "", "kl": ""}, "form") request = request.headers({ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" }) response = await request.build().execute() if not response.isSuccessful(): raise Exception(f"HTTP 错误! 状态码: {response.statusCode}") html = response.content results = [] resultRegex = re.compile( r'