在做商務(wù)E流量分析的時(shí)候,需要實(shí)現(xiàn)一個(gè)功能:如果訪客是通過(guò)搜索引擎的搜索找到客戶網(wǎng)站的,要統(tǒng)計(jì)出訪客是通過(guò)哪個(gè)搜索引擎訪問(wèn)到頁(yè)面,并且統(tǒng)計(jì)出是通過(guò) 什么關(guān)鍵字搜索到該網(wǎng)站的。在網(wǎng)上google一下,發(fā)出對(duì)這方面的描述文檔還是比較少的,在做這個(gè)功能的過(guò)程中有些經(jīng)驗(yàn)給人家分享一下。
實(shí)現(xiàn)這樣的功能,基本原理是獲取到來(lái)源地址,然后分析其中的內(nèi)容,把所需要的搜索引擎名稱和關(guān)鍵字取出。 獲取來(lái)源地址很簡(jiǎn)單,在servlet 中可以通過(guò)HttpServletRequest.getHeader("Referer")方法取得,jsp頁(yè)面中可以通過(guò) request.getHeader("referer")取得。取得來(lái)源地址后便可以通過(guò)分析得到的來(lái)源地址分析出我們所需要的內(nèi)容。通常我們常用的搜 索引擎有以下14個(gè)。 http://www.google.com; http://www.google.cn; http://www.sogou.com; http://so.163.com; http://www.; http://www.yahoo.com; http://www.baidu.com; http://www.; http://www.soso.com; http://www.; http://www.; http://www.; http://www.; http://www.;
要獲取我們所需要的內(nèi)容,我們必須分析 各個(gè)引擎的特性,由于各個(gè)搜索引擎的格式不一樣,獲取到的來(lái)源地址必然也不一致,下面我們來(lái)分析一下各種搜索引擎的地址格式。
在搜索引擎里輸入關(guān)鍵字,點(diǎn)擊搜索之后地址欄中的內(nèi)容就是我們通過(guò)HttpServletRequest.getHeader("Referer")或 request.getHeader("referer")取得的來(lái)源地址。
google搜索引擎: http://www.google.com/search?hl= zh-N&newwindow=1& q=%E4%BB%8A%E7%A7%91%E4%BF%A1%E6%81%AF%E7%A7%91%E6%8A%80& btnG= %E6%90%9C%E7%B4%A2&lr=
http://www.google.cn/search?hl= zh-N&newwindow=1& q=%E6%B0%B8%E5%AE%89%E8%B7%AF%E7%81%AF& btnG= %E6%90%9C%E7%B4%A2&meta=
從這里我們可以得到我們所需要的搜索引擎名稱和關(guān)鍵字。其中,搜索引擎顯而易見(jiàn),是google;而關(guān)鍵字呢?經(jīng)過(guò)我仔細(xì)觀察、 測(cè)試后發(fā)現(xiàn)關(guān)鍵字是編碼后放 在參數(shù)q里,也就是說(shuō) %E4%BB%8A%E7%A7%91%E4%BF%A1%E6%81%AF%E7%A7%91%E6%8A%80和 %E6%B0 %B8%E5%AE%89%E8%B7%AF%E7%81%AF 就是輸入的關(guān)鍵字。
(有人會(huì)問(wèn),那btnG這個(gè)參數(shù)的值是什么來(lái)頭,他也編過(guò)碼 啊?是用來(lái)干嘛的呢?呵呵,它什么來(lái)頭都沒(méi)有,什么也沒(méi)干,多余的!你試試輸入關(guān)鍵字之后點(diǎn)擊搜索按鈕看看地址欄,然后再試試輸入關(guān)鍵字之后回車,再看看 地址欄,看出兩種做法在地址欄中的一點(diǎn)點(diǎn)差別之后你就會(huì)明白的啦)
baidu搜索引擎: (1)http://www.baidu.com/s?ie=gb2312&bs=%CB%B3%B5%C2%BC%D2%BE%DF&sr=&z=&cl=3&f=8& wd=%BD%F1%BF%C6%BF%C6%BC%BC&ct=0 (2)http://www.baidu.com/baidu?tn=nanlingcb&word=%CB%B3%B5%C2%BC%D2%BE%DF
baidu 搜索引擎,這里需要說(shuō)明一下,當(dāng)我們?cè)谕ㄟ^(guò)在http://www.baidu.com中 輸入搜索關(guān)鍵字,獲取的來(lái)源地址為(1)字符串;當(dāng)通過(guò)其它方式,比如在一些瀏覽器插件中輸入關(guān)鍵字搜索的獲取的來(lái)源地址為(2)字符串。通過(guò)獲取來(lái)的這來(lái)源地,我也可以很容易的知道當(dāng)前的搜索引擎是baidu;而關(guān)鍵字呢?看看(1),這里有兩個(gè)經(jīng)過(guò)編碼的字符串,到底哪個(gè)是關(guān)鍵字呢?wd的值是關(guān)鍵字!信我啦!那bs的值是什么呢?你輸入關(guān)鍵字多搜索幾次,看看你有什么發(fā)現(xiàn)?發(fā)現(xiàn)了吧,bs是你上一次搜索的關(guān)鍵字!這個(gè)我們不管,它不是我們所要的東 西。分析得知,在baidu搜索引擎里有兩個(gè)地方放關(guān)鍵字,一個(gè)地方是編碼后放在在參數(shù)wd里,另外一個(gè)地方是編碼后放在word參數(shù)里。明白了吧?:)
sogou搜索引擎 http://www.sogou.com/web?query=%BD%F1%BF%C6%D0%C5%CF%A2%BF%C6%BC%BC 這個(gè)就沒(méi)這么復(fù)雜了,我們通過(guò)字符串可以知道搜索引擎為sogou,關(guān)鍵字經(jīng)編碼后放在參數(shù)query里,這里值為 %BD%F1%BF%C6%D0%C5 %CF%A2%BF%C6%BC%BC,有時(shí)候也會(huì)附帶多一些參數(shù),但附帶的這些參數(shù)對(duì)我們來(lái)說(shuō)是沒(méi)用的。
163搜索引擎 http://cha.so.163.com/so.php?in=seek&c=26&key=032152284&q=%BD%F1%BF%C6%D0%C5%CF%A2%BF%C6%BC%BC &x=61&y=19 這個(gè)也不復(fù)雜,分析得知,搜索引擎名稱為163,關(guān)鍵字在參數(shù)q里,這里值為%BD%F1%BF%C6%D0%C5%CF%A2%BF%C6%BC%BC
yahoo 搜索引擎 http://search.cn.yahoo.com/search?p=%D3%C0%B0%B2%C2%B7%B5%C6& source=toolbar_yassist_button&pid=58061_1006&ei=gbk
http://search.cn.yahoo.com/search?lp=%E4%B8%AD%E5%B1%B1%E5%8F%A4%E9%95%87%E7%81%AF%E9%A5%B0& p=%E4%BB%8A%E7%A7%91%E4%BF%A1%E6%81%AF%E7%A7%91%E6%8A%80&pid=&ei=UTF-8 很容易得到,搜索引擎名稱為yahoo,那關(guān)鍵字是哪些呢?關(guān)鍵字是放在參數(shù)p里,而參數(shù)lp的值跟baidu類似,也是上一次搜索的關(guān)鍵字。
lycos 搜索引擎 http://search./?query=website 這 個(gè)我們用得比較少,同樣我們通過(guò)這個(gè)字符串得出搜索引擎為lycos,關(guān)鍵字放在query里.
3721搜索引擎 http://seek./index.htm?name=%D6%E9%BA%A3%CF%E3%D6%DE%C0%CD%CE%F1%CA%D0%B3%A1 容 易得到,搜索引擎名稱為3721,關(guān)鍵字放在name里
search搜索引擎 http://www./search?lq=d%25E4%25B8%25AD%25E5%259B%25BDd& q=%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%9B%BD%E5%92%8C 這 個(gè)我們用得很少,也容易得到搜索引擎名稱為search,關(guān)鍵字放在p里,而lp放的是什么呢?尚未弄清楚, 反正與我們所要的東西無(wú)關(guān)。
soso 搜索引擎 http://www.soso.com/q?w=%BD%F1%BF%C6%D0%C5%CF%A2%BF%C6%BC%BC12&sc=web& bs=%BD%F1%BF%C6%D0%C5%CF%A2%BF%C6%BC%BC1&ch=w.soso.pr&uin=&lr=chs&web_options=on 可 以看出搜索引擎名稱為soso,關(guān)鍵字放在參數(shù)w里,需參數(shù)bs的值跟baidu相似,是上一次搜索的關(guān)鍵字
zhongsou搜索引擎 http://p./p?w=%BD%F1%BF%C6%D0%C5%CF%A2%BF%C6%BC%BC&l=&jk=&k=&r=&aid=&pt=1&dt=2 可 以看出搜索引擎名稱為zhongsou,關(guān)鍵字在參數(shù)w里。
alexa搜索引擎 http://www./search?q=%E4%BB%8A%E7%A7%91%E4%BF%A1%E6%81%AF%E7%A7%91%E6%8A%80 得出搜索引擎名稱為zhongsou,關(guān)鍵字放在參數(shù)q里。
對(duì)各種搜索引擎的url的分析已完成,大家都對(duì)這些常用的搜索引擎的url的格式有所了解了,下面我們看看怎樣從我們所取得的這些字符串中得到我們所要的信息,也就是怎樣從這些字符串中提取我們所需的搜索引擎名稱和搜索關(guān)鍵字.這里理所當(dāng)然使用功能強(qiáng)大的正則表達(dá)式了.好,現(xiàn)在我們逐個(gè)逐個(gè)地分析各個(gè)搜索引擎用什么正則表達(dá)式提取我們所需要的內(nèi)容. 首先還是先分析 google搜索引擎: 上面已經(jīng)提到我們?nèi)〉玫膅oogle搜索引擎的地址是這樣的: http://www.google.com/search?hl= zh-N&newwindow=1 &q=%E4%BB%8A%E7%A7%91%E4%BF%A1%E6%81%AF%E7%A7%91%E6%8A%80& btnG= %E6%90%9C%E7%B4%A2&lr=
http://www.google.cn/search?hl= zh-N&newwindow=1 &q=%E6%B0%B8%E5%AE%89%E8%B7%AF%E7%81%AF& btnG= %E6%90%9C%E7%B4%A2&meta=
其 實(shí)它還有一種形式是這樣的: (3)http://www.google.com/custom?hl=zh-CN&inlang=zh-CN&ie=GB2312&oe=GB2312&newwindow=1& client=pub3261928361684765&cof=FORID%3A1%3BGL%3A1%3BBGC%3AFFFFFF%3BT%3A%23000000%3BLC%3A %230000ff%3BVLC%3A%23663399%3BALC%3A%230000ff%3BGALT%3A%23008000%3BGFNT%3A %230000ff%3BGIMP%3A%230000ff%3BDIV%3A%23336699%3BLBGC%3A336699%3BAH%3Acenter%3B &q=%C5%B7%C2%FC%D5%D5%C3%F7&lr= OH,my god,是不是看得頭暈了?先不要暈,往下看你就不會(huì)覺(jué)得暈的啦....
我們仔細(xì)觀察一下,這三種格式都有一個(gè)共通點(diǎn),大家有沒(méi)有發(fā)現(xiàn)呢?就是 他的格式都是這樣的:
http://www.google.[...]/[...]&q= [關(guān)鍵字][...] [...]表示有一個(gè)以上的字符.
就如(2)我們?cè)诶锩娣湃胍恍]就可以看得更清楚了: http://www.google.[cn]/[search?hl=zh-CN&newwindow=1] &q=[%E6%B0%B8%E5%AE%89%E8%B7%AF%E7%81%AF][&btnG=%E6%90%9C%E7%B4%A2&meta=] 看明白了吧?看明白了我們就接下去了.于是我們可以得出google搜索引擎的正則表達(dá)式了:
http:\\/\\/www\\.google \\.[a-zA-Z]+\\/.+[\\&\\?]q=[^\\&]*。
現(xiàn)在解釋一下這個(gè)正則表達(dá)式的意思。 http:\\/ \\/www\\.這一段是匹配http://www.,為什么這里多了這么多\呢?因?yàn)樽址?'/'和字符'.'在正則表達(dá)式中有特殊意義,要用'\'對(duì)這兩個(gè)字符轉(zhuǎn)義,'/'通過(guò)'\/'轉(zhuǎn)義,相似的.也通過(guò)'\.'轉(zhuǎn)義,而字符'\'在 java里也是一個(gè)特殊字符,本身也需要轉(zhuǎn)義,所以'\/'寫成'\\/',類似的'\.'寫成'\\.';
接下來(lái)google\\.[a-zA-Z]+ \\/.+匹配google.com/search?hl=zh-CN&newwindow=1,這里解釋一下[a-zA-Z]+,意思是最少有 一個(gè)(包括一個(gè))以上英文字母,[a-zA-Z]表示從a到z,從A到Z的字符,+表示至少一個(gè)以上,[\\&\\?]q=[^\\&]*匹配的是&q=%E6%B0%B8%E5%AE%89%E8%B7%AF%E7%81%AF,[\\&\\?],表示字符&或字符?由于&和?都是特殊字符,所以都要用轉(zhuǎn)義符轉(zhuǎn)義,q=[^\\&]*表示q=后面是零個(gè)(包括零個(gè))以上的非& 字符,[^\\&]表示不為&的字符,為什么不為&呢,因?yàn)?amp;后面的字符也經(jīng)不再屬于參數(shù)q的值了,我們要取的是q=之 后,字符&之前的字符串.這個(gè)正則表達(dá)式的解釋就到此了?,F(xiàn)在這個(gè)正則表達(dá)式已經(jīng)可以從眾多的獲取過(guò)來(lái)的來(lái)源地址中分辯出哪些是google搜索引擎了,但是有一個(gè)問(wèn)題,假如以后google搜索引擎不是這樣,換成http://search.google.com/search?hl=zh-CN&newwindow=1&q=%E6%B0%B8%E5%AE%89%E8%B7%AF%E7%81%AF &btnG=%E6%90%9C%E7%B4%A2&meta= 呢,
那這個(gè)正則表達(dá)式就不合適了,怎樣能在以后改動(dòng)之后我們寫的正則表達(dá)式還適用呢?很簡(jiǎn)單,我們把它改成這個(gè)樣子:\\.google\\.[a- zA-Z]+\\/.+[\\&\\?]q=[^\\&]*,意思是我們不必匹配http://www這 一串字符串。這樣如果google搜索引擎做了類似http://search.google.com/..... 的修改,我們寫的正則表達(dá)式也適用了,那假如它把域名也改了就沒(méi)得說(shuō)了,:);還有一種情況,在地址欄里輸入www.google.com:80/也可以正常訪問(wèn)google,也就是說(shuō)還有 一種情況就是加端口的訪問(wèn),這種情況也要考慮到,因此之前我們的正則表達(dá)式應(yīng)改成:\\.google\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]q=[^\\&]*, (:\\d{1,}){0,1}是什么意思呢?他匹配類似":80"也就是說(shuō)冒號(hào)(:)后跟1個(gè)以上的數(shù)字字符,而端口是可選的,并且如果出現(xiàn)只會(huì)出現(xiàn)一 次,所以用{0,1}.這個(gè)正則表達(dá)式的用途是用于獲取關(guān)鍵字,所以這里我把關(guān)鍵字部分劃分為一個(gè)組(這在下面會(huì)用到),因此,最終的正則表達(dá)式為:
\\.google\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]q=([^\\&]*)
對(duì) google搜索引擎已經(jīng)說(shuō)得很詳細(xì),接下來(lái)的我就簡(jiǎn)略的說(shuō)說(shuō)了,原理都差不多的了。
baidu搜索引擎: 分 析得知baidu搜索引擎的正則表達(dá)式為: \\.baidu\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]wd=([^\\&]*) 或 \\.baidu\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]word=([^\\&]*)
sogou 搜索引擎 http://www.sogou.com/web?query=%BD%F1%BF%C6%D0%C5%CF%A2%BF%C6%BC%BC 正 則表達(dá)式: \\.sogou\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]query=([^\\&]*)
yahoo搜索引擎 正 則表達(dá)式: \\.yahoo\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]p=([^\\&]*)
lycos 搜索引擎 http://search./?query=website 正 則表達(dá)式: \\.lycos\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.*[\\&\\?]query=([^\\&]*)
3721 搜索引擎 http://seek./index.htm?name=%D6%E9%BA%A3%CF%E3%D6%DE%C0%CD%CE%F1%CA%D0%B3%A1 http://seek./index.htm?q=%D6%E9%BA%A3%CF%E3%D6%DE%C0%CD%CE%F1%CA%D0%B3%A1 正 則表達(dá)式: \\.3721\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]p=([^\\&]*) 或 \\.3721\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]name=([^\\&]*)
search 搜索引擎 正則表達(dá)式: \\.search\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]q=([^\\&]*)
soso搜索引擎 正 則表達(dá)式: \\.soso\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]w=([^\\&]*)
zhongsou搜索引擎 http://p./p?w=%BD%F1%BF%C6%D0%C5%CF%A2%BF%C6%BC%BC&l=&jk=&k=&r=&aid=&pt=1&dt=2 正 則表達(dá)式: \\.zhongsou\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]w=([^\\&]*)
alexa搜索引擎 http://www./search?q=%E4%BB%8A%E7%A7%91%E4%BF%A1%E6%81%AF%E7%A7%91%E6%8A%80 正 則表達(dá)式: \\.alexa\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]q=([^\\&]*)
iask搜索引擎 正則表達(dá)式: \\.iask\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]k=([^\\&]*) 或 \\.iask\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]_searchkey=([^\\&]*)
好了,正則表達(dá)式已經(jīng)寫出來(lái)了,事情已經(jīng)完成一半了?,F(xiàn)在我們把話題轉(zhuǎn)一下,等會(huì)我們?cè)俎D(zhuǎn)回來(lái),現(xiàn)在我們先看看如何獲取搜索引擎的名稱。同樣,也 需要用正則表達(dá)式,正則表達(dá)式實(shí)在太強(qiáng)了:)。 我們可以通過(guò)以下的正則表達(dá)式匹配到google搜索引擎: http:\\/\\/.* \\.google\\.com(:\\d{1,}){0,1}\\/或 http:\\/\\/.*\\.google\\.cn(:\\d{1,}){0,1}\\/
類 似的也可以匹配其它搜索引擎,我把他們寫在一起: http:\\/\\/.*\\.(google\\.com(:\\d{1,}){0,1}\\/|google\\.cn(:\\d{1,}){0,1}\\/| baidu\\.com(:\\d{1,}){0,1}\\/|yahoo\\.com(:\\d{1,}){0,1}\\/| iask\\.com(:\\d{1,}){0,1}\\/|sogou\\.com(:\\d{1,}){0,1}\\/| 163\\.com(:\\d{1,}){0,1}\\/|lycos\\.com(:\\d{1,}){0,1}\\/| aol\\.com(:\\d{1,}){0,1}\\/|3721\\.com(:\\d{1,}){0,1}\\/| search\\.com(:\\d{1,}){0,1}\\/|soso.com(:\\d{1,}){0,1}\\/| zhongsou\\.com(:\\d{1,}){0,1}\\/|alexa\\.com(:\\d{1,}){0,1}\\/) 通過(guò)以下程序可以獲取到搜索引擎的名稱:
import java.util.regex.*;
public class GetEngine
{
public static void main(String[] arg)
{
GetEngine engine=new GetEngine();
String referer="http://www.baidu.com/s?wd=java%D1%A7%CF%B0%CA%D2";
String engineName=engine.getSearchEngine(referer);
System.out.println("搜索引擎名稱:"+engineName);
}
public String getSearchEngine(String refUrl) {
if(refUrl.length()>11)
{
//p是匹配各種搜索引擎的正則表達(dá)式
Pattern p = Pattern.compile("http:\\/\\/.*\\.(google\\.com(:\\d{1,}){0,1}\\/|
google\\.cn(:\\d{1,}){0,1}\\/|baidu\\.com(:\\d{1,}){0,1}\\/|
yahoo\\.com(:\\d{1,}){0,1}\\/|iask\\.com(:\\d{1,}){0,1}\\/|
sogou\\.com(:\\d{1,}){0,1}\\/|163\\.com(:\\d{1,}){0,1}\\/|
lycos\\.com(:\\d{1,}){0,1}\\/|aol\\.com(:\\d{1,}){0,1}\\/|
3721\\.com(:\\d{1,}){0,1}\\/|search\\.com(:\\d{1,}){0,1}\\/|
soso.com(:\\d{1,}){0,1}\\/|zhongsou\\.com(:\\d{1,}){0,1}\\/|
alexa\\.com(:\\d{1,}){0,1}\\/)");
Matcher m = p.matcher(refUrl);
if (m.find())//如果來(lái)源地址可以匹配以上的pattern
{
//因?yàn)閙.group(0)是域名,m.group(1)才是我們最合適我們所要的
return insteadCode(m.group(1),"(\\.com(:\\d{1,}){0,1}\\/|\\.cn(:\\d{1,}){0,1}\\/|
\\.org(:\\d{1,}){0,1}\\/)","");//把.com,.cn,.org替換為""
}
}
return "未發(fā)現(xiàn)搜索引擎";
}
public String insteadCode(String str,String regEx,String code){
Pattern p=Pattern.compile(regEx);
Matcher m=p.matcher(str);
String s=m.replaceAll(code);
return s;
}
}
通過(guò)以上的代碼即可得出搜索引擎名稱了,似乎任務(wù)完成一大半了。只是接著下來(lái)的要做的事情比之前所做的要麻煩點(diǎn)點(diǎn),麻煩就麻煩在編碼上。 現(xiàn)在我樣回過(guò)頭看我們上面寫的一大堆各種搜索引擎的正則表達(dá)式。 由于這里要大量的字符串操作,這里使用StringBuffer來(lái)做字符串的連接。 StringBuffer sb=new StringBuffer(); sb.append("\\.google\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]q=([^\\&]*)") .append("|\\.iask\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]k=([^\\&]*)") .append("|\\.iask\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]_searchkey=([^\\&]*)") .append("|\\.sogou\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]query=([^\\&]*)") .append("|\\.163\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]q=([^\\&]*)") .append("|\\.yahoo\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]p=([^\\&]*)") .append("|\\.baidu\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]wd=([^\\&]*)") .append("|\\.baidu\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]word=([^\\&]*)") .append("|\\.lycos\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.*[\\&\\?]query=([^\\&]*)") .append("|\\.aol\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]encquery=([^\\&]*)") .append("|\\.3721\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]p=([^\\&]*)") .append("|\\.3721\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]name=([^\\&]*)") .append("|\\.search\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]q=([^\\&]*)") .append("|\\.soso\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]w=([^\\&]*)") .append("|\\.zhongsou\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]w=([^\\&]*)") .append("|\\.alexa\\.[a-zA-Z]+(:\\d{1,}){0,1}\\/.+[\\&\\?]q=([^\\&]*)");
這個(gè)正則表達(dá)式是把所有搜索引擎用或"|"連接起來(lái),因?yàn)橹灰ヅ淦渲幸粋€(gè)搜索引擎的正則表達(dá)式就可以。 前面已經(jīng)說(shuō)到,關(guān)鍵字是經(jīng)過(guò)編碼 的,我們直接取出的關(guān)鍵字會(huì)像%BD%F1%BF%C6%D0%C5%CF%A2%BF%C6%BC%BC12, 這樣的關(guān)鍵字我們無(wú)法讀懂,因些需要對(duì)這 些關(guān)鍵進(jìn)行反編碼,這要用到j(luò)ava.net.URLDecoder.decode(String s,String enc),這個(gè)方法有兩個(gè)參數(shù),一個(gè)參數(shù)是要進(jìn)行反編碼的字符串,另一個(gè)是指定的字符集。第一個(gè)參數(shù)很簡(jiǎn)單,只要我們把取得的關(guān)鍵放到這個(gè)參數(shù)里,至于第 二個(gè)參數(shù)怎樣呢?這里我只討論中文的情況,這些搜索引擎有兩種字符集編碼方式,一種是UTF-8,另外一種是GBK。 只有GBK一種編碼方式的搜 索引擎: 3721,iask,sogou,163,baidu,soso,zhongsou 只有UTF-8一種編碼方式的搜索引擎: lycos,aol,search,alexa 有 兩種編碼方式的: google,yahoo
只有一種編碼方式的問(wèn)題容易解決,有兩種編碼方式的怎辦呢?辦法總比問(wèn)題多,其實(shí)采用哪一個(gè)編碼方工,它是有”暗示“的,對(duì)于google,大多數(shù)情況下它是采用UTF-8的編碼方式,我們?cè)跒g覽器的地址欄上輸入www.google.com搜索的都是以這種方式來(lái)編碼的,但有種情況如: http://www.google.com/custom?hl=zh-CN&inlang=zh-CN&ie=GB2312&oe=GB2312&newwindow=1&client=pub-3261928361684765& cof=FORID%3A1%3BGL%3A1%3BBGC%3AFFFFFF%3BT%3A%23000000%3BLC%3A%230000ff %3BVLC%3A%23663399%3BALC%3A%230000ff%3BGALT%3A%23008000%3BGFNT%3A%230000ff%3BGIMP%3A %230000ff%3BDIV%3A%23336699%3BLBGC%3A336699%3BAH%3Acenter%3B&q=%C5%B7%C2%FC%D5%D5%C3%F7&lr=
這種情況下就不一定是UTF-8編碼了,這種情況下以ie這個(gè)參數(shù)指定,這里ie=gb2312,所以編碼方式為gb2312,而gb2312是gbk的字 集,所以這里我們用gbk而不用gb2312;對(duì)于yahoo情況類似,只不過(guò)yahoo在大多數(shù)情況下使用GBK編碼,如: http://search.cn.yahoo.com/search?p=%C5%B7%C2%FC%BF%C6%BC%BC%CA%B5%D2%B5 &source=toolbar_yassist_button&pid=54554_1006&f=A279_1 就是GBK編碼,但這種情況: http://search.cn.yahoo.com/search?ei=gbk&fr=fp-tab-web-ycn&source=errhint_up_web &p=%BD%F1%BF%C6&meta=vl%3Dlang_zh-CN%26vl%3Dlang_zh-TW&pid=ysearch 就 用ei參數(shù)里指定的紡碼方式了,這里有可能指定的是gbk,也有可能指定的是UTF-8。 根據(jù)以上的解釋,于是有以下的程序來(lái)獲得各種搜索引擎的關(guān)鍵字:
import java.util.regex.*;
import java.sql.*;
import java.net.URLDecoder;
import java.io.*;
public class GetKeyword
{
public static void main(String[] arg)
{
String referer="http://www.baidu.com/s?wd=java%D1%A7%CF%B0%CA%D2";
if(arg.length!=0)
{
referer=arg[0];
}
GetKeyword getKeyword=new GetKeyword();
String searchEngine=getKeyword.getSearchEngine(referer);
System.out.println("searchEngine:"+searchEngine);
System.out.println("keyword:"+getKeyword.getKeyword(referer));
}
public String getKeyword(String refererUrl)
{
StringBuffer sb=new StringBuffer();
if(refererUrl!=null)
{
sb.append("(google\\.[a-zA-Z]+/.+[\\&|\\?]q=([^\\&]*)")
.append("|iask\\.[a-zA-Z]+/.+[\\&|\\?]k=([^\\&]*)")
.append("|iask\\.[a-zA-Z]+/.+[\\&|\\?]_searchkey=([^\\&]*)")
.append("|sogou\\.[a-zA-Z]+/.+[\\&|\\?]query=([^\\&]*)")
.append("|163\\.[a-zA-Z]+/.+[\\&|\\?]q=([^\\&]*)")
.append("|yahoo\\.[a-zA-Z]+/.+[\\&|\\?]p=([^\\&]*)")
.append("|baidu\\.[a-zA-Z]+/.+[\\&|\\?]wd=([^\\&]*)")
.append("|baidu\\.[a-zA-Z]+/.+[\\&|\\?]word=([^\\&]*)")
.append("|lycos\\.[a-zA-Z]+/.*[\\&|\\?]query=([^\\&]*)")
.append("|aol\\.[a-zA-Z]+/.+[\\&|\\?]encquery=([^\\&]*)")
.append("|3721\\.[a-zA-Z]+/.+[\\&|\\?]p=([^\\&]*)")
.append("|3721\\.[a-zA-Z]+/.+[\\&|\\?]name=([^\\&]*)")
.append("|search\\.[a-zA-Z]+/.+[\\&|\\?]q=([^\\&]*)")
.append("|soso\\.[a-zA-Z]+/.+[\\&|\\?]w=([^\\&]*)")
.append("|zhongsou\\.[a-zA-Z]+/.+[\\&|\\?]w=([^\\&]*)")
.append("|alexa\\.[a-zA-Z]+/.+[\\&|\\?]q=([^\\&]*)")
.append(")");
Pattern p = Pattern.compile(sb.toString());
Matcher m = p.matcher(refererUrl);
return decoderKeyword(m,refererUrl);
}
return null;
}
public String decoderKeyword(Matcher m,String refererUrl)
{
String keyword=null;
String encode="UTF-8";
String searchEngine=getSearchEngine(refererUrl);
if(searchEngine!=null)
{
if ((checkCode("3721|iask|sogou|163|baidu|soso|zhongsou",searchEngine)
||(checkCode("yahoo",searchEngine)&&!checkCode("ei=utf-8",refererUrl.toLowerCase()))))
{
encode = "GBK";
}
if (m.find())
{
for (int i = 2; i <= m.groupCount(); i++)
{
if (m.group(i) != null)//在這里對(duì)關(guān)鍵字分組就用到了
{
try
{
keyword = URLDecoder.decode(m.group(i), encode);
}
catch(UnsupportedEncodingException e)
{
System.out.println(e.getMessage());
}
break;
}
}
}
}
return keyword;
}
public String getSearchEngine(String refUrl) {
if(refUrl.length()>11)
{
//p是匹配各種搜索引擎的正則表達(dá)式
Pattern p =
Pattern.compile("http:\\/\\/.*\\.(google\\.com(:\\d{1,}){0,1}\\/|
google\\.cn(:\\d{1,}){0,1}\\/|baidu\\.com(:\\d{1,}){0,1}\\/|
yahoo\\.com(:\\d{1,}){0,1}\\/|iask\\.com(:\\d{1,}){0,1}\\/|
sogou\\.com(:\\d{1,}){0,1}\\/|163\\.com(:\\d{1,}){0,1}\\/|
lycos\\.com(:\\d{1,}){0,1}\\/|aol\\.com(:\\d{1,}){0,1}\\/|
3721\\.com(:\\d{1,}){0,1}\\/|search\\.com(:\\d{1,}){0,1}\\/|
soso.com(:\\d{1,}){0,1}\\/|zhongsou\\.com(:\\d{1,}){0,1}\\/|
alexa\\.com(:\\d{1,}){0,1}\\/)");
Matcher m = p.matcher(refUrl);
if (m.find())
{
return insteadCode(m.group(1),
"(\\.com(:\\d{1,}){0,1}\\/|\\.cn(:\\d{1,}){0,1}\\/|\\.org(:\\d{1,}){0,1}\\/)","");
}
}
return "未發(fā)現(xiàn)有搜索引擎";
}
public String insteadCode(String str,String regEx,String code){
Pattern p=Pattern.compile(regEx);
Matcher m=p.matcher(str);
String s=m.replaceAll(code);
return s;
}
public boolean checkCode(String regEx,String str){
Pattern p=Pattern.compile(regEx);
Matcher m=p.matcher(str);
return m.find();
}
}
|