網頁抓取與分析

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.plgraphics/myname.jpggraphics/animgif/flare.gifgraphics/course.gifgraphics/research.gifhttp://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.htmhttp://neural.cs.nthu.edu.tw/jang/cgi-bin/rand_image.plhttp://neural.cs.nthu.edu.tw/graphics/myname.jpghttp://neural.cs.nthu.edu.tw/graphics/animgif/flare.gifhttp://neural.cs.nthu.edu.tw/graphics/course.gifhttp://neural.cs.nthu.edu.tw/graphics/research.gifhttp://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.htmhttp://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/demohttp://www.cs.nthu.edu.tw/~jang/mlbookhttp://neural.cs.nthu.edu.tw/research/undergradhttp://anfis.cs.nthu.edu.tw/vod/http://140.114.119.1/~vm...

由此可見 tlink3.pl 已經可以抓取出網頁的連結,而且所有連結網址也都轉換為絕對網址。如果我們要實作一個 Web 的搜尋引擎,第一步驟就是要寫出一個 Web Robot,它的功能就是要能抓取網頁,並抽取每一個網頁的連結網址,然後再往下繼續抓取被連結網頁,如此依此類推。所以上述的範例程式,就是一個簡單 Web Robot 的雛形。


7-2 網頁抓取與分析:進階篇

在上節中,我們介紹了 LWP::Simple 的用法和範例。使用 LWP::Simple 來抓取網頁相當方便,但是它也有一些缺點:
  1. 在抓取網頁過程中,無法傳會狀態碼(Status Code)。常見的狀態碼有下列幾種:

    狀態碼 說明
    200OK,一切正常
    404找不到所要求的網頁
    408等待伺服器回覆時間過久
    500伺服器內部發生錯誤

  2. Perl 程式並不會在表頭(Header)向伺服器表明自己的身份。
  3. 不支援代理伺服器(Proxy Server)。
因此,若要能夠取得要求網頁的狀態碼,就必須要使用較複雜的模組。以下的這個例子,可以先判斷是否抓取網頁成功,若成功,則印出網頁原始碼;若不成功,則印出錯誤訊息。程式碼( tstatus.pl)如下:

原始檔(tstatus.pl): (灰色區域按兩下即可拷貝)
use LWP::UserAgent;
use HTTP::Request;
use HTTP::Response;

$ua = new LWP::UserAgent;				# 產生 UserAgent 物件
$request = new HTTP::Request('GET', $ARGV[0]);	# 產生 Request 物件
$response = $ua->request($request);			# 開始抓取網頁,並將結果傳會 $response
if ($response->is_success) {			# 若抓取網頁成功,則印出 HTML 原始碼
	print $response->content;
} else {						# 若抓取網頁不成功,則印出錯誤訊息
	print $response->error_as_HTML;
}

下面這個範例(tproxy.pl),則使用了 HTTP 代理伺服器來減少網路的流量:

原始檔(tproxy.pl): (灰色區域按兩下即可拷貝)
use LWP::UserAgent;
use HTTP::Request;
use HTTP::Response;

$ua = new LWP::UserAgent;				# 產生 UserAgent 物件
$ua->proxy('http', 'http://proxy.nthu.edu.tw/proxy.pac');	# 設定 HTTP 的代理伺服器
$ua->no_proxy('nthu.edu.tw');			# 在清大的網頁(nthu.edu.tw)不使用代理伺服器
$request = new HTTP::Request('GET', $ARGV[0]);	# 產生 Request 物件
$response = $ua->request($request);			# 開始抓取網頁,並將結果傳會 $response
if ($response->is_success) {			# 若抓取網頁成功,則印出 HTML 原始碼
	print $response->content;
} else {						# 若抓取網頁不成功,則印出錯誤訊息
	print $response->error_as_HTML;
}

行文至此,讀者應該可以感受到用 Perl 來抓取網頁的便利性與彈性。稍微修改上述的範例程式,就可以產生許多不同的應用,以下是一些有用(或有趣)的應用範例:

  • 自動留言程式:你可以寫一個 Perl 程式,自動尋找留言版,並自動留言,如「孫悟空到此一遊」等。
  • Web 統計資料:可以根據搜尋引擎的結果,來發掘對於某個問題的正反面答案。例如,如果你想知道那個程式語言最被大家喜愛,可參見:
    http://www.lehigh.edu/~sol0/rules.html
    (不看上述網頁,你大概可以猜到答案是什麼吧?)
  • 驗證網頁的連結是否正確:我們只需抽取出此網頁的連結,再抓取所有連結網頁的表頭(不需抓取內文,以減輕網路流量),即可確認連結是否正確。
  • 表明 User Agent 身份:在向伺服器送出的 Request 表頭中,Perl 程式碼可以表明自己的身份,此功能能讓伺服器記錄送出 request 的 UserAgent 的類別。
  • 個人資訊代理程式(Agent):你可以寫一個 Perl 程式,定期自動抓取個人所需特定資訊,並即刻顯示再瀏覽器,例如某城市的氣溫、快遞包裹的傳送情況等。
  • Mirror 功能:建立一個 Mirror 站台,並用 Perl 程式在預定時段自動更新。
  • 網羅新聞:即時抓取線上新聞,並根據新聞標題加以自動聚題(同一個主題的新聞放在一起)與分類(政治類、娛樂類等)。這是典型的「網頁加工業」,也是「知識管理」的一部份,可見太一信通公司的網羅新聞頁:
    http://www.taiyi.com
  • 全文搜尋引擎:你可以反覆抓取網頁,再根據資訊檢索(Information Retrieval)的各種演算法,建立反轉索引(Inverted Indexing),最後建立一個網頁的全文檢索搜尋引擎。典型的搜尋引擎可見中正大學的蓋世引擎:
    http://gais.cs.ccu.edu.tw/
    或美國的 Google 搜尋引擎:
    http://www.google.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值