天天看點

PHP 程式設計擷取網站的 Alexa 排名

現在大多數提供網站排名的網站,其資料都是取自于 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;