185 lines
5.8 KiB
Python
185 lines
5.8 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
SearXNG API 客户端 - 快速搜索工具
|
|
"""
|
|
|
|
import requests
|
|
import json
|
|
import sys
|
|
import argparse
|
|
from urllib.parse import urlencode
|
|
|
|
# 配置
|
|
SEARXNG_URL = "https://searxng.erhe.top"
|
|
API_TOKEN = "fGWEFWGrgasegtjt1jUJG"
|
|
|
|
def search(query,
|
|
format_type="json",
|
|
categories=None,
|
|
language="auto",
|
|
safesearch=0,
|
|
time_range=None,
|
|
max_results=10):
|
|
"""
|
|
搜索函数
|
|
|
|
参数:
|
|
query: 搜索关键词
|
|
format_type: 返回格式 (json/html/csv/rss)
|
|
categories: 分类 (images/videos/news/music/general)
|
|
language: 语言代码 (auto/zh/en/ja/de/fr)
|
|
safesearch: 安全搜索级别 (0=关闭, 1=适中, 2=严格)
|
|
time_range: 时间范围 (day/week/month/year)
|
|
max_results: 最大结果数
|
|
|
|
返回:
|
|
dict: 搜索结果
|
|
"""
|
|
params = {
|
|
"q": query,
|
|
"format": format_type,
|
|
"token": API_TOKEN,
|
|
"language": language,
|
|
"safesearch": safesearch
|
|
}
|
|
|
|
if categories:
|
|
params["categories"] = categories
|
|
|
|
if time_range:
|
|
params["time_range"] = time_range
|
|
|
|
try:
|
|
response = requests.get(
|
|
f"{SEARXNG_URL}/search",
|
|
params=params,
|
|
timeout=15
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
if format_type == "json":
|
|
return response.json()
|
|
else:
|
|
return {"html": response.text}
|
|
elif response.status_code == 403:
|
|
return {"error": "API token 无效或缺失"}
|
|
else:
|
|
return {"error": f"请求失败: {response.status_code}"}
|
|
|
|
except requests.exceptions.Timeout:
|
|
return {"error": "请求超时"}
|
|
except requests.exceptions.ConnectionError:
|
|
return {"error": "连接失败,请检查网络"}
|
|
except Exception as e:
|
|
return {"error": str(e)}
|
|
|
|
def print_results(results, max_results=10, verbose=False):
|
|
"""格式化输出结果"""
|
|
if "error" in results:
|
|
print(f"❌ 错误: {results['error']}")
|
|
return
|
|
|
|
query = results.get('query', '未知')
|
|
results_list = results.get('results', [])
|
|
unresponsive = results.get('unresponsive_engines', [])
|
|
|
|
print(f"\n{'='*70}")
|
|
print(f"🔍 查询: {query}")
|
|
print(f"📊 找到 {len(results_list)} 个结果")
|
|
if unresponsive:
|
|
print(f"⚠️ 部分搜索引擎失败: {', '.join([u[0] for u in unresponsive[:3]])}")
|
|
print(f"{'='*70}\n")
|
|
|
|
for i, result in enumerate(results_list[:max_results], 1):
|
|
title = result.get('title', '无标题')
|
|
url = result.get('url', '无链接')
|
|
content = result.get('content', '')
|
|
engine = result.get('engine', '未知')
|
|
published = result.get('publishedDate', '')
|
|
|
|
print(f"{i:2d}. {title}")
|
|
print(f" 🔗 {url}")
|
|
|
|
if content:
|
|
# 截断内容
|
|
if len(content) > 150:
|
|
content = content[:150] + "..."
|
|
print(f" 📝 {content}")
|
|
|
|
print(f" ⚙️ 来源: {engine}", end="")
|
|
if published:
|
|
print(f" | 📅 {published}", end="")
|
|
print("\n")
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="SearXNG 搜索工具",
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
epilog="""
|
|
示例:
|
|
%(prog)s python 教程
|
|
%(prog)s "machine learning" --category videos
|
|
%(prog)s linux --language en --time-range week
|
|
%(prog)s python --max-results 20 --verbose
|
|
"""
|
|
)
|
|
|
|
parser.add_argument('query', nargs='+', help='搜索关键词')
|
|
parser.add_argument('-c', '--category',
|
|
choices=['general', 'images', 'videos', 'news', 'music', 'files', 'it', 'science'],
|
|
default='general',
|
|
help='搜索分类 (默认: general)')
|
|
parser.add_argument('-l', '--language',
|
|
default='auto',
|
|
help='语言代码 (默认: auto)')
|
|
parser.add_argument('-s', '--safesearch',
|
|
type=int, choices=[0, 1, 2], default=0,
|
|
help='安全搜索: 0=关闭, 1=适中, 2=严格 (默认: 0)')
|
|
parser.add_argument('-t', '--time-range',
|
|
choices=['day', 'week', 'month', 'year'],
|
|
help='时间范围')
|
|
parser.add_argument('-m', '--max-results',
|
|
type=int, default=10,
|
|
help='最大结果数 (默认: 10)')
|
|
parser.add_argument('-v', '--verbose',
|
|
action='store_true',
|
|
help='详细输出')
|
|
parser.add_argument('--format',
|
|
choices=['json', 'html', 'csv', 'rss'],
|
|
default='json',
|
|
help='返回格式 (默认: json)')
|
|
parser.add_argument('--raw',
|
|
action='store_true',
|
|
help='输出原始 JSON')
|
|
|
|
args = parser.parse_args()
|
|
|
|
# 组合查询词
|
|
query = ' '.join(args.query)
|
|
|
|
# 执行搜索
|
|
results = search(
|
|
query,
|
|
format_type=args.format,
|
|
categories=args.category if args.category != 'general' else None,
|
|
language=args.language,
|
|
safesearch=args.safesearch,
|
|
time_range=args.time_range,
|
|
max_results=args.max_results
|
|
)
|
|
|
|
# 输出结果
|
|
if args.raw:
|
|
print(json.dumps(results, indent=2, ensure_ascii=False))
|
|
else:
|
|
print_results(results, max_results=args.max_results, verbose=args.verbose)
|
|
|
|
# 如果有建议搜索词
|
|
if 'suggestions' in results and results['suggestions']:
|
|
print(f"💡 你可能想搜索:")
|
|
for suggestion in results['suggestions']:
|
|
print(f" - {suggestion}")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|