- 前言
- 實現效果
- 實現思路
- 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來八卦