打造完美的 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="http://www.google.com/jsapi" type="text/javascript"></script>
<script src="http://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>

参考文献

最新评论

  • the market compare This site is like a classroom, except I don't hate it. lol 人脸标签!体验 Picasa 网络相册新功能
  • Kaylin Pra quem leva a sério esses argumentos desses links, é melhor nunca mais assistir um filme de Holywood. Todos sabem que Disney era conaorvsder para os padrões de lá. 人脸标签!体验 Picasa 网络相册新功能
  • Justice | | | | | inmidderen film izleme sitesi bedava filmler canlı film seyret binlerce filmler online sinema izletir beleÅŸ filmler filmini full izle ücretsiz sinema izleme sitesi filmini izle direk filmler son çıkan filmler vizyondan sonra full sinema izleme sitesi filmleri tam izle indirmeden bedava filim filmler full ve bedava 非常有创意的献血慈善广告
  • Mikel Congratulations on your spicy new name; and the expansion of your services.As a long time patron of ‘Chef Sazon’, I look forward to Roho Kitchen’s future success. Whether it is cooking classes, food and beverage pairing classes,event catering, or pop- up reratusants— I know that Roho Kitchen will always deliver an amazing culinary experience!. Semih Sayginer的开伦表演
  • Charlotte Gee willekirs, that's such a great post! 超牛的flash忍者游戏: N-Game

发表您的评论

您的评论将回复给 原评论者

:D:):O8):(8D;DXD:P:nice::rainbow::cafe::love::cake:

目前有 188 条评论

  

图标比较可爱

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

自己订阅...

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

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

这个够 special 了吧?

机器人 提醒木有情调

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

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

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

然后呢?

你是赤裸裸的嫉妒

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

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

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

哈哈,是啊

鼠标移到代码部分为什么要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

留个名 这个博客做得太好了 :)

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

有意思! :nice:

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

看得有点迷糊!!!!

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

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

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

:)不错。。。

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

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

Just for a test!

不错,学习了...

效果是不错啊

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

真是强人

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

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

谢谢了.是高手呀.

我按照博主的方法,发现只能搜索英文能同步到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的可自定义的内容多了很多

博客更新的不错。支持

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

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

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

测试一下啦 :nice:

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

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

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

准备弄弄

加上去了 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

:nice: :cake:

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

博主 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,不是直接的谷歌域名。请问怎么实现。

Until I found this I thgohut I'd have to spend the day inside.


有 7 篇其他博客的文章引用了本文

  1. 10年5月17日博客整合Google自定义搜索菜鸟操作步骤 = 飞龙博客 飞龙在天
  2. 10年8月11日WordPress 整合 Google Ajax 搜索 - 光线部落
  3. 10年8月20日WordPress优化之Google Ajax搜索 _ BoKeam's Blog
  4. 11年1月19日整理一下关于在卜卜口の猫窝上使用过的简单技巧v4 - 卜卜口の猫窝
  5. 11年6月14日Django 开发中使用 Google custom search API - webguo在路上
  6. 11年11月30日为主题添加ajax版的谷歌搜索 – 站长交流 - 闲云野鹤夫妻博客
  7. 12年4月13日【代码】高度定制的Ajax版Google自定义搜索 - 卜卜口の猫窝