現在大多數提供網站排名的網站,其資料都是取自于 Alexa 釋出的資料。但是 Alexa 的網站排名資料并不能簡單、直接地得到,這是因為 Alexa 使用了幹擾碼技術,使得程式設計變得困難和繁瑣。
但是從理論上講,隻要能在頁面上看到的資訊,除過圖檔識别現在還是個頂尖技術以外,文字資訊都可能通過抓取頁面得到源檔案,再進行分析而得到具體的資料。
我們先分析一下“電腦學習網” http://www.why100000.com 在 http://www.alexa.com 查詢排名時得到的資料:在 http://www.alexa.com 頁面輸入網址 http://www.why100000.com,點選按鈕“Get traffic Detail”。頁面下載下傳完畢後,檢視源檔案,搜尋字元串“traffic rank”(搜尋“Why100000.com has a traffic rank”可能找不到,因為單詞之間有多個空格,無法比對),找到排名資料的附近,往後看,可以看到以下類似的字元串:
<!–Did you know? Alexa offers this data programmatically. Visit http://aws.amazon.com/awis for more information about the Alexa Web Information Service.–><span class=”ca53″>61</span>5<span class=”c34d”>57</span>,<span class=”c8a7″>78</span><span class=”c1db”>35</span>4</span><!– google_ad_section_end(name=default) –>
之是以強調“類似”,是因為每次看到的資訊一般都不完全相同,Alexa說了,是“programmatically”産生的這些資料,已經通過程式設計對真實資料進行了幹擾,雖然在頁面上眼睛看到的是數字字串“557354”,但是即使在頁面上“選擇-複制-粘貼”,得到的卻是字元串“61557,78354”(每次重新查詢後差不多都是不相同的)。從上面的代碼中也可以看到“61557,78354”的資訊。
但是,如果仔細觀察,就會看到,真正的排名資料“557354”是包含在“61557,78354”字元串中的,而實際上,它 “總是”包含在這個變化的字元串中的,多試幾次就會看到!多試幾次還會看到,真正的排名字元有時沒有包含在<span class=”xxxx”>61</span>中,這讓我們想到,幹擾字元是通過包含在<span class=”xxxx”>……</span>中,使用class引用樣式表“xxxx”來使其在頁面隐含的。但是,有時排名真實資料的數字也包含在<span class=”yyyy”>……</span>中,那麼該樣式表應該不設定該字元(串)隐含。–這就是幹擾算法的思想:在真實資料中插入頁面上看不到的數字,不影響人眼觀看,但對程式分析造成幹擾,而且對部分可見字元有的也加上<span>…</span>标簽,更進一步增加了程式分析的複雜度。
但是,既然浏覽器看到了資訊,其秘密應該就包含在源檔案之中,而且一般和 Javascript、CSS 引用都可能有關系。按照這個思路,我們把源檔案相關的Javascript 腳本、CSS 腳本都下載下傳下來進行分析。
而秘密其實就包含在 http://client.alexa.com/common/css/scramble.css 樣式表檔案中。打開該檔案,可以看到以下 189 個 CSS 類的定義:
.c11e {
display: none
}
.c125 {
.c12d {
……
.cfe9 {
混淆字元串中以<span class=”xxxx”>……<span>包含的“xxxx”都是在這裡定義的!真實字元<span class=”yyyy”>……<span>的樣式yyyy可能是随機産生的,但肯定不會和這189個定義相同。
到此真相大白。我們可以通過編寫程式來獲得該真實排名資料了。
我們可以編寫桌面程式,比如用 Delphi、C# 等編寫Windows桌面程式,這個需要用到 Internet Browser 元件,來擷取
http://www.alexa.com/data/details/traffic_details/why100000.com
的頁面源檔案,然後進行分析,最終儲存到資料庫中。
也可以在網頁中通過Javascript腳本操作頁面文檔來擷取該資料。這個需要對javascript很熟悉。但要把資料儲存到背景資料庫中,一般需要手工打開頁面來操作。
也可以通過網站背景程式設計來實作,需要背景程式設計語言有背景擷取網頁源檔案的能力,這個用Java、ASP.NET、PHP等語言都能實作。
以上所有程式設計過程,都需要程式設計語言或腳本有很強的字元串分析和處理能力,常見的就是使用正規表達式,一般流行的語言都支援。
我選用現在很流行的 Web 程式設計語言 PHP 來實作。
程式設計過程簡述:
觀察源檔案,發現段落:
<!–Did you know? Alexa offers this data programmatically. Visit http://aws.amazon.com/awis for more information about the Alexa Web Information Service.–>
在源檔案中是第一次出現的。排名資訊就包含在它與
<!– google_ad_section_end(name=default) –>
之間。這為程式設計提供了便利。我們可以根據這個特征首先把最有用的資訊挖出來,以縮小範圍,為精細程式設計提供基礎。這個是用getBody()函數實作的,實際采用的特征字元串是“Information Service.–>”和“<!– google_ad_section_end(name=default) –>”,抽取它們之間的字元串即可。
getAlexaRank是主函數。其他函數通過擷取<span class=”zzzz”>……<span>中的樣式表“zzzz”并存入數組,通過對數組的周遊,判斷核心資料塊内在數字(串)是該删除還是保留,最終産生出真實的資料。程式中充分發揮了PHP正規表達式和字元串處理函數的極大威力,使其比ASP等腳本代碼短得多。
在Alexa查詢結果中還有其他大量的資料可能也用得到,也可以通過本程式設計思想來設計和編寫程式代碼。比如抽取通路某站點的全球使用者的比例,一周内的平均值,可以參考以下部位的代碼:
Percent of global Internet users who visit this site
<td><!–Did you know? Alexa offers this data programmatically.
Visit http://aws.amazon.com/awis for more information about the Alexa Web Information Service.–>
<span class=”cded”>10</span>0<span class=”cd83″>.0</span>00<span class=”cd81″>18</span>%
</td>
方法還是尋找段落特征,取出<span>部分的精細資訊,再進行深入分析得到資料。
用該文的方法也可以編寫網頁資訊采集程式,包括新聞、部落格等等網際網路上的大量文章。
但是,如果Alexa下次再修改算法,該方法就會失效了。
附件:
Index.php檔案:
<form name=”alexaform” method=”post” action=”get_alexa.php”>
輸入網址:<input type=”text” name=”url” value=”http://www.why100000.com” size=40>
<input type=”submit” value=”查 詢”>
</form>
get_alexa.php檔案:
<?php
//PHP版本要求:PHP 4.4.7
//支援原創,請保留該處注釋:
//作者:張慶(網眼)陝西-西安
//網站位址:
//電腦學習網:http://www.why100000.com
//《部落格》:http://blog.why100000.com
//《問吧!》http://ask.why100000.com
//示範位址:http://www.why100000.com/test/alexa
//代碼下載下傳位址:http://www.why100000.com/test /alexa/alexa.rar
$url = $_POST[’url’];
if($url!=”")
{
echo “您的網站 “. $url .” 在 ALEXA 的排名為:<br>”;
$rank = getAlexaRank($url);
echo ‘[’ . $rank .’]';
}
function getAlexaRank($weburl)
$weburl = strtolower($weburl);
$tempurl = getDomainUrl($weburl);
//讀取http://client.alexa.com/common/css/scramble.css中的資料
$strAlexaCss = file_get_contents(’http://client.alexa.com/common/css/scramble.css’);
$alexaRankQueryUrl = ‘http://www.alexa.com/data/details/traffic_details/’ . $tempurl;
$strAlexaContent = file_get_contents($alexaRankQueryUrl);
$rankContent = getBody($strAlexaContent, ‘Information Service.–>’, ‘<!– google_ad_section_end(name=default) –>’);
echo ‘<xmp>’;
echo $rankContent;
echo ‘</xmp>’;
$arrSpanClass = getArray($rankContent, ‘<span class=”‘, ‘”>’);
print_r($arrSpanClass);
foreach($arrSpanClass as $css)
{
//global $rankContent;
if (strpos($strAlexaCss, ‘.’ . $css)>0)
{
echo $css .’(h)’;
$rankContent = ScriptHtml($rankContent, “span”, 2, $css);
}
else
echo $css .’(s)’;
$rankContent = ScriptHtml($rankContent, “span”, 1, $css);
}
$rankContent = str_replace(’</span>’, ”, $rankContent);
$rankContent = str_replace(’,', ”, $rankContent);
return $rankContent;
function getBody($ContentStr, $StartStr, $EndStr)
$ContentStr = strtolower($ContentStr);
$StartStr = strtolower($StartStr);
$EndStr = strtolower($EndStr);
$StartPos = strpos($ContentStr, $StartStr);
$EndPos = strpos($ContentStr, $EndStr);
return substr($ContentStr, $StartPos+strlen($StartStr), $EndPos-$StartPos-strlen($StartStr));
function getArray($ContentStr, $StartStr, $EndStr)
$reg = ‘/’ . $StartStr . ‘.+?’ . $EndStr . ‘/’;
preg_match_all($reg, $ContentStr, $arr, PREG_PATTERN_ORDER);
for($i=0; $i<count($arr[0]); $i++)
$arr[0][$i] = str_replace($EndStr, ”, str_replace($StartStr, ”, $arr[0][$i]));
return $arr[0];
function getDomainUrl($url)
$tempUrl = str_replace(’http://’, ”, $url);
$tempUrl = str_replace(’/', ”, $tempUrl);
return $tempUrl;