打造完美的 ajax 版 Google 自定义搜索

通常我们选用 Google CSE 自定义搜索引擎代替网站自身的搜索服务,可以减轻服务器的负载,但更重要的原因是 Google 搜索有强大的词语分割、智能匹配、拼写纠正功能,甚至能将 “bb” 与 “BlackBerry”, “DM” 与 “桌面管理器” 进行通配,这些算法是我们自己做不到的。我以前在博客中采用 iframe 版的 CSE, 最近把它换成了定制性更强,基于 Google ajax API 的新版,将经验分享一下。本方案优点:

  • 不搜索时完全不加载任何相关资源,如 ajax API 库等
  • 搜索 url 非常干净,没有多余的参数:fis.io/search?q=cse
  • 方便使用 javascript 对结果样式进一步调整

获取代码

首先需要在 控制面板 – 外观新功能!中选择“搜索元素”模式 (Search element), 再选择一种布局和一种样式。实际上 ajax API 能做的事情非常多,比如就在搜索框下方即时展开结果列表。如果把结果列表悬浮绝对定位,再加上 Search as user Types, 就可以做 apple.com 右上角那种搜索样式了,一边输入一边匹配。

但是考虑到小博客的站内搜索被使用得并不多,我还是选择了两栏布局,将结果列表放在一个专门的页面 /search 中,这样的好处是不搜索的时候可以不加载多余的内容:API 库,JS, CSS 等等。

改造搜索框

先不急着把获取的那一大堆代码往搜索框上放,上面说了,我们要的效果是不搜索的时候不加载。就改造一下模板原生的搜索框就可以了,让它提交用户输入的内容到 /search 这个页面,就这样。我的 header.php 中的搜索框是这样的:

<form action="/search" id="searchbox">
    <input type="text" name="q" id="input_search" />
    <input type="submit" value="搜索" />
</form>

一个 form 中装一个输入框和一个按钮,关键内容是 action=”/search” 和 name=”q”, 表示将会跳转到 /search?q=搜索的内容.

结果页面

建立一个页面 /search 来放入所有 CSE 代码。页面正文中放入 id=”cse” 的 div, 搜索执行的时候脚本将会改写其中的内容。

<div id="cse">正在搜索...</div>

然后在页面任意位置,比如末尾,写入前面获得的两个 javascript 代码,一个是 ajax API 库 google.com/jsapi, 另一个是以 google.load 开头的一大串。还有些 CSS, 是前面获取代码的时候选择的一种样式。

但这时候还不会自动执行用户之前输入的搜索,要从 url 请求中把搜索词剥离出来,并执行。这里我用了 Kevin Yang 提供的方法,在 draw(‘cse’) 一行后加入:

var match = location.search.match(/q=([^&]*)(&|$)/);
if(match && match[1]){
    var search = decodeURIComponent(match[1]);
    customSearchControl.execute(search);
}

现在这个搜索系统就可以正常工作了。下面是对脚本的进一步自定义,只逐条说明,不每次都写完整的代码,我会把完整的修改后的脚本放在本文末尾。如果今后代码发生变动,请自行查看我的 搜索结果页 源代码。

不加载 Google 的 CSS

如果要用自己网站的样式,最好是完全不加载 Google 的 CSS, 不然覆盖样式就有得写了。在 google.load 中加入 “nocss” : true 即可。

google.load('search', '1', {language : 'zh-CN' , "nocss" : true });

无结果时显示的文字

由 setNoResultsString 控制,在无结果时将字串写入到 “正在搜索” 处。中文语言下缺省值为“无结果”

customSearchControl.setNoResultsString('什么也没找到,请重试');

结果每页条数

由 setResultSetSize 控制,可选参数为 FILTERED_CSE_RESULTSET 10条;LARGE_RESULTSET 8条;SMALL_RESULTSET 4条。

customSearchControl.setResultSetSize( google.search.Search.SMALL_RESULTSET);

是否在新标签中打开链接

由 setLinkTarget 控制,一般用到的就是 LINK_TARGET_BLANK 和 LINK_TARGET_SELF 两种。

customSearchControl.setLinkTarget( google.search.Search.LINK_TARGET_SELF);

搜索执行完毕后调用其它脚本

由 setSearchCompleteCallback 控制,这是一个相当灵活的命令,我这里用它来将搜索结果标题中的“老肥博客 » 非唠不可”去掉,不然每条标题后面都有这样一句,比较难看。这里我另外加载了 jQuery 来用,当然这不是必需的,如果没有需要就不用了。

customSearchControl.setSearchCompleteCallback(null, function() {
    $('input.gsc-input').select();
    $('a.gs-title').unwrap().wrap('<h3></h3>').each(function() {
        var title = $(this).html().replace(/\|.*/g, '');
        $(this).html(title);
    });
    $('b:contains("...")').contents().unwrap();
});

以上在 setSearchCompleteCallback 中执行了三个步骤:

  • 将焦点放到搜索框 input.gsc-input 中并全选文字;
  • 将搜索结果标题链接 a.gs-title 先去掉外面的一层 div, 再套在 <h3> 内(这样方便沿用全局 CSS 里面的标题样式),然后对每个标题链接读取内容,替换,写回去;
  • 将包含 “…” 的关键字高亮去掉 <b>;(Google 用 <b> 标示关键字,但不知为何 “…” 也都这样标记)

其它

我的搜索页面中还有一些脚本和样式,比如将 CSE 的搜索框伪装成模板原生的输入框,这样可以避免多次搜索的时候重复加载页面;从搜索框中取得当前关键字,写入到右侧提示区;等等,比较特殊,这里就不细写了,反正 Firebug 什么的都一眼看穿。

另外,前面提到 Kevin 的文章中有个技巧很不错,只让单篇文章出现在搜索结果中,排除掉翻页、标签等页面,像我用 .html 作为单篇文章的链接结构就很好办,直接在 CSE 控制面板中设置“包含的网站”为 fis.io/*.html, 就排除了其它形式的链接结构。

微博也是博客,我在 fis.io/*.html 之外还将 twitter.com/fisio/* 编入了索引,在搜索某些内容的时候会看到我的推也在搜索结果中。

最后是我的 /search 页面中相关脚本完整版:

<script src="https://www.google.com/jsapi" type="text/javascript"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
google.load('search', '1', {language : 'zh-CN' , "nocss" : true });
google.setOnLoadCallback(function(){
    var customSearchControl = new google.search.CustomSearchControl('015811090669888844099:szzhafqj8_4');
    customSearchControl.setResultSetSize(google.search.Search.SMALL_RESULTSET);
    customSearchControl.setLinkTarget(google.search.Search.LINK_TARGET_SELF);
    customSearchControl.setNoResultsString('<img src="/b.gif" class="wp-smiley sm-sad">  什么也没找到,请重试');
    customSearchControl.setSearchCompleteCallback(null,function() {
        $('input.gsc-input').select();
        var searchwords = $('input.gsc-input').val();
        $('.p > b').text(searchwords);
        $('a.gs-title').addClass('new').unwrap().wrap('<h3></h3>').each(function() {
            var title = $(this).html().replace(/\|.*/g, '');
            $(this).html(title);
        });
        $('b:contains("...")').contents().unwrap();
        $('.gsc-cursor-current-page').removeClass('gsc-cursor-page');
    });
    customSearchControl.draw('cse');
    var match = location.search.match(/q=([^&]*)(&|$)/);
    if(match && match[1]){
        var search = decodeURIComponent(match[1]);
        customSearchControl.execute(search);
    }
});
</script>

参考文献

最新评论

  • fisio 可不,Google Reader 都去世十年了… Google Reader 的分享和效率
  • 轻重 天哪!今天整理Evernote,发现这条2010年的剪藏笔记,点击连接,原网站还在!12年了,中文互联网早已面目全非! Google Reader 的分享和效率
  • 小波 重新改博客,看看以前的wp小伙伴的博客,发现绝大部分都关了,没想到你的还在,只是停在11年了 我为什么爱 Twitter
  • 心灵博客 当年有这个效果已经很不错哦 diy 山寨投影家庭影院
  • fisio 可不咋地!您也是老司机了 我为什么爱 Twitter

发表您的评论

评论将回复给

😀🙂😯😁🙁😄😆😝😜👍🌈💖🎂

目前有 187 条评论

图标比较可爱

肥叔叔,这篇文章写好,怎么没有特别通知我来抢沙发咩,我表示not happy

自己订阅…

咩。我的google reader 太汹涌了,又不是每天都看咩。。。 叔叔,我要special

http://feedburner.google.com/fb/a/mailverify?uri=fisio

这个够 special 了吧?

机器人 提醒木有情调

下次我记得的时候人肉提醒..

叔叔乖,奖励棒棒糖一只 (/ ̄ˇ ̄)/

你们有JQ,居然公开调情 哼哼

然后呢?

你是赤裸裸的嫉妒

嗯 Google自定义搜索添加到自己的博客上不错。。

嗯,找个时间也加到自己blog上去~~ 😛

诶?话说评论换成ajax的了?不错不错~~~~ 👍

哈哈,是啊

鼠标移到代码部分为什么要overflow:visible呢?文字破框而出了呀~

我觉得这样方便阅读些。。

今天把文章发出来才临时加上的 white-space: nowrap 和 overflow-x: auto, 回头再斟酌一下 😛

我觉得可以在hover的时候把<code>设为float:left
不过缺点是要紧跟清除浮动的标签,而且如果代码真的很长的话还是会有些问题

谢谢您的意见,float 这样好多了,边框一起变宽了。

我一开始就单独设了个 class 来做这个 hover, 就是担心以前文章里面的代码搞出问题,这样就不用去复查以前贴的代码了 😀

常规留言。。。看不懂

以前尝试过,没有成功!

不知道我这篇算写明白了没有 😀

好像挺有趣,回头试一下

哈哈。。

好,我去把我的搜索框修改一下,问题是,搜索框里面有个背景字啊,custom srearch,这个这么去掉啊,我看有点博客搜索框没这个字啊。

文中的方法加的输入框就是个普通的输入框,不是用的 google 的代码

研究一下,回头我也试试。

改改看上去爽多了

不错,支持一下

我看我有必要在我新主题内加上这功能。。。 8D

测试一下的!

楼层显示有点问题呀,都是1楼!

这个问题还没想到什么好的办法,不过反正刷新一下就是了…

你的主题很漂亮

给你的i[at]fls.io发邮件,是不是没收到啊?

问一下你的主题中,CSS中的当前页面(class:current_page)是如何把“存档”给做进去的?比如,点击你任一篇文章,都会发现,“订阅”页面被标记为当前页面,that’s
cool!这是如何实现的呢?谢谢。

我回复过了哈。。你mx什么的正常么,其它邮件收取是否正常?

哦,看到了……
忘记把Google Apps信箱的邮件转发到主信箱了……

呃。。。好吧
我现在都只用 google apps 邮箱了
另一个同名的 google account 没有 gmail 服务

我很喜欢你博客,很想要你所有的widget和代码,呵呵

抱歉,目前没有将修改版主题公布的打算..

似懂非懂看完了,等哪天再亲手实践一下

HOHO,不想在中国google已经完了

不会吧

不清不楚 看不明白

很完美!!!

老肥!我已经完全折服了。爱死您的博客了!
问下,链接上的箭头是什么插件?

那只是个 css 样式,应用于 a class=”external”, 有个右边的 padding, 然后应用了一个背景图片 😀

搜索结果标题怎么去掉博客的名称呀?

参考一下我的代码,就是这行:

var title = $(this).html().replace(/\|.*/g, ”);

将标题读取了之后,进行正则替换,扔掉了第一个 “|” 之后的所有内容,如果你的标题格式并不是这样,改成自己的就好了,| 前面的 \ 是转义符。

谢谢,这个问题解决了。

按照你的方法做了。为什么用IE和chrome搜索中文没有任何结果,而firefox下却正常呢?

这个比较奇怪了,仔细比较一下代码吧。。。

另外还有页面编码什么的也检查一下?

代码比较好几次了,如果我眼睛无码应该没问呀。我的博客不是放在根目录而是xx.com/blog/这样子的,是不是这个和那个正则表达“var match = location.search.match(/q=([^&]*)(&|$)/);”式有关系?

应该是这一步的原因,因为从你的搜索结果页面上的 google 搜索框去搜索中文是正常的.. 😮

试试看在 /q 之前加上 /blog 呢?

我测试了下,确定是子目录的问题,试着加/blog无效。这个该怎么修改呢?

我也是用的这个主题,请问怎么能实现评论框随着页面的往下而自动向下滚动 呢?

看本页的源代码,里面引用了 jquery, 还有一段代码是滚动用到的,源代码里搜索一下 toppadding 就找到啦

谢谢了

原来高手隐于市啊

我这里GOOGLE好像访问不了呀,郁闷 :O

留个名 这个博客做得太好了 🙂

继续支持老肥童鞋…顺便也跟进下新技术.

有意思! 👍

这不错啊 ,好东西,完了我也加上

看得有点迷糊!!!!

👍 测试成功了,哈哈,我用的PAGE的模板,可以看这里,样式就象这样:http://shengshengman.com/search?q=hello+site%3Ashengshengman.com

谷歌推出的很多有意思的插件,可惜被大陆屏蔽了,真是郁闷。。。

先看看,大家都用了我再玩。。

:)不错。。。

现在返回的结果最多只能有8页吗?上一页-下一页怎么做的?

翻页按钮是自带的,我只是调过了样式,如果有更多的搜索结果,好像是另外打开一个 google 的页面来显示,也可以关闭掉这个外链

Just for a test!

不错,学习了…

效果是不错啊

博客好热闹,留言真多,路过。。。。

嗯,找个时间也加到自己blog上去~~~ 👍

都是技术方面的东西哦,我都看不懂。

谢谢了.是高手呀.

我按照博主的方法,发现只能搜索英文能同步到search页面,但是如果搜索中文,搜索的关键字就不行

这个问题我倒是没遇到,不过有个朋友遇到过,来问过我,后来好像他自己把问题解决了,不如你问问看他吧? http://www.badmilk.com.cn/blog/contact

您好,看了好多人做的Google自定义搜索,均没有完美解决问题,你的搜索看起来解决了许多问题,我研究了很久依然没成功,主要是样式的定义,无法控制外观,出现很多问题,可否把你的搜索的相关文件发到我QQ邮箱:394731189@qq.com
我好研究一下,非常感谢

样式和脚本都在页面源代码里面,到搜索页查看页面源代码就可以了

跟其他人一样,用中文传参数会报错:
解码的url不合法
解决方法是将页面编码变成utf-8
另外一个问题是,你试着用ie浏览器浏览下,就会发现,你的搜索框在输入一次内容之后缩小成只容一个字符那样的宽度,解决的方法是,在你的css文件中加入如下这行:
.gsc-input{width:155px;}
定义他的宽度。

其实还存在一个问题,你用ie浏览器搜索会发现,第一条搜索结果的标题没有显示,
我改了你自己定义的一些jQuery,我也不知道咋意思,不过这问题被我稀里糊涂的解决了。

博主,关注您博客很久了,可以和您做一个友情吗?

有时间我也要试下! 😀

其实还有个致命的漏洞,你在你的博客搜索
字母”b” 这个关键字看看
你再测试一下分页,你点下第七页,就会发觉
本来只有八页,现在变成了只有两页而已。请问博主,这个问题如何解决? 8)

这个问题也没多严重吧,而且估计也做不了什么

已经点阅!!

这篇文章不错.收藏一下.谢谢了!

不错。。支持

老肥是个非常有耐心,写得好仔细啊

江总书记,病句啊。。

非常感谢你的博客,我的项目完成了,大家可以看看我做的自定义搜索
http://www.nomoso.cn/search_new.php?action=class_ques&c=4
XD

感谢你的博客,我的项目也做完了,解决了很多问题,欢迎大家跟我讨论
这是我的Google自定义搜索
http://www.nomoso.cn/search_new.php?action=class_ques&c=4

哈哈哈,貌似评论重复了,因为我点第一次没反应,关于输入b翻页问题,其实是Google自己的问题,这问题我测试过了,的确是Google自己的问题,可能有人不相信Google这大公司也有这种错误,其实还有一个乱码的问题,Google自己的网站上也是出现这个问题。

确实是高手

这个不错,比iframe的可自定义的内容多了很多

博客更新的不错。支持

按老肥的教程做成功了,谢谢老肥,写的很仔细 👍

0.0。。评论框竟然是飘浮的。。飘浮啊。。
———-
热。。。

好文。另,评论框跟随很富想象力

测试一下啦 👍

这个自定义搜索有意思,而且也很漂亮

和我同在一个服务器的老肥。。。

很好的功能,正在思考博客里面的搜索框

准备弄弄

加上去了 XD

模板真漂亮~~!可惜我不太会CSS~

老肥这favicon看着眼熟……

那是。。哈哈

这个主题好让人眼馋啊,什么时候能发出来啊?[img]http://gif2show.appspot.com/smile/11.gif[/img]

忒厉害 订阅中

可惜我也不太会CSS~

刚整理了下收藏夹,若干年前收藏的博客吖

试一下回复

确实不错,不知道能不能加到cms上~

发现搜索后搜索框的长度会变短。

那是 IE6

喜欢google的产品

有时间也在自己的博客上试一下。毕竟自己的博客就是针对Google的技术的 😛

为什么我的最多只显示3页,难道单纯是索引的太少了? http://hotoo.github.com/blog/search.html

搜 google 有四页..

另外一个问题:搜索 vimwiki 第一页的时候显示有 3 页,但是翻页到后面,却只有两页。然后翻回到第一页还是 3 页。

这个,我也是这样。。

真不错

很不错

这个感觉好麻烦 想弄的来着。。。

你这个域名 叼

这么好的博客,我从你这至少都取得了2名访客的回访了。不知道您是不是最近过于太忙的缘故,最近您好像都不怎么更新文章了。

还不错哦

我很喜欢你博客,很想要你所有的widget和代码,呵呵

不错,感谢分享啊

支持下 呵呵

8) 🙁 ;D

👍 🎂

技术文,留个脚印,慢慢详读。

博主 2011 新年快乐~!

请问能否给出google adsense版本的搜索能功能呢?

动态的评论框,感觉不错~~~

学习改造中。

不知道为什么 我那只显示一条搜索信息。 郁闷死了 能指导下不。

有空摆弄下…

谢谢老肥的分享,这次博客改造正好用得上!

很少人用到博客上的搜索~~

很不错,收藏了! 😀

非常实用的文章

听说今天是纪念日

😛

你这个主题是我见过最强悍的了,哇,这个方法更爽,哈哈,偶像啊

有时候我在线我们的博客真的需要那么强大的搜索功能吗?我现在改用默认的了,懒得改模板

博主是技术党啊。这个个性搜索蛮实用的。支持下

有空试试 🙂

好久没更新文章啦?
好文章,原来谷歌搜索也有API

学习了 ;D

果然很好、
楼主域名也很棒啊

GOOGLE 提供的东西都那么好利用。 😀

这个评论框很好玩

博主这个留言板,太好了

博主,你是怎样去掉自定搜索再带的那个搜索框的?

不是去掉了自定搜索的搜索框,而是留了它,去掉了原来位置的那个

学习了!!!但请问有没有办法让出来的结果的链接不是通过google的url跳转阿?遇到敏感词时一跳转就被墙,貌似90秒左右

google 就是google,每样东西都很好用

要用到了,来看看这篇。

这真是技术型文章啊,赶紧折腾。

google cse最近改版了,作为新的趋势,希望博主能对这篇博文更新下

贵站现在用的是该文描述的方法吗?怎么搜索的时候不显示搜索结果呢?测试了 IE9 和 Chrome。

是的,但是搜索一切正常嘛

那看来是我的 IE9 出问题了,搜索之后没有结果显示。
刚又试了试 Firefox,倒是显示搜索结果了。

请教站长,为什么我按照以下步骤,都没有成功呢?
1.把“searchform”搜索框代码更改你上述的代码
2.建立 cse.php文件上传,并建立search页面【导入cse.php模板】,cse.php模板的代码是最后/search的完整版;
结果一点效果都没有。。。我不太懂代码,我上面这样的步骤有什么不对的吗?
对了,你的固定链接是怎么设置的?

麻烦站长答复,非常感谢!

为什么没有成功。。这个真回答不了,找个熟悉你代码的人帮你看吧。固定链接的设置在 WordPress 设置里有

谢谢博主的回答。
能否问2个和代码没有关的问题?
1.我的2个步骤没有出错吧?
2.除了你上述的步骤,还需要做其他设置吗?

呵呵,不好意思,再请教个非代码问题
是不是要申请Google AJAX Search API key,这些代码才能生效呢?

博主,你的博客文章都写得不错,怎么一直没有再更新了呢?

这个很好用啊

我仔细看了你写的,听着很高深的样子,然后,我试了一下你右上角的那个谷歌搜索,然后,,,然后一直等待。。。我重新刷新了页面,又欢乐个词搜索,然后,,,还是等待,,,

这个不是一般的复杂,我直接把GOOGLE的代码放上去就行了。

前來支持一下~~好多評論哇!! 8D

博主,我想知道,谷歌被墙,自定义搜索还能用吗

不知道,应该不能了吧

大牛,pansou也是用的ajax search,为什么他不会被墙呢,因为他调用的地址是ip,不是直接的谷歌域名。请问怎么实现。


  1. 10年5月17日博客整合Google自定义搜索菜鸟操作步骤 = 飞龙博客 飞龙在天 feilong.org/google-cse-into-blog
  2. 10年8月11日WordPress 整合 Google Ajax 搜索 - 光线部落 raychow.info/2010/wordpress-goo-gle-ajax-search.html
  3. 10年8月20日WordPress优化之Google Ajax搜索 _ BoKeam's Blog www.bokeam.com/wordpress%e4%bc%98%e5%8c%96%e4%b9%8bgoogle-ajax%e6%90%9c%e7%b4%a2/
  4. 11年1月19日整理一下关于在卜卜口の猫窝上使用过的简单技巧v4 - 卜卜口の猫窝 asuka.tk/52691
  5. 11年6月14日Django 开发中使用 Google custom search API - webguo在路上 www.webguo.com/2011/06/14/django_google_custom_search.html
  6. 11年11月30日为主题添加ajax版的谷歌搜索 – 站长交流 - 闲云野鹤夫妻博客 blog.xianyunyehe.net/2419
  7. 12年4月13日【代码】高度定制的Ajax版Google自定义搜索 - 卜卜口の猫窝 mouto.org/53529