
Web Search
- 368 installs
- 2 repo stars
- Updated March 3, 2026
- yejinlei/web-search-skill
web-search is a Claude Code skill that gives coding agents live web search to pull current docs, API changes, error fixes, and market signals while implementing features or debugging unfamiliar stacks.
About
web-search is a yejinlei/web-search-skill agent skill providing multi-engine live search for coding agents without API keys. Version 1.3.0 supports three actions—search, deep_search, and crawl—across four engines: Baidu via Playwright, DuckDuckGo, Bing, and baidusearch library fallback, returning up to 20 structured results with title, URL, and snippet. The Python script uses Playwright browser automation, crawl4ai, and async requests with smart engine fallback when one source fails. Developers reach for web-search when agents need current framework docs, breaking API changes, or stack traces not in local context. First Playwright run downloads Chromium (~100MB). Default num_results is 5 and region defaults to cn-zh, making Baidu-first strategy strong for Chinese-language queries.
- Real-time external knowledge for agents
- Reduces stale training-data guesses
- Supports doc and API lookup during coding
- Useful for debugging obscure errors
- Pairs with research and competitor checks
Web Search by the numbers
- 368 all-time installs (skills.sh)
- +5 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #2,087 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Jul 27, 2026 (Skillselion catalog sync)
npx skills add https://github.com/yejinlei/web-search-skill --skill web-searchAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 368 |
|---|---|
| repo stars | ★ 2 |
| Last updated | March 3, 2026 |
| Repository | yejinlei/web-search-skill ↗ |
How do coding agents search the web without API keys?
Give coding agents live web search to pull current docs, API changes, error fixes, and market signals while implementing features or debugging unfamiliar stacks.
Who is it for?
Developers wiring coding agents that need current documentation, release notes, or error solutions without paid search API keys.
Skip if: Production apps that need compliant enterprise search APIs, offline-only workflows, or agents forbidden from browser automation and web scraping.
When should I use this skill?
An agent needs current docs, API changelog details, unfamiliar stack error fixes, or live market signals beyond its training cutoff during implementation.
What you get
Structured search results with title, URL, and snippet JSON, plus optional deep-search page content or single-URL crawl output.
- structured search result JSON
- deep-search page excerpts
- crawled URL content
By the numbers
- Version 1.3.0 with 3 actions and 4 search engines
- Returns up to 20 results per query, default 5
Files
Web Search Skill
A powerful web search skill supporting multiple search engines without requiring API keys.
Features
- 🔍 Multi-Engine Support: Baidu (Playwright), Bing, DuckDuckGo
- 🌐 No API Key Required: Uses browser automation and web scraping
- 🔄 Smart Fallback: Automatically switches engines when one fails
- 📊 Structured Results: Returns clean search results with title, URL, and snippet
- 🚀 High Performance: Async support with Playwright browser automation
Usage
Basic Search
result = main({
"action": "search",
"query": "Python tutorial",
"num_results": 5
})Deep Search
result = main({
"action": "deep_search",
"query": "machine learning latest research",
"num_results": 5
})Web Page Crawling
result = main({
"action": "crawl",
"url": "https://example.com"
})Input Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| action | string | Yes | Operation type: "search", "deep_search", or "crawl" |
| query | string | Conditional | Search query (required for search/deep_search) |
| url | string | Conditional | Target URL (required for crawl) |
| num_results | int | No | Number of results, default 5, max 20 |
| region | string | No | Region code, default 'cn-zh' |
Output Format
Search Result
{
"success": True,
"query": "search query",
"engine": "baidu+playwright",
"num_results": 5,
"results": [
{
"title": "Result title",
"href": "https://...",
"body": "Snippet content"
}
],
"message": "Search completed"
}Deep Search Result
{
"success": True,
"query": "search query",
"search_results": [...],
"detailed_info": {
"extracted_content": "..."
},
"message": "Deep search completed"
}Execution
type: script script_path: scripts/web_search.py entry_point: main dependencies:
- uv>=0.1.0
- requests>=2.28.0
- baidusearch>=1.0.3
- crawl4ai>=0.8.0
- playwright>=1.40.0
Search Strategy
1. Primary: baidusearch library (fastest, no browser) 2. Secondary: Playwright + Baidu (most reliable, bypasses anti-bot) 3. Tertiary: DuckDuckGo (privacy-focused) 4. Fallback: Bing (international)
Notes
1. First Run: Playwright will download Chromium browser on first use (~100MB) 2. Rate Limiting: Be mindful of search frequency to avoid temporary blocks 3. Network: Requires internet connection 4. Results: May vary based on search engine algorithms and location
Error Handling
- Returns
{"success": False, "message": "..."}on errors - Automatically retries with fallback engines
- Graceful degradation when optional dependencies are missing
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Virtual environments
.venv/
venv/
ENV/
env/
# IDE
.idea/
.vscode/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# Testing
.pytest_cache/
.coverage
htmlcov/
# Logs
*.log
# Local config
.env
.env.local
MIT License
Copyright (c) 2025 Web Search Skill Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
include README.md
include LICENSE.txt
include SKILL.md
include requirements.txt
recursive-include scripts *.py
recursive-exclude * __pycache__
recursive-exclude * *.py[co]
Web Search Skill
一个功能强大的网络搜索技能,支持多种搜索引擎,无需 API 密钥。
✨ 功能特性
- 🔍 多引擎支持:百度(Playwright)、必应、DuckDuckGo
- 🌐 无需 API Key:使用浏览器自动化和网页抓取
- 🔄 智能降级:一个引擎失败时自动切换其他引擎
- 📊 结构化结果:返回清晰的搜索结果(标题、URL、摘要)
- 🚀 高性能:异步支持,Playwright 浏览器自动化
📦 安装
依赖安装
pip install -r requirements.txtPlaywright 浏览器安装(首次使用)
playwright install chromium注意:首次安装会下载 Chromium 浏览器(约 100MB)
🚀 快速开始
基本搜索
from web_search import main
# 执行搜索
result = main({
"action": "search",
"query": "Python 教程",
"num_results": 5
})
print(f"搜索引擎: {result['engine']}")
for r in result['results']:
print(f"- {r['title']}: {r['href']}")深度搜索
# 深度搜索并抓取详情
result = main({
"action": "deep_search",
"query": "machine learning latest research",
"num_results": 5
})
# 查看详细内容
if result.get('detailed_info'):
print(result['detailed_info']['extracted_content'])网页抓取
# 抓取特定网页
result = main({
"action": "crawl",
"url": "https://example.com"
})
if result['success']:
print(result['markdown'])📋 输入参数
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
| action | string | 是 | 操作类型:search、deep_search、crawl |
| query | string | 条件 | 搜索关键词(search/deep_search 必需) |
| url | string | 条件 | 目标 URL(crawl 必需) |
| num_results | int | 否 | 返回结果数量,默认 5,最大 20 |
| region | string | 否 | 地区代码,默认 cn-zh |
📤 输出格式
搜索结果
{
"success": true,
"query": "搜索关键词",
"engine": "baidu+playwright",
"num_results": 5,
"results": [
{
"title": "结果标题",
"href": "https://...",
"body": "摘要内容"
}
],
"message": "搜索完成"
}深度搜索结果
{
"success": true,
"query": "搜索关键词",
"search_results": [...],
"detailed_info": {
"extracted_content": "抓取的详细内容..."
},
"message": "深度搜索完成"
}🔍 搜索策略
技能按以下优先级自动选择搜索引擎:
1. baidusearch 库 - 最快,无需浏览器 2. Playwright + 百度 - 最可靠,绕过反爬虫 3. DuckDuckGo - 隐私保护 4. 必应 - 国际搜索
💡 使用场景
- 📰 新闻资讯获取:搜索最新新闻报道
- 📚 知识查询:获取技术文档、教程
- 🌐 信息收集:网络信息搜集
- 🔍 研究调研:学术研究、市场调研
⚠️ 注意事项
1. 首次运行:Playwright 会自动下载 Chromium 浏览器(约 100MB) 2. 搜索频率:建议合理控制频率,避免被搜索引擎临时限制 3. 网络要求:需要稳定的互联网连接 4. 结果差异:搜索结果可能因搜索引擎算法和地理位置而异
🔧 故障排除
问题:Playwright 浏览器下载失败
解决:手动安装浏览器
playwright install chromium问题:搜索结果为空
可能原因:
- 网络连接问题
- 搜索引擎反爬虫机制
- 查询词过于特殊
解决:技能会自动尝试其他搜索引擎,无需手动干预
问题:网页抓取失败
可能原因:
- 网站反爬虫机制
- 网站需要登录
- 网站结构复杂
解决:尝试使用其他 URL 或简化需求
📄 许可证
MIT License - 详见 LICENSE
🤝 贡献
欢迎提交 Issue 和 Pull Request!
📝 更新日志
v1.1.0 (2025-03-01)
- ✅ 集成 Playwright 浏览器自动化
- ✅ 支持深度搜索模式
- ✅ 多引擎智能降级策略
v1.0.0 (2025-03-01)
- 🎉 初始版本发布
- ✅ 支持必应搜索引擎
- ✅ 支持百度搜索引擎
# Web Search Skill Requirements
# 包管理器(推荐用于快速安装)
uv>=0.1.0
# HTTP请求
requests>=2.28.0
# 百度搜索库(无需API Key)
baidusearch>=1.0.3
# 网页抓取库(深度搜索)
crawl4ai>=0.8.0
# Playwright 浏览器自动化
playwright>=1.40.0
"""
Web Search Skill Scripts Package
"""
from .web_search import web_search, execute, main
__all__ = ['web_search', 'execute', 'main']
__version__ = '1.0.0'
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
网络搜索技能
支持多种搜索引擎:百度(Playwright)、必应、DuckDuckGo
无需 API Key
"""
import sys
import json
import urllib.parse
import re
import asyncio
from html import unescape
from typing import Dict, Any, List, Optional
from concurrent.futures import ThreadPoolExecutor
try:
import requests
HAS_REQUESTS = True
except ImportError:
HAS_REQUESTS = False
try:
from baidusearch.baidusearch import search as baidu_search
HAS_BAIDU_SEARCH = True
except ImportError:
HAS_BAIDU_SEARCH = False
try:
from crawl4ai import AsyncWebCrawler
HAS_CRAWL4AI = True
except ImportError:
HAS_CRAWL4AI = False
try:
from playwright.sync_api import sync_playwright
HAS_PLAYWRIGHT = True
except ImportError:
HAS_PLAYWRIGHT = False
def extract_search_results_from_html(html: str) -> List[Dict[str, str]]:
"""从HTML中提取搜索结果"""
results = []
# 百度结果提取
baidu_patterns = [
r'<h3[^>]*>.*?<a[^>]+href="([^"]+)"[^>]*>(.*?)</a>.*?</h3>',
r'class="result"[^>]*>.*?<a[^>]+href="([^"]+)"[^>]*>(.*?)</a>',
]
for pattern in baidu_patterns:
matches = re.findall(pattern, html, re.DOTALL | re.IGNORECASE)
for href, title in matches:
title = re.sub(r'<[^>]+>', '', title).strip()
title = unescape(title)
if title and len(title) > 5 and href.startswith('http'):
results.append({'title': title, 'href': href, 'body': ''})
return results
def search_baidu_playwright(query: str, num_results: int = 5) -> List[Dict[str, str]]:
"""使用 Playwright 进行百度搜索"""
results = []
if not HAS_PLAYWRIGHT:
return results
try:
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
context = browser.new_context(
user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
viewport={'width': 1920, 'height': 1080}
)
page = context.new_page()
encoded_query = urllib.parse.quote(query)
url = f"https://www.baidu.com/s?wd={encoded_query}&rn={num_results * 2}"
page.goto(url, wait_until='networkidle', timeout=30000)
page.wait_for_selector('#content_left', timeout=10000)
search_results = page.query_selector_all('#content_left .result, #content_left .c-container')
for result in search_results:
if len(results) >= num_results:
break
try:
title_elem = result.query_selector('h3 a, .t a')
if title_elem:
title = title_elem.inner_text()
href = title_elem.get_attribute('href')
abstract_elem = result.query_selector('.content-right_8Zs40, .c-abstract, .content-right')
body = ''
if abstract_elem:
body = abstract_elem.inner_text()
if title and href and len(title) > 5:
if not any(x in href for x in ['baidu.com/home', 'baidu.com/s?', 'passport', 'javascript:']):
if href not in [r['href'] for r in results]:
results.append({
'title': title.strip(),
'href': href,
'body': body.strip()
})
except Exception:
continue
browser.close()
except Exception as e:
print(f"Playwright 搜索错误: {e}")
return results
def search_baidu(query: str, num_results: int = 5) -> List[Dict[str, str]]:
"""使用百度搜索 - 优先使用 baidusearch 库,然后使用 Playwright"""
results = []
# 1. 尝试使用 baidusearch 库
if HAS_BAIDU_SEARCH:
try:
baidu_results = baidu_search(query, num_results=num_results)
if baidu_results:
for r in baidu_results:
results.append({
'title': r.get('title', ''),
'href': r.get('url', ''),
'body': r.get('abstract', '')
})
if results:
return results
except Exception:
pass
# 2. 尝试使用 Playwright
if HAS_PLAYWRIGHT:
try:
playwright_results = search_baidu_playwright(query, num_results)
if playwright_results:
return playwright_results
except Exception:
pass
# 3. 回退到 requests
if not HAS_REQUESTS:
return []
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9',
}
encoded_query = urllib.parse.quote(query)
url = f"https://www.baidu.com/s?wd={encoded_query}&rn={num_results * 2}"
response = requests.get(url, headers=headers, timeout=15)
if response.status_code == 200:
html = response.text
results = extract_search_results_from_html(html)
if not results:
patterns = [
r'href="(https://[^"]+)"[^>]*>([^<]{10,100}?)</a>',
]
for pattern in patterns:
matches = re.findall(pattern, html, re.DOTALL)
for href, title in matches:
if len(results) >= num_results:
break
title = re.sub(r'<[^>]+>', '', title).strip()
title = unescape(title)
if not title or len(title) < 5:
continue
if href in [r['href'] for r in results]:
continue
if 'javascript:' in href:
continue
if any(x in href for x in ['baidu.com/home', 'baidu.com/s?', 'passport']):
continue
results.append({
'title': title,
'href': href,
'body': ''
})
except Exception:
pass
return results[:num_results]
def search_duckduckgo(query: str, num_results: int = 5) -> List[Dict[str, str]]:
"""使用 DuckDuckGo 搜索"""
results = []
if not HAS_REQUESTS:
return results
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
}
encoded_query = urllib.parse.quote(query)
url = f"https://html.duckduckgo.com/html/?q={encoded_query}"
response = requests.get(url, headers=headers, timeout=15)
if response.status_code == 200:
html = response.text
pattern = r'<a[^>]+class="result__a"[^>]+href="([^"]+)"[^>]*>(.*?)</a>'
matches = re.findall(pattern, html, re.DOTALL)
for href, title in matches[:num_results]:
title = re.sub(r'<[^>]+>', '', title).strip()
title = unescape(title)
if title and href:
results.append({
'title': title,
'href': href,
'body': ''
})
except Exception:
pass
return results
def search_bing(query: str, num_results: int = 5) -> List[Dict[str, str]]:
"""使用必应搜索"""
results = []
if not HAS_REQUESTS:
return results
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
}
encoded_query = urllib.parse.quote(query)
url = f"https://cn.bing.com/search?q={encoded_query}&count={num_results}"
response = requests.get(url, headers=headers, timeout=15)
if response.status_code == 200:
html = response.text
pattern = r'<li class="b_algo"[^>]*>.*?<h2[^>]*>.*?<a[^>]+href="([^"]+)"[^>]*>(.*?)</a>.*?</h2>.*?</li>'
matches = re.findall(pattern, html, re.DOTALL)
for href, title in matches[:num_results]:
title = re.sub(r'<[^>]+>', '', title).strip()
title = unescape(title)
if title and href:
results.append({
'title': title,
'href': href,
'body': ''
})
except Exception:
pass
return results
async def crawl_page_async(url: str) -> Dict[str, Any]:
"""异步抓取网页内容"""
if not HAS_CRAWL4AI:
return {
'success': False,
'message': 'crawl4ai 未安装,无法抓取网页'
}
try:
async with AsyncWebCrawler() as crawler:
result = await crawler.arun(url=url)
return {
'success': True,
'url': url,
'title': result.metadata.get('title', ''),
'markdown': result.markdown,
'text': result.markdown[:5000] if result.markdown else ''
}
except Exception as e:
return {
'success': False,
'url': url,
'message': f'抓取失败: {str(e)}'
}
def crawl_page(url: str) -> Dict[str, Any]:
"""抓取网页内容(同步接口)"""
if not HAS_CRAWL4AI:
return {
'success': False,
'message': 'crawl4ai 未安装,无法抓取网页'
}
try:
return asyncio.run(crawl_page_async(url))
except Exception as e:
return {
'success': False,
'url': url,
'message': f'抓取失败: {str(e)}'
}
def deep_search(query: str, num_results: int = 5) -> Dict[str, Any]:
"""深度搜索 - 搜索并抓取详情"""
search_results = search_baidu(query, num_results)
if not search_results:
return {
'success': False,
'query': query,
'error': '未找到搜索结果'
}
detailed_content = []
# 抓取前3个结果的详情
for r in search_results[:3]:
if HAS_CRAWL4AI:
crawl_result = crawl_page(r['href'])
if crawl_result.get('success'):
detailed_content.append({
'url': r['href'],
'title': r['title'],
'content': crawl_result.get('text', '')[:2000]
})
return {
'success': True,
'query': query,
'search_results': search_results,
'detailed_info': {
'extracted_content': detailed_content
},
'message': '深度搜索完成'
}
def validate_search_params(query: str, num_results: int) -> tuple:
"""验证搜索参数"""
if not query:
return False, '搜索关键词不能为空', 0
if not isinstance(query, str):
return False, '搜索关键词必须是字符串', 0
query = query.strip()
if len(query) == 0:
return False, '搜索关键词不能为空', 0
if len(query) > 500:
return False, '搜索关键词长度不能超过500字符', 0
try:
num_results = int(num_results)
except (ValueError, TypeError):
num_results = 5
num_results = max(1, min(num_results, 20))
return True, '', num_results
def validate_url(url: str) -> tuple:
"""验证 URL"""
if not url:
return False, 'URL 不能为空'
if not isinstance(url, str):
return False, 'URL 必须是字符串'
url = url.strip()
if len(url) == 0:
return False, 'URL 不能为空'
if not url.startswith(('http://', 'https://')):
return False, 'URL 必须以 http:// 或 https:// 开头'
if len(url) > 2000:
return False, 'URL 长度不能超过2000字符'
return True, ''
def web_search(query: str, num_results: int = 5, region: str = 'cn-zh', deep: bool = False) -> Dict[str, Any]:
"""执行网络搜索"""
is_valid, error_msg, num_results = validate_search_params(query, num_results)
if not is_valid:
return {
'success': False,
'query': query if isinstance(query, str) else '',
'num_results': 0,
'results': [],
'errors': [error_msg],
'message': error_msg
}
query = query.strip()
if not HAS_REQUESTS:
return {
'success': False,
'query': query,
'num_results': 0,
'results': [],
'errors': ['请安装 requests: uv pip install requests'],
'message': '缺少依赖'
}
if deep and HAS_CRAWL4AI:
return deep_search(query, num_results)
all_results = []
engines_tried = []
try:
baidu_results = search_baidu(query, num_results)
if baidu_results:
all_results.extend(baidu_results)
engines_tried.append('baidu')
except:
engines_tried.append('baidu(failed)')
try:
ddg_results = search_duckduckgo(query, num_results)
if ddg_results:
for r in ddg_results:
if r['href'] not in [x['href'] for x in all_results]:
all_results.append(r)
engines_tried.append('duckduckgo')
except:
engines_tried.append('duckduckgo(failed)')
try:
bing_results = search_bing(query, num_results)
if bing_results:
for r in bing_results:
if r['href'] not in [x['href'] for x in all_results]:
all_results.append(r)
engines_tried.append('bing')
except:
engines_tried.append('bing(failed)')
seen = set()
unique_results = []
for r in all_results:
if r['href'] not in seen:
seen.add(r['href'])
unique_results.append(r)
results = unique_results[:num_results]
return {
'success': len(results) > 0,
'query': query,
'engine': '+'.join(engines_tried),
'num_results': len(results),
'results': results,
'message': '搜索完成' if results else '未找到结果'
}
def execute(action: str, **kwargs) -> Dict[str, Any]:
"""执行技能操作"""
if not action:
return {'success': False, 'message': '操作类型不能为空'}
if not isinstance(action, str):
return {'success': False, 'message': '操作类型必须是字符串'}
action = action.strip().lower()
if action == 'search':
query = kwargs.get('query', '')
num_results = kwargs.get('num_results', 5)
region = kwargs.get('region', 'cn-zh')
deep = kwargs.get('deep', False)
return web_search(query, num_results, region, deep)
elif action == 'crawl':
url = kwargs.get('url', '')
is_valid, error_msg = validate_url(url)
if not is_valid:
return {'success': False, 'message': error_msg}
return crawl_page(url.strip())
elif action == 'deep_search':
query = kwargs.get('query', '')
is_valid, error_msg, num_results = validate_search_params(
query, kwargs.get('num_results', 5)
)
if not is_valid:
return {'success': False, 'message': error_msg}
return deep_search(query.strip(), num_results)
else:
valid_actions = ['search', 'crawl', 'deep_search']
return {
'success': False,
'message': f'未知操作: {action}。有效操作: {", ".join(valid_actions)}'
}
def main(input_data: Dict[str, Any] = None) -> Dict[str, Any]:
"""技能入口点"""
if input_data is None:
input_data = {}
action = input_data.get('action', 'search')
kwargs = {k: v for k, v in input_data.items() if k != 'action'}
return execute(action, **kwargs)
if __name__ == "__main__":
if len(sys.argv) > 1:
query = ' '.join(sys.argv[1:])
else:
query = "Python tutorial"
result = main({'action': 'search', 'query': query, 'num_results': 5})
print(json.dumps(result, ensure_ascii=False, indent=2))
"""
Web Search Skill Setup
Installation with uv (recommended):
uv pip install -e .
Installation with pip:
pip install -e .
"""
from setuptools import setup, find_packages
with open("README.md", "r", encoding="utf-8") as fh:
long_description = fh.read()
with open("requirements.txt", "r", encoding="utf-8") as fh:
requirements = [line.strip() for line in fh if line.strip() and not line.startswith("#")]
setup(
name="web-search-skill",
version="1.2.0",
author="yejinlei",
author_email="",
description="Web Search Skill - Multi-engine web search without API keys",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/yejinlei/web-search-skill",
packages=find_packages(),
classifiers=[
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
],
python_requires=">=3.8",
install_requires=requirements,
keywords="web search baidu bing duckduckgo internet",
project_urls={
"Bug Reports": "https://github.com/yejinlei/web-search-skill/issues",
"Source": "https://github.com/yejinlei/web-search-skill",
},
)
Related skills
How it compares
Pick web-search over paid search API integrations when agents need keyless multi-engine lookup with Playwright fallback and deep page crawling during coding sessions.
FAQ
Which search engines does web-search support?
web-search queries Baidu via Playwright, DuckDuckGo, Bing, and the baidusearch library with four-tier smart fallback. Engines switch automatically when one fails, and no API keys are required for any source.
What actions does web-search expose?
web-search version 1.3.0 exposes three actions: search for keyword results, deep_search to fetch page content from hits, and crawl for a single target URL. Each returns structured JSON with title, URL, and snippet fields.
What are web-search default result limits?
web-search defaults to 5 results per query with a maximum of 20 via the num_results parameter. Region defaults to cn-zh, and Playwright downloads Chromium on first run at roughly 100MB.