From c3eef4fa21508c9dc389d4e7af79cf817bbecc6f Mon Sep 17 00:00:00 2001 From: hz4th_coder Date: Mon, 13 Jul 2026 17:03:26 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BA=92=E8=81=94=E7=BD=91=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=A4=9A=E6=90=9C=E7=B4=A2=E5=BC=95=E6=93=8E?= =?UTF-8?q?=E9=80=89=E6=8B=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增搜索引擎选择下拉框 - 支持 Bing 中国(默认)、Bing 国际、Google、百度 - 后端 API 支持 engine 参数 - 添加百度搜索结果解析方法 --- routes/articles.py | 5 +-- services/search_service.py | 70 +++++++++++++++++++++++++++++++++----- static/css/search.css | 15 ++++++++ static/js/search.js | 11 ++++-- templates/search.html | 6 ++++ 5 files changed, 95 insertions(+), 12 deletions(-) diff --git a/routes/articles.py b/routes/articles.py index ce7da58..b5aac9b 100644 --- a/routes/articles.py +++ b/routes/articles.py @@ -140,17 +140,18 @@ def internet_search(): data = request.get_json() keyword = data.get('keyword', '') max_results = data.get('max_results', 10) - save_to_library = data.get('save_to_library', False) + engine = data.get('engine', 'bing_cn') # 默认 Bing 中国 if not keyword: return jsonify({'error': '请提供搜索关键词'}), 400 # 执行互联网搜索 - results = search_service.search_internet(keyword, max_results) + results = search_service.search_internet(keyword, max_results, engine) return jsonify({ 'success': True, 'keyword': keyword, + 'engine': engine, 'results': results, 'count': len(results) }) diff --git a/services/search_service.py b/services/search_service.py index 12978a6..665eb4d 100644 --- a/services/search_service.py +++ b/services/search_service.py @@ -33,18 +33,32 @@ class SearchService: ) return result.stdout, result.stderr, result.returncode - def search_internet(self, keyword, max_results=None): + def search_internet(self, keyword, max_results=None, engine='bing_cn'): """ 从互联网搜索(使用 agent-browser 浏览器自动化) + + 支持的搜索引擎: + - bing_cn: Bing 中国(默认) + - bing_global: Bing 国际版 + - google: Google + - baidu: 百度 """ max_results = max_results or self.max_results results = [] + # 根据搜索引擎选择 URL + encoded_keyword = urllib.parse.quote(keyword) + search_urls = { + 'bing_cn': f"https://cn.bing.com/search?q={encoded_keyword}", + 'bing_global': f"https://www.bing.com/search?q={encoded_keyword}", + 'google': f"https://www.google.com/search?q={encoded_keyword}", + 'baidu': f"https://www.baidu.com/s?wd={encoded_keyword}" + } + + search_url = search_urls.get(engine, search_urls['bing_cn']) + try: - # 1. 打开 Bing 搜索 - encoded_keyword = urllib.parse.quote(keyword) - search_url = f"https://www.bing.com/search?q={encoded_keyword}" - + # 1. 打开搜索引擎 stdout, stderr, code = self._run_browser('open', search_url, '--timeout', '20000') if code != 0: print(f"打开搜索页面失败: {stderr}") @@ -66,9 +80,11 @@ class SearchService: print(f"解析 JSON 失败: {stdout[:500]}") return results - # 4. 从 accessibility tree 中提取搜索结果 - # Bing 搜索结果在 main[aria-label="搜索结果"] 区域内 - results = self._parse_bing_results(data, max_results) + # 4. 根据搜索引擎选择解析方法 + if engine == 'baidu': + results = self._parse_baidu_results(data, max_results) + else: + results = self._parse_bing_results(data, max_results) # 5. 关闭浏览器 self._run_browser('close') @@ -143,6 +159,44 @@ class SearchService: return results + def _parse_baidu_results(self, snapshot_data, max_results=10): + """从百度搜索结果中解析标题和链接""" + results = [] + + snapshot = snapshot_data.get('data', {}).get('snapshot', '') + if not snapshot: + return results + + # 百度搜索结果解析 + refs = [] + lines = snapshot.split('\n') + + for line in lines: + line = line.strip() + + # 百度结果通常在 link 标签中 + if 'link "' in line and '[ref=' in line: + match = re.search(r'link "([^"]+)" \[ref=(e\d+)\]', line) + if match: + title = match.group(1) + ref = match.group(2) + # 过滤百度内部链接和广告 + if len(title) > 10 and '百度' not in title[:6]: + refs.append((title, ref)) + + # 获取每个结果的 URL + for title, ref in refs[:max_results]: + url = self._get_link_url(ref) + if url and 'baidu.com' not in url: + results.append({ + 'title': title, + 'url': url, + 'snippet': '', + 'source': 'baidu' + }) + + return results + def _get_link_url(self, ref): """通过 agent-browser 获取链接的 URL""" try: diff --git a/static/css/search.css b/static/css/search.css index 192ba0b..e9ec94a 100644 --- a/static/css/search.css +++ b/static/css/search.css @@ -87,6 +87,21 @@ font-size: 16px; } +.engine-select { + padding: 15px; + border: 2px solid #e9ecef; + border-radius: 8px; + font-size: 16px; + background: white; + cursor: pointer; + min-width: 120px; +} + +.engine-select:focus { + outline: none; + border-color: #667eea; +} + .search-options { display: flex; gap: 20px; diff --git a/static/js/search.js b/static/js/search.js index 9a2c8e4..3ab3319 100644 --- a/static/js/search.js +++ b/static/js/search.js @@ -19,6 +19,7 @@ document.addEventListener('DOMContentLoaded', () => { async function doSearch() { const keyword = document.getElementById('search-keyword').value.trim(); const maxResults = parseInt(document.getElementById('search-count').value) || 10; + const engine = document.getElementById('search-engine').value; const autoFetch = document.getElementById('auto-fetch').checked; const autoSave = document.getElementById('auto-save').checked; @@ -28,7 +29,13 @@ async function doSearch() { } // 更新状态 - updateStatus('searching', '搜索中...'); + const engineNames = { + 'bing_cn': 'Bing 中国', + 'bing_global': 'Bing 国际', + 'google': 'Google', + 'baidu': '百度' + }; + updateStatus('searching', `正在通过 ${engineNames[engine]} 搜索...`); document.getElementById('search-btn').disabled = true; // 显示进度 @@ -41,7 +48,7 @@ async function doSearch() { const response = await fetch(`${API_BASE}/api/articles/internet-search`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ keyword, max_results: maxResults }) + body: JSON.stringify({ keyword, max_results: maxResults, engine }) }); const data = await response.json(); diff --git a/templates/search.html b/templates/search.html index a59d20a..2f0e195 100644 --- a/templates/search.html +++ b/templates/search.html @@ -29,6 +29,12 @@