如何借助Google可编程搜索实现带标签页的网页与图片搜索结果展示
如何借助Google可编程搜索实现带标签页的网页与图片搜索结果展示
看起来你已经迈出了很好的第一步,现在的核心问题是如何同时发起两种类型的搜索请求,并把结果分别渲染到对应的标签页里。其实不用纠结于“怎么加两个hndlr”,更清晰的思路是拆分回调函数,发起两个独立的API请求,分别处理网页和图片的结果,再把它们渲染到各自的标签容器中。下面是具体的实现方案:
1. 先修正DOM中的重复ID问题
你原来的代码里有两个id="resultmeta",这会导致JS无法正确区分它们,所以先把它们改成唯一ID:
- 网页标签页的元信息容器改成
id="web-resultmeta" - 图片标签页的改成
id="image-resultmeta"
2. 拆分回调函数,各司其职
原来的hndlr既要处理网页又要处理图片,逻辑太混乱。我们拆成两个专属函数:
handleWebResults:专门处理网页搜索响应,渲染到「Search Results」标签页handleImageResults:专门处理图片搜索响应,渲染到「Image Results」标签页
每个函数只负责自己的容器,不会清空或修改对方的内容,避免冲突。
3. 发起两个独立的API请求
分别构造网页和图片搜索的API URL,创建两个<script>标签插入文档,各自调用对应的回调函数即可。
修改后的完整代码
HTML部分(修正ID后的结构)
<html> <head> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script> </head> <body> <form action="searchresults.html" id="cse-search-box"> <div> <input class="" name="q" type="text"> <input class="" type="submit"> </div> </form> <ul class="nav nav-tabs" id="mytabs" role="tablist"> <li class="nav-item" role="presentation"> <a class="nav-link active" id="tab-0" data-bs-toggle="tab" href="#tabpanel-0" role="tab" aria-controls="tabpanel-0" aria-selected="true">Search Results</a> </li> <li class="nav-item" role="presentation"> <a class="nav-link" id="tab-1" data-bs-toggle="tab" href="#tabpanel-1" role="tab" aria-controls="tabpanel-1" aria-selected="false">Image Results</a> </li> </ul> <div class="tab-content pt-5" id="tab-content"> <div class="tab-pane active" id="tabpanel-0" role="tabpanel" aria-labelledby="tab-0"> <div class="gsc-result-info" id="web-resultmeta"></div> <div id="searchresults"></div> </div> <div class="tab-pane" id="tabpanel-1" role="tabpanel" aria-labelledby="tab-1"> <div class="gsc-result-info" id="image-resultmeta"></div> <div id="images"></div></div> </div> <script> // JavaScript 代码放在这里 </script> </body> </html>
JavaScript部分(拆分回调+双请求)
// 处理网页搜索结果 function handleWebResults(response) { // 更新网页结果的元信息 document.getElementById("web-resultmeta").innerHTML = "About " + response.searchInformation.formattedTotalResults + " results (" + response.searchInformation.formattedSearchTime + " seconds)"; // 清空网页结果容器 const webResultsContainer = document.getElementById("searchresults"); webResultsContainer.innerHTML = ""; // 渲染网页搜索结果 for (var i = 0; i < response.items.length; i++) { var item = response.items[i]; var content = ""; // 网页结果标题链接 content += "<a class='gs-title' href='" + item.link + "'>" + item.htmlTitle + "</a><br />"; // 网页结果缩略图(判断是否存在,避免报错) if (item.pagemap?.cse_thumbnail) { content += "<a href='" + item.link + "'><img src='" + item.pagemap.cse_thumbnail[0].src + "'></a>"; } // 网页结果摘要 if (item.htmlSnippet) { content += "<p>" + item.htmlSnippet + "</p>"; } // 将结果添加到容器 const resultDiv = document.createElement("div"); resultDiv.innerHTML = content; webResultsContainer.appendChild(resultDiv); } // 渲染网页结果分页 var totalPages = Math.ceil(response.searchInformation.totalResults / 10); var currentPage = Math.floor(start / 10 + 1); var pageControls = "<div class='gsc-results'><div class='gsc-cursor-box gs-bidi-start-align' dir='ltr'><div class='gsc-cursor'>"; for (var x = 1; x <= totalPages && x <=10; x++) { pageControls += "<div class='gsc-cursor-page"; if (x === currentPage) pageControls += " gsc-cursor-current-page"; var pageLinkStart = x * 10 - 9; pageControls += "'><a href='test.html?start="+pageLinkStart+"&q="+query+"'>"+x+"</a></div>"; } pageControls += "</div></div></div>"; webResultsContainer.innerHTML += pageControls; } // 处理图片搜索结果 function handleImageResults(response) { // 更新图片结果的元信息 document.getElementById("image-resultmeta").innerHTML = "About " + response.searchInformation.formattedTotalResults + " results (" + response.searchInformation.formattedSearchTime + " seconds)"; // 清空图片结果容器 const imageResultsContainer = document.getElementById("images"); imageResultsContainer.innerHTML = ""; // 渲染图片搜索结果 for (var i = 0; i < response.items.length; i++) { var item = response.items[i]; var content = ""; // 图片链接与原图展示 content += "<a href='" + item.link + "' target='_blank'><img src='" + item.link + "' alt='" + item.title + "' style='max-width:200px; margin:10px;'></a>"; // 图片标题 content += "<p>" + item.title + "</p>"; // 将结果添加到容器 const resultDiv = document.createElement("div"); resultDiv.innerHTML = content; imageResultsContainer.appendChild(resultDiv); } // 渲染图片结果分页(确保分页时仍为图片搜索) var totalPages = Math.ceil(response.searchInformation.totalResults / 10); var currentPage = Math.floor(start / 10 + 1); var pageControls = "<div class='gsc-results'><div class='gsc-cursor-box gs-bidi-start-align' dir='ltr'><div class='gsc-cursor'>"; for (var x = 1; x <= totalPages && x <=10; x++) { pageControls += "<div class='gsc-cursor-page"; if (x === currentPage) pageControls += " gsc-cursor-current-page"; var pageLinkStart = x * 10 - 9; pageControls += "'><a href='test.html?start="+pageLinkStart+"&q="+query+"&searchType=image'>"+x+"</a></div>"; } pageControls += "</div></div></div>"; imageResultsContainer.innerHTML += pageControls; } // 获取查询参数(处理特殊字符与截断) var query = document.URL.substr(document.URL.indexOf("q=") + 2); if (query.includes("&")) { query = query.split("&")[0]; } var start = document.URL.substr(document.URL.indexOf("start=") + 6, 2); if (start === "1&" || document.URL.indexOf("start=") === -1) start = 1; // 发起网页搜索请求 var webSearchScript = document.createElement("script"); webSearchScript.type = "application/javascript"; webSearchScript.src = "https://www.googleapis.com/customsearch/v1?key=YOUR_API_KEY&cx=YOUR_CX&start="+start+"&q=" + encodeURIComponent(query) + "&callback=handleWebResults"; document.body.appendChild(webSearchScript); // 发起图片搜索请求 var imageSearchScript = document.createElement("script"); imageSearchScript.type = "application/javascript"; imageSearchScript.src = "https://www.googleapis.com/customsearch/v1?key=YOUR_API_KEY&cx=YOUR_CX&start="+start+"&q=" + encodeURIComponent(query) + "&searchType=image&callback=handleImageResults"; document.body.appendChild(imageSearchScript);
额外注意事项
- 确保你的API Key和CX值正确,且已在Google Cloud控制台启用图片搜索权限;
- 注意API调用限制:免费版Google Custom Search API有每日调用限额,避免超出;
- 可以进一步优化样式(比如把图片结果改成网格布局),让界面更接近Google托管版的体验。
备注:内容来源于stack exchange,提问作者user5853892




