7-1 網頁抓取與分析:入門篇

Perl 在 Web 程式設計與應用的用途可以大略分為三方面:
  1. 用於 CGI(Common Gateway Interface)程式設計,亦即在伺服器端使用 Perl 程式來接收使用者由網頁中的表單(Forms)所填寫的資料,並回覆適當的訊息。
  2. 用於 Web Client Programming,亦即使用在用戶端的 Perl 程式,來抓取所需的網頁或其他網路上的資料。
  3. 用於資料處理,例如從網業中抽取有用的資訊。
本節將針對第二及第三點來說明。

在用戶端要用 Perl 程式來抓取所需的網頁,最主要有兩程式庫可供使用:

  1. LWP Library: 這是一組適用於 Perl 第五版的模組(Module),可以看成是專門用於 Web Client Programming 的應用程式介面(Application Program Interface, API),其程式介面較簡單,用此模組寫出來的程式碼也較為簡潔。
  2. Socket Library: 這是一組較低層次的應用程式介面,可以讓用戶端和伺服器建立 TCP/IP 連結,並進行各種通訊與溝通。Socket Library 的功能較強大,但由於包含太多細節,因此學習門檻較高。
由於一般用戶只是要對 Web 伺服器抓取網頁而已,因此本節介紹就以 LWP Library 為主。

LWP Library 又稱為 libwww-perl-5,其主要作者(也是推動者)是 Gisle Aas,他是根據 Roy Fielding 在 Perl 4 所發展的 libwww library 來加以推廣、改良而得到的模組。和 LWP Library 相關的各種資訊可在其網頁獲得:

http://www.linpro.no/lwp/
截至本書發梓為止,LWP Library 的最新版本是 5.48,發行日期是 2000 年四月九號。目前在市面上以 LWP Library 為基礎所寫的原文書有兩本: 舉一個最簡單的例子,如果要抓取清華大學資訊系的網頁,可以使用下列程式碼(lwp1.pl):

原始檔(lwp1.pl):(灰色區域按兩下即可拷貝)
use LWP::Simple;
$doc = get 'http://www.cs.nthu.edu.tw';
print($doc);

上述程式碼的第一列,代表此程式碼會用到 LWP Library 中名稱為 Simple 的模組。第二列程式碼將清大資訊系的首頁抓回,並將資訊填入字串變數 $doc。第三列程式碼則印出變數 $doc。筆者相信,在所有抓取網頁的任何程式碼,不論使用任何語言,再也不可能會有比上述程式碼更簡潔的版本了!

事實上,若要抓取網頁並將其內容顯示在螢幕上,我們可以在 DOS 命令視窗下輸入下列單行的敘述:

perl -MLWP::Simple -e 'getprint "http://www.cs.nthu.edu.tw";' 此時 Perl 就會使用 LWP Library 來捉取網頁,並將 HTML 原始檔顯示在螢幕上,讀者不妨一試!

若在取得網頁原始碼後,希望能刪除 HTML 的標籤(Tags),則可使用下列的程式碼(lwp2.pl):

原始檔(lwp2.pl):(灰色區域按兩下即可拷貝)
use LWP::Simple;
foreach (get $ARGV[0]) {
	s/<[^>]*>//g;
	print;
}

在上述範例中,ARGV[0] 代表由命令列輸入的第一個參數,因此以下是一個呼叫此範例程式的例子:

perl lwp2.pl http://neural.cs.nthu.edu.tw/jang 若在取得網頁原始碼後,希望能以 ASCII 檔案顯示,但盡量保留 HTML 的排版效果,則可使用下列的程式碼(lwp3.pl):

原始檔(lwp3.pl):(灰色區域按兩下即可拷貝)
use LWP::Simple;
use HTML::Parse;
print parse_html(get ($ARGV[0]))->format;

若希望能抽取網頁原始碼所包含的所有連結,可使用下列程式碼(tlink1.pl):

原始檔(tlink1.pl):(灰色區域按兩下即可拷貝)
use LWP::Simple;
use HTML::Parse;
use HTML::Element;
$html = get $ARGV[0];
$parsed_html = HTML::Parse::parse_html($html);
for (@{ $parsed_html->extract_links() }) {
	$link = $_->[0];
	print "$link\n";
}

我們可執行上述程式碼,如下:

perl tlink1.pl http://neural.cs.nthu.edu.tw/jang 執行後的結果如下: sandbox/html/autoload.htm /jang/cgi-bin/rand_image.pl graphics/myname.jpg graphics/animgif/flare.gif graphics/course.gif graphics/research.gif http://neural.cs.nthu.edu.tw/jang/courses/cs4601/ http://neural.cs.nthu.edu.tw/jang/courses/cs5652/ http://www.cs.nthu.edu.tw/~jang/courses/cs3331/ ... 此 Perl 程式雖然已將各個連結印出,但有些是相對網址,有些則是絕對網址,非常不方便。以下程式碼(tlink2.pl)可以將所有連結的相對網址轉成絕對網址:

原始檔(tlink2.pl):(灰色區域按兩下即可拷貝)
use LWP::Simple;
use HTML::Parse;
use HTML::Element;
use URI::URL;
$html = get $ARGV[0];
$parsed_html = HTML::Parse::parse_html($html);
for (@{ $parsed_html->extract_links() }) {
	$link = $_->[0];
	$url = new URI::URL $link;
	$full_url = $url->abs($ARGV[0]);
	print "$full_url\n";
}

我們可執行上述程式碼,如下:

perl tlink2.pl http://neural.cs.nthu.edu.tw/jang 執行後的結果如下: http://neural.cs.nthu.edu.tw/sandbox/html/autoload.htm http://neural.cs.nthu.edu.tw/jang/cgi-bin/rand_image.pl http://neural.cs.nthu.edu.tw/graphics/myname.jpg http://neural.cs.nthu.edu.tw/graphics/animgif/flare.gif http://neural.cs.nthu.edu.tw/graphics/course.gif http://neural.cs.nthu.edu.tw/graphics/research.gif http://neural.cs.nthu.edu.tw/jang/courses/cs4601/ http://neural.cs.nthu.edu.tw/jang/courses/cs5652/ http://www.cs.nthu.edu.tw/~jang/courses/cs3331/ ... 很明顯地,所有的相對路徑已經被轉成絕對路徑。但是,其中有很多連結是連到一個影像檔(如*.jpg),並不是我們所想到的資訊,因此我們可用下列程式碼(tlink3.pl)來規範所想要的文字連結:

原始檔(tlink3.pl):(灰色區域按兩下即可拷貝)
use LWP::Simple;
use HTML::Parse;
use HTML::Element;
use URI::URL;
$html = get $ARGV[0];
$parsed_html = HTML::Parse::parse_html($html);
for (@{ $parsed_html->extract_links((“a”)) }) {
	$link = $_->[0];
	$url = new URI::URL $link;
	$full_url = $url->abs($ARGV[0]);
	print “$full_url\n”;
}

我們可執行上述程式碼,如下:

perl tlink3.pl http://neural.cs.nthu.edu.tw/jang 執行後的結果如下: http://neural.cs.nthu.edu.tw/sandbox/html/autoload.htm http://neural.cs.nthu.edu.tw/jang/courses/cs4601/ http://neural.cs.nthu.edu.tw/jang/courses/cs5652/ http://www.cs.nthu.edu.tw/~jang/courses/cs3331/ http://neural.cs.nthu.edu.tw/jang/courses/cs3430/ http://www.cs.nthu.edu.tw/~jang/mlbook/demo http://www.cs.nthu.edu.tw/~jang/mlbook http://neural.cs.nthu.edu.tw/research/undergrad http://anfis.cs.nthu.edu.tw/vod/ http://140.114.119.1/~vm ... 由此可見 tlink3.pl 已經可以抓取出網頁的連結,而且所有連結網址也都轉換為絕對網址。如果我們要實作一個 Web 的搜尋引擎,第一步驟就是要寫出一個 Web Robot,它的功能就是要能抓取網頁,並抽取每一個網頁的連結網址,然後再往下繼續抓取被連結網頁,如此依此類推。所以上述的範例程式,就是一個簡單 Web Robot 的雛形。
Perl