镜像自地址
https://github.com/lhly/search-syntax-pro.git
已同步 2026-10-20 14:27:47 +08:00
- 添加 DuckDuckGo、Brave、Yandex、Reddit、GitHub 和 StackOverflow 适配器 - 实现动态语言选择器功能 - 更新搜索引擎类型定义和国际化翻译 - 添加详细的搜索引擎文档和语法参考
16 KiB
16 KiB
Stack Overflow 搜索引擎适配器文档
📋 基本信息
| 属性 | 值 |
|---|---|
| 引擎名称 | Stack Overflow |
| 官方网站 | https://stackoverflow.com |
| 市场定位 | 技术问答社区平台 |
| 月访问量 | 5000万+ |
| 问题数量 | 2400万+ |
| 主要用户群 | 开发者、程序员、技术学习者 |
| 优先级 | P2 (低) |
| 实施复杂度 | 🔴 高 |
| 预计工期 | 3-4天 |
🎯 产品价值
用户价值
- ✅ 问题解决: 快速找到技术问题的答案
- ✅ 最佳实践: 学习社区认可的解决方案
- ✅ 代码示例: 获取实际可用的代码片段
- ✅ 专家观点: 访问经验丰富开发者的见解
业务价值
- 👨💻 吸引技术学习者
- 🎯 专业开发工具定位
- 💡 提升产品技术属性
- 🏆 增强用户黏性
🔍 支持的搜索语法
1. 基础搜索
1.1 关键词搜索
关键词
示例:
React hooks
Python async
JavaScript promise
说明: 搜索标题、正文、标签中的关键词
1.2 精确短语 ("...")
"完整短语"
示例:
"how to use async await"
"what is closure"
2. 标签筛选
2.1 单标签筛选 ([tag])
[标签名]
示例:
[javascript]
[python]
[react]
[typescript]
说明: 只搜索带有指定标签的问题
2.2 多标签组合
[标签1] [标签2]
示例:
[javascript] [react]
[python] [django]
[typescript] [node.js]
说明: 搜索同时包含多个标签的问题(AND关系)
2.3 标签OR逻辑
[标签1] or [标签2]
示例:
[react] or [vue]
[python] or [javascript]
说明: 搜索包含任一标签的问题
3. 筛选器
3.1 用户筛选 (user:)
user:用户ID
示例:
user:12345
user:me (搜索自己的问题)
说明: 搜索特定用户提出或回答的问题
3.2 已接受答案 (isaccepted: 或 hasaccepted:)
关键词 isaccepted:yes
关键词 hasaccepted:yes
示例:
React hooks isaccepted:yes
Python async hasaccepted:yes
说明: 只显示有已接受答案的问题
3.3 问题状态 (is:question / is:answer)
is:question
is:answer
示例:
React is:question
async is:answer
说明:
is:question- 只搜索问题is:answer- 只搜索答案
3.4 分数筛选 (score:)
score:>数值
score:范围
示例:
React score:>10
Python score:5..20
JavaScript score:>=15
说明: 筛选特定分数范围的问题或答案
3.5 回答数筛选 (answers:)
answers:>数值
示例:
React answers:>5
Python answers:0 (未回答的问题)
3.6 浏览量筛选 (views:)
views:>数值
示例:
React views:>1000
Python views:500..2000
4. 时间筛选
4.1 创建时间 (created:)
created:日期范围
示例:
React created:2024-01-01..2024-12-31
Python created:>2024-01-01
JavaScript created:<2023-01-01
日期格式:
YYYY-MM-DDYYYY-MM-DD..YYYY-MM-DD(范围)>YYYY-MM-DD,<YYYY-MM-DD
4.2 最后活动时间 (lastactive:)
lastactive:日期范围
示例:
React lastactive:>2024-11-01
Python lastactive:1m (最近1个月)
时间单位:
d- 天 (days)w- 周 (weeks)m- 月 (months)y- 年 (years)
5. 内容筛选
5.1 标题搜索 (title:)
title:关键词
示例:
title:React
title:"how to"
说明: 只搜索标题中包含关键词的问题
5.2 正文搜索 (body:)
body:关键词
示例:
body:async
body:"error message"
说明: 只搜索正文中包含关键词的内容
5.3 代码搜索 (code:)
code:代码片段
示例:
code:useState
code:"async function"
说明: 搜索代码块中的内容
6. 布尔运算符
6.1 OR 逻辑
关键词1 OR 关键词2
示例:
React OR Vue
Python OR JavaScript
6.2 NOT 逻辑 (-)
关键词 -排除词
示例:
React -class
Python -2.7
7. 特殊筛选
7.1 已关闭问题 (closed:)
closed:yes
closed:no
示例:
React closed:yes
Python closed:no
7.2 已锁定问题 (locked:)
locked:yes
示例:
controversial locked:yes
7.3 Wiki类型 (wiki:)
wiki:yes
示例:
tutorial wiki:yes
🔧 技术实现
URL 构建格式
基础URL:
https://stackoverflow.com/search
查询参数:
interface StackOverflowSearchParams {
q: string; // 搜索查询
tab?: string; // relevance|newest|votes|active
pagesize?: number; // 每页结果数 (默认: 15)
}
完整URL示例:
https://stackoverflow.com/search?q=%5Breact%5D+hooks+isaccepted%3Ayes
适配器实现模板
import type { SearchEngineAdapter, SearchParams, SyntaxType, ValidationResult, UIFeatureType } from '@/types'
/**
* Stack Overflow 搜索引擎适配器
* 支持技术问答搜索和标签筛选
*/
export class StackOverflowAdapter implements SearchEngineAdapter {
getName(): string {
return 'Stack Overflow'
}
getBaseUrl(): string {
return 'https://stackoverflow.com/search'
}
/**
* 构建 Stack Overflow 搜索查询 URL
*/
buildQuery(params: SearchParams): string {
const baseUrl = this.getBaseUrl()
const query = this.buildSearchQuery(params)
const urlParams = new URLSearchParams({
q: query,
tab: 'relevance'
})
return `${baseUrl}?${urlParams.toString()}`
}
/**
* 构建搜索查询字符串
*/
private buildSearchQuery(params: SearchParams): string {
const queryParts: string[] = []
// 1. 基础关键词
if (params.keyword && params.keyword.trim()) {
queryParts.push(params.keyword.trim())
}
// 2. 精确匹配
if (params.exactMatch && params.exactMatch.trim()) {
queryParts.push(`"${params.exactMatch.trim()}"`)
}
// 3. 标签筛选 (Stack Overflow特有)
// 将多个标签转换为 [tag1] [tag2] 格式
if (params.site && params.site.trim()) {
const tags = params.site.split(',').map(tag => tag.trim())
tags.forEach(tag => {
if (tag) {
queryParts.push(`[${tag}]`)
}
})
}
// 4. 用户筛选
if (params.fromUser && params.fromUser.trim()) {
const userId = params.fromUser.replace('@', '')
queryParts.push(`user:${userId}`)
}
// 5. 标题搜索
if (params.inTitle && params.inTitle.trim()) {
queryParts.push(`title:${params.inTitle.trim()}`)
}
// 6. 正文搜索
if (params.inText && params.inText.trim()) {
queryParts.push(`body:${params.inText.trim()}`)
}
// 7. 日期范围 (使用created:)
if (params.dateRange) {
const { from, to } = params.dateRange
if (from && to) {
queryParts.push(`created:${from}..${to}`)
} else if (from) {
queryParts.push(`created:>${from}`)
} else if (to) {
queryParts.push(`created:<${to}`)
}
}
// 8. 已接受答案筛选 (Stack Overflow特有)
// 可以通过自定义字段添加
// queryParts.push('isaccepted:yes')
// 9. 排除关键词
if (params.excludeWords && params.excludeWords.length > 0) {
params.excludeWords.forEach(word => {
if (word.trim()) {
queryParts.push(`-${word.trim()}`)
}
})
}
// 10. OR 逻辑关键词
if (params.orKeywords && params.orKeywords.length > 0) {
const orQuery = params.orKeywords
.filter(word => word.trim())
.join(' OR ')
if (orQuery) {
queryParts.push(`(${orQuery})`)
}
}
return queryParts.join(' ')
}
/**
* 验证语法类型
*/
validateSyntax(syntax: SyntaxType): boolean {
const supportedSyntax: SyntaxType[] = [
'site', // 映射为标签 [tag]
'exact',
'intitle',
'intext',
'exclude',
'or',
'from_user',
'date_range'
]
return supportedSyntax.includes(syntax)
}
/**
* 获取支持的语法类型
*/
getSupportedSyntax(): SyntaxType[] {
return [
'site',
'exact',
'intitle',
'intext',
'exclude',
'or',
'from_user',
'date_range'
]
}
/**
* 获取支持的UI功能特性
*/
getSupportedFeatures(): UIFeatureType[] {
return [
'site', // 显示为"标签"
'exact_match',
'intitle',
'intext',
'exclude',
'or_keywords',
'from_user', // 显示为"用户ID"
'date_range' // 显示为"创建时间"
]
}
/**
* 验证搜索参数
*/
validateParams(params: SearchParams): ValidationResult {
const errors: string[] = []
const warnings: string[] = []
// 检查基本关键词
if (!params.keyword || !params.keyword.trim()) {
if (!params.exactMatch && !params.site) {
errors.push('请输入搜索关键词或标签')
}
}
// 检查标签格式
if (params.site && params.site.trim()) {
const tags = params.site.split(',')
tags.forEach(tag => {
const trimmedTag = tag.trim()
if (trimmedTag && !/^[a-z0-9.\-#+]+$/.test(trimmedTag)) {
warnings.push(`标签 "${trimmedTag}" 格式可能不正确`)
}
})
}
// 检查用户ID
if (params.fromUser && params.fromUser.trim()) {
const userId = params.fromUser.replace('@', '')
if (isNaN(Number(userId)) && userId !== 'me') {
warnings.push('用户ID应该是数字或"me"')
}
}
return {
isValid: errors.length === 0,
errors,
warnings
}
}
/**
* 获取搜索建议
*/
getSearchSuggestions(params: SearchParams): string[] {
const suggestions: string[] = []
if (params.keyword && !params.site) {
suggestions.push('添加标签可以精确定位技术领域')
}
if (params.keyword) {
suggestions.push('使用 isaccepted:yes 只显示有已接受答案的问题')
}
if (!params.dateRange) {
suggestions.push('使用日期筛选可以找到最新的解决方案')
}
return suggestions
}
}
📝 实施清单
Phase 1: 核心功能 (Day 1-2)
- 创建
src/services/adapters/stackoverflow.ts - 实现
StackOverflowAdapter类 - 实现基础搜索和标签筛选
- 单元测试
Phase 2: 高级筛选 (Day 2-3)
- 实现用户筛选
- 实现分数、回答数、浏览量筛选
- 实现时间筛选
- 实现内容筛选 (title, body, code)
- 参数验证
Phase 3: UI集成 (Day 3-4)
- 标签输入组件
- 常用标签预设
- 高级筛选UI (isaccepted, score等)
- 国际化翻译
- 完整测试
✅ 测试用例
describe('StackOverflowAdapter', () => {
const adapter = new StackOverflowAdapter()
test('基础关键词搜索', () => {
const url = adapter.buildQuery({
keyword: 'React hooks',
engine: 'stackoverflow'
})
expect(url).toContain('q=React+hooks')
expect(url).toContain('tab=relevance')
})
test('标签筛选', () => {
const url = adapter.buildQuery({
keyword: 'tutorial',
site: 'javascript,react',
engine: 'stackoverflow'
})
expect(url).toContain('%5Bjavascript%5D') // [javascript]
expect(url).toContain('%5Breact%5D') // [react]
})
test('用户筛选', () => {
const url = adapter.buildQuery({
keyword: 'answer',
fromUser: '12345',
engine: 'stackoverflow'
})
expect(url).toContain('user%3A12345')
})
test('标题和正文搜索', () => {
const url = adapter.buildQuery({
keyword: 'error',
inTitle: 'async',
inText: 'await',
engine: 'stackoverflow'
})
expect(url).toContain('title%3Aasync')
expect(url).toContain('body%3Aawait')
})
test('组合查询', () => {
const url = adapter.buildQuery({
keyword: 'tutorial',
site: 'react',
dateRange: {
from: '2024-01-01',
to: '2024-12-31'
},
excludeWords: ['deprecated'],
engine: 'stackoverflow'
})
expect(url).toContain('%5Breact%5D')
expect(url).toContain('created%3A2024-01-01..2024-12-31')
expect(url).toContain('-deprecated')
})
})
🌍 国际化支持
{
"engines.stackoverflow": "Stack Overflow",
"engines.stackoverflow.description": "全球最大的技术问答社区",
"engines.stackoverflow.features": {
"tags": "标签筛选",
"isaccepted": "已接受答案",
"score": "分数筛选",
"answers": "回答数",
"views": "浏览量",
"user": "用户筛选"
},
"engines.stackoverflow.labels": {
"site": "标签 (逗号分隔)",
"fromUser": "用户ID",
"inTitle": "标题搜索",
"inText": "正文搜索",
"dateRange": "创建时间"
},
"engines.stackoverflow.placeholders": {
"site": "例如: javascript,react,typescript",
"fromUser": "例如: 12345 或 me",
"keyword": "例如: how to use async await"
},
"engines.stackoverflow.commonTags": {
"javascript": "JavaScript",
"python": "Python",
"java": "Java",
"c#": "C#",
"php": "PHP",
"android": "Android",
"html": "HTML",
"jquery": "jQuery",
"c++": "C++",
"css": "CSS",
"ios": "iOS",
"mysql": "MySQL",
"sql": "SQL",
"r": "R",
"node.js": "Node.js",
"reactjs": "React.js",
"arrays": "Arrays",
"c": "C",
"ruby-on-rails": "Ruby on Rails",
"json": "JSON"
}
}
🎨 UI特殊处理
常用标签快捷选择
const POPULAR_TAGS = {
frontend: ['javascript', 'html', 'css', 'reactjs', 'vue.js', 'angular'],
backend: ['node.js', 'python', 'java', 'php', 'ruby-on-rails', 'asp.net'],
mobile: ['android', 'ios', 'react-native', 'flutter', 'swift', 'kotlin'],
database: ['mysql', 'postgresql', 'mongodb', 'sql', 'sqlite'],
tools: ['git', 'docker', 'linux', 'bash', 'regex']
}
标签输入组件
// TagInput.tsx - Stack Overflow专用
interface TagInputProps {
value: string
onChange: (tags: string) => void
suggestions?: string[]
}
// 支持逗号分隔多个标签
// 自动提示常用标签
// 标签验证(小写字母、数字、.-#+)
📚 参考资源
官方文档
技术文章
💡 使用场景
1. 问题解决
错误信息 [javascript] isaccepted:yes
bug描述 [react] score:>5
2. 学习最佳实践
"best practices" [python] score:>10
tutorial [typescript] views:>1000
3. 代码示例查找
code:async [javascript]
code:useState [react]
4. 技术趋势研究
[react] created:>2024-01-01
[typescript] lastactive:1m
⚠️ 注意事项
标签规则
- 只能包含:小写字母、数字、
.、-、#、+ - 不能包含空格
- 使用连字符分隔多词标签:
node.js,ruby-on-rails
API访问限制
- 建议注册API Key提升限额
- 未认证: 300次/天
- 认证用户: 10000次/天
🔄 更新日志
| 日期 | 版本 | 更新内容 |
|---|---|---|
| 2025-11-09 | v1.0 | 初始文档创建,包含完整的搜索语法和标签系统 |
文档完成: 所有六个搜索引擎的详细文档已创建完毕,请查看 总览文档