search-syntax-pro/docs/search-engines/yandex.md
Zain feaf3ef7de feat(search): 新增多个搜索引擎适配器及文档
- 添加 DuckDuckGo、Brave、Yandex、Reddit、GitHub 和 StackOverflow 适配器
- 实现动态语言选择器功能
- 更新搜索引擎类型定义和国际化翻译
- 添加详细的搜索引擎文档和语法参考
2025-11-10 08:56:29 +08:00

12 KiB

Yandex 搜索引擎适配器文档

📋 基本信息

属性 值
引擎名称 Yandex
官方网站 https://yandex.com
市场定位 俄罗斯领先搜索引擎
全球市场份额 ~2.5%
俄语市场份额 ~60% (第一名)
主要用户群 俄语用户、东欧用户、CIS国家
优先级 P1 (中等)
实施复杂度 🟡 中等
预计工期 2-3天

🎯 产品价值

用户价值

  • ✅ 俄语优化: 最佳的俄语搜索体验
  • ✅ 区域覆盖: 覆盖俄罗斯、乌克兰、白俄罗斯等
  • ✅ 本地化服务: 地图、新闻、邮件等生态系统
  • ✅ 独特语法: 支持其他引擎不支持的特殊搜索

业务价值

  • 🌍 国际化战略支持
  • 📈 扩展非英语市场
  • 💡 差异化竞争优势
  • 🎯 覆盖特定地域用户群

🔍 支持的搜索语法

1. 基础语法

1.1 网站内搜索 (site:)

关键词 site:域名

示例:

поиск site:wikipedia.org
React site:github.com

说明: 限定搜索结果只来自指定网站


1.2 主机搜索 (host:)

关键词 host:完整主机名

示例:

warming host:www.wikipedia.org

说明: 搜索特定主机上的内容(需要包含www等前缀)

格式: www.second-level-domain.top-level-domain


1.3 反向主机搜索 (rhost:) ⭐ 独有

关键词 rhost:反向域名

示例:

warming rhost:org.wikipedia.www
warming rhost:org.wikipedia.*

说明:

  • 使用反向域名格式:top-level.second-level.www
  • 支持通配符 * 匹配所有子域名
  • Yandex独有的特殊语法

用途: 搜索整个域名下的所有子域


1.4 MIME类型搜索 (mime:) ⭐ 独有

关键词 mime:类型

示例:

报告 mime:pdf
数据 mime:xml
图片 mime:image

说明:

  • 搜索特定MIME类型的文件
  • 比 filetype: 更精确
  • Yandex独有语法

常用MIME类型:

  • pdf - PDF文档
  • doc - Word文档
  • xls - Excel文档
  • xml - XML文件
  • image - 所有图片类型

1.5 精确匹配 ("...")

"完整短语"

示例:

"machine learning tutorial"
"React best practices"

2. 逻辑运算符

2.1 AND 运算 (&&)

关键词1 && 关键词2

示例:

Python && tutorial
前端 && 开发

说明: 结果必须同时包含两个关键词


2.2 OR 运算 (|)

关键词1 | 关键词2

示例:

React | Vue
JavaScript | TypeScript

说明: 结果包含任一关键词即可


2.3 必须包含 (+)

+必须包含的词 其他词

示例:

Python +tutorial Flask

说明: +后的词必须出现在结果中


2.4 排除 (-)

关键词 -排除词

示例:

Python -Django

说明: 排除包含指定词的结果


3. 特殊搜索

3.1 日期范围

关键词 date:YYYYMMDD..YYYYMMDD

示例:

新闻 date:20240101..20241231

说明: 搜索指定日期范围内的内容


3.2 标题搜索 (title:)

title:关键词

示例:

title:tutorial React

说明: 只搜索标题中包含关键词的页面


3.3 URL搜索 (url:)

url:关键词

示例:

url:github
url:docs

说明: 只搜索URL中包含关键词的页面


🔧 技术实现

URL 构建格式

基础URL:

https://yandex.com/search/

查询参数:

interface YandexSearchParams {
  text: string;           // 搜索查询
  lr?: number;           // 地区ID (如: 213=莫斯科, 2=圣彼得堡)
  lang?: string;         // 界面语言 (如: 'ru', 'en')
}

完整URL示例:

https://yandex.com/search/?text=React+tutorial+site%3Agithub.com

适配器实现模板

import type { SearchEngineAdapter, SearchParams, SyntaxType, ValidationResult, UIFeatureType } from '@/types'

/**
 * Yandex 搜索引擎适配器
 * 支持俄语优化和独特的高级搜索语法
 */
export class YandexAdapter implements SearchEngineAdapter {
  getName(): string {
    return 'Yandex'
  }

  getBaseUrl(): string {
    return 'https://yandex.com/search/'
  }

  /**
   * 构建 Yandex 搜索查询 URL
   */
  buildQuery(params: SearchParams): string {
    const baseUrl = this.getBaseUrl()
    const query = this.buildSearchQuery(params)
    const urlParams = new URLSearchParams({
      text: query
    })
    
    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. 网站内搜索
    if (params.site && params.site.trim()) {
      queryParts.push(`site:${params.site.trim()}`)
    }

    // 4. MIME类型搜索 (Yandex独有)
    if (params.fileType && params.fileType.trim()) {
      queryParts.push(`mime:${params.fileType.trim()}`)
    }

    // 5. 标题搜索
    if (params.inTitle && params.inTitle.trim()) {
      queryParts.push(`title:${params.inTitle.trim()}`)
    }

    // 6. URL搜索
    if (params.inUrl && params.inUrl.trim()) {
      queryParts.push(`url:${params.inUrl.trim()}`)
    }

    // 7. 日期范围
    if (params.dateRange) {
      const { from, to } = params.dateRange
      if (from && to) {
        const fromDate = this.formatDate(from)
        const toDate = this.formatDate(to)
        queryParts.push(`date:${fromDate}..${toDate}`)
      }
    }

    // 8. 排除关键词
    if (params.excludeWords && params.excludeWords.length > 0) {
      params.excludeWords.forEach(word => {
        if (word.trim()) {
          queryParts.push(`-${word.trim()}`)
        }
      })
    }

    // 9. OR 逻辑关键词 (使用 | 符号)
    if (params.orKeywords && params.orKeywords.length > 0) {
      const orQuery = params.orKeywords
        .filter(word => word.trim())
        .join(' | ')
      if (orQuery) {
        queryParts.push(`(${orQuery})`)
      }
    }

    return queryParts.join(' ')
  }

  /**
   * 格式化日期为 YYYYMMDD
   */
  private formatDate(dateString: string): string {
    const date = new Date(dateString)
    const year = date.getFullYear()
    const month = String(date.getMonth() + 1).padStart(2, '0')
    const day = String(date.getDate()).padStart(2, '0')
    return `${year}${month}${day}`
  }

  /**
   * 验证语法类型
   */
  validateSyntax(syntax: SyntaxType): boolean {
    const supportedSyntax: SyntaxType[] = [
      'site',
      'filetype', // 实际使用 mime:
      'exact',
      'intitle',
      'inurl',
      'exclude',
      'or',
      'date_range'
    ]
    return supportedSyntax.includes(syntax)
  }

  /**
   * 获取支持的语法类型
   */
  getSupportedSyntax(): SyntaxType[] {
    return [
      'site',
      'filetype',
      'exact',
      'intitle',
      'inurl',
      'exclude',
      'or',
      'date_range'
    ]
  }

  /**
   * 获取支持的UI功能特性
   */
  getSupportedFeatures(): UIFeatureType[] {
    return [
      'site',
      'filetype',
      'exact_match',
      'intitle',
      'inurl',
      'exclude',
      'or_keywords',
      '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.dateRange) {
      if (params.dateRange.from && params.dateRange.to) {
        const fromDate = new Date(params.dateRange.from)
        const toDate = new Date(params.dateRange.to)
        if (fromDate > toDate) {
          errors.push('开始日期不能晚于结束日期')
        }
      }
    }

    return {
      isValid: errors.length === 0,
      errors,
      warnings
    }
  }

  /**
   * 获取搜索建议
   */
  getSearchSuggestions(params: SearchParams): string[] {
    const suggestions: string[] = []

    if (params.keyword && !params.site) {
      suggestions.push('使用 site: 可以在特定网站内搜索')
    }

    if (params.fileType) {
      suggestions.push('Yandex使用mime:语法进行文件类型搜索')
    }

    if (params.keyword && !params.dateRange) {
      suggestions.push('可以使用日期范围筛选最新内容')
    }

    return suggestions
  }
}

📝 实施清单

Phase 1: 核心功能 (Day 1)

  • 创建 src/services/adapters/yandex.ts
  • 实现 YandexAdapter 类
  • 实现基础语法 (site, mime, exact)
  • 单元测试

Phase 2: 高级功能 (Day 2)

  • 实现逻辑运算符 (&&, |, +, -)
  • 实现日期范围搜索
  • 实现 title: 和 url: 语法
  • 参数验证

Phase 3: 特殊功能 (Day 3)

  • 实现 rhost: 反向域名搜索(可选)
  • 实现 host: 主机搜索(可选)
  • UI集成和国际化
  • 完整测试

✅ 测试用例

describe('YandexAdapter', () => {
  const adapter = new YandexAdapter()

  test('基础关键词搜索', () => {
    const url = adapter.buildQuery({
      keyword: 'React tutorial',
      engine: 'yandex'
    })
    expect(url).toContain('text=React+tutorial')
  })

  test('MIME类型搜索', () => {
    const url = adapter.buildQuery({
      keyword: '报告',
      fileType: 'pdf',
      engine: 'yandex'
    })
    expect(url).toContain('mime%3Apdf')
  })

  test('日期范围搜索', () => {
    const url = adapter.buildQuery({
      keyword: '新闻',
      dateRange: {
        from: '2024-01-01',
        to: '2024-12-31'
      },
      engine: 'yandex'
    })
    expect(url).toContain('date%3A20240101..20241231')
  })

  test('OR逻辑运算', () => {
    const url = adapter.buildQuery({
      keyword: 'tutorial',
      orKeywords: ['React', 'Vue'],
      engine: 'yandex'
    })
    expect(url).toContain('React+%7C+Vue')
  })

  test('组合查询', () => {
    const url = adapter.buildQuery({
      keyword: 'programming',
      site: 'github.com',
      inTitle: 'tutorial',
      excludeWords: ['beginner'],
      engine: 'yandex'
    })
    expect(url).toContain('site%3Agithub.com')
    expect(url).toContain('title%3Atutorial')
    expect(url).toContain('-beginner')
  })
})

🌍 国际化支持

{
  "engines.yandex": "Yandex",
  "engines.yandex.description": "俄罗斯领先的搜索引擎",
  "engines.yandex.features": {
    "mime": "MIME类型搜索",
    "rhost": "反向域名搜索",
    "host": "主机搜索",
    "russian": "俄语优化"
  },
  "engines.yandex.tips": {
    "mime": "使用mime:而非filetype:进行文件搜索",
    "rhost": "rhost:可以搜索整个域名的所有子域",
    "operators": "支持 && (AND) 和 | (OR) 逻辑运算"
  }
}

📚 参考资源

官方文档


⚠️ 特殊说明

rhost: 语法使用示例

搜索整个Wikipedia域名:

关键词 rhost:org.wikipedia.*

只搜索www.wikipedia.org:

关键词 rhost:org.wikipedia.www

MIME vs filetype

Yandex (mime:) 标准 (filetype:)
mime:pdf filetype:pdf
mime:image filetype:jpg
mime:xml filetype:xml

建议: UI层将 filetype: 转换为 mime: 以适配Yandex


🔄 更新日志

日期 版本 更新内容
2025-11-09 v1.0 初始文档创建,包含独特语法支持

下一步: 查看 Reddit 文档 了解社区搜索引擎的实现细节