- 前言
- 实现效果
- 实现思路
- Java编码实现
- 其他
1 前言:
注意到不少站点都有这个功能(包括javaeye和pconline)。
就是从百度/谷歌等搜索页面点过来的用户可以看见页面下方有搜索帮助提示,如图:
前一阵子给CTBA也加上了相关功能, 这里大致说说实现方法。
2 实现效果:
百度搜索”扯谈 新闻风”
点击进入CTBA的网站, 页面底部显示提示
3 实现思路:
参考了这篇文章, 利用请求的referer头. 如果乃还不知道referer是什么的话, 点这里
- 从referer头中取得来源页面的地址
- 解析出查询关键词
- 全文检索得出结果
首先必须分析referer, 知道url中哪部分是关键字。例如在baidu输入关键字"扯谈社",在搜索结果中访问你的网站,那么来源的url就是:http://www.baidu.com/s?wd=%B3%B6%CC%B8%C9%E7上面的url中,wd=%B3%B6%CC%B8%C9%E7就是关键字部分,其中%B3%B6%CC%B8%C9%E7是"扯谈社"编码后的字符串, 我们通过UrlDecode解码就可以得到原来用户输入了什么关键字访问了自己的网站, 一般的编程语言都提供了解码工具, Java里的是URLDecoder。
百度对关键字是使用GBK编码,不过有些网站比如谷歌使用的是UTF8编码,需要根据不同情况加以处理。
上面的参考文章列出各个搜索引擎的关键字,但是其实有很多已经是无效的(比如china的已经转为使用google的搜索服务),实际上还有效的列表如下(加上了后来的有道)
名称 | 关键字 | 编码 |
baidu | wd/word | GBK |
sogou | query | GBK |
yahoo | p | UTF-8 |
q | UTF-8 | |
search.msn | q | UTF-8 |
youdao | q/lq | UTF-8 |
search.114.vnet.cn | kw | GBK |
4 Java的编码实现:
贴点代码
(HttpUtils.java)
/**
* 从当前请求得到请求来源
*
* @param request
* @return
*/
public static String getReferer(HttpServletRequest request) {
return request.getHeader("Referer");
}
/**
* #727 针对搜索引擎来源用户的提示
*
* 从某个url里面得到特定参数的值
*
* @param name
* @param url
* @return
*/
public static String getParameterFromUrl(String name, String url) {
if (!url.contains("?")) {
return "";
}
String reval = "";
url = url.substring(url.indexOf("?") + 1);
String[] pairs = url.split("&");
for (String pair : pairs) {
if (pair.contains("=")) {
String pairName = pair.substring(0, pair.indexOf("="));
if (name.equals(pairName)) {
reval = pair.substring(pair.indexOf("=") + 1);
return reval;
}
}
}
return reval;
}
/**
* #727 针对搜索引擎来源用户的提示
*
* 根据url取得搜索关键词
*
* @param refererURL
* request的来源url
* @return
*/
public static String getSearchKeyInRefererURL(String refererURL) {
String searchKey = "";
if (StringUtils.isNotEmpty(refererURL)) {
try {
if (refererURL.contains("baidu.com")) {
// wd/word
searchKey = getParameterFromUrl("wd", refererURL);
if (StringUtils.isEmpty(searchKey)) {
searchKey = getParameterFromUrl("word", refererURL);
}
if (StringUtils.isNotEmpty(searchKey)) {
searchKey = StringUtils.urlDecode(searchKey,
StringUtils.ENCODE_GBK);
}
} else if (refererURL.contains("sogou.com")) {
// query
searchKey = getParameterFromUrl("query", refererURL);
if (StringUtils.isNotEmpty(searchKey)) {
searchKey = StringUtils.urlDecode(searchKey,
StringUtils.ENCODE_GBK);
}
} else if (refererURL.contains("search.114.vnet.cn")) {
// kw
searchKey = getParameterFromUrl("kw", refererURL);
if (StringUtils.isNotEmpty(searchKey)) {
searchKey = StringUtils.urlDecode(searchKey,
StringUtils.ENCODE_GBK);
}
} else if (refererURL.contains("search.msn.com")
|| refererURL.contains("live.com")) {
// q
searchKey = getParameterFromUrl("q", refererURL);
if (StringUtils.isNotEmpty(searchKey)) {
searchKey = StringUtils.urlDecode(searchKey, null);
}
} else if (refererURL.contains("yahoo.com")
|| refererURL.contains("yahoo.cn")) {
// p
searchKey = getParameterFromUrl("p", refererURL);
if (StringUtils.isNotEmpty(searchKey)) {
searchKey = StringUtils.urlDecode(searchKey, null);
}
} else if (refererURL.contains("www.google")) {
// q
searchKey = getParameterFromUrl("q", refererURL);
if (StringUtils.isNotEmpty(searchKey)) {
searchKey = StringUtils.urlDecode(searchKey, null);
}
} else if (refererURL.contains("www.youdao")) {
// q or lq
searchKey = getParameterFromUrl("q", refererURL);
if (StringUtils.isEmpty(searchKey)) {
searchKey = getParameterFromUrl("lq", refererURL);
}
if (StringUtils.isNotEmpty(searchKey)) {
searchKey = StringUtils.urlDecode(searchKey, null);
}
}
} catch (Exception e) {
log.error(e.getMessage());
searchKey = "";
}
}
return searchKey;
}
(SearchEngineHintFilter.java)
在请求过滤器里面取得关键字, 进行搜索:
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) {
…
String refererURL = HttpUtils.getReferer(request);String searchKey = HttpUtils.getSearchKeyInRefererURL(refererURL);
if (StringUtils.isNotEmpty(searchKey)) {
log.debug("Got searchkey: " + searchKey+" |"+HttpUtils.getURL(httpRequest));
httpRequest.setAttribute(WebConstants.REQUEST_SEARCH_KEYWORD,
searchKey);
List<Map<String, String>> refTopics = doSearch(searchKey);
httpRequest.setAttribute(WebConstants.REQUEST_SEARCH_RESULT,
refTopics);
}
…
}doSearch方法里面调用了庖丁分词, 根据关键字全文检索站内文章
5 其他:
提示框的CSS+JS置底 这个详情请mockee来八卦