Web-Harvest是一個Java開源Web數據抽取工具。它能夠收集指定的Web頁面並從這些頁面中提取有用的數據。其實現原理是,根據預先定義的配置文件用httpclient獲取頁面的全部內容(關於httpclient的內容,本博有些文章已介紹),然後運用XPath、XQuery、正則表達式等這些技術來實現對text/xml的內容篩選操作,選取精確的數據。前兩年比較火的垂直搜索(比如:酷訊等)也是采用類似的原理實現的。Web-Harvest應用,關鍵就是理解和定義配置文件,其他的就是考慮怎麼處理數據的Java代碼。當然在爬蟲開始前,也可以把Java變量填充到配置文件中,實現動態的配置。
現在以爬取天涯論壇的所有版面信息為例,介紹Web-Harvest的用法,特別是其配置文件。
天涯的版塊地圖頁面時:http://www.tianya.cn/bbs/index.shtml
[天涯的部分版面列表]
我們的目標就是要抓取全部的版塊信息,包括版塊之間的父子關系。
先查看版塊地圖的頁面源代碼,尋求規律:
<div class="backrgoundcolor">
<div class="bankuai_list">
<h3>社會民生</h3>
<ul>
<li><a href="http://www.tianya.cn/publicforum/articleslist/0/free.shtml" id="item天涯雜談">天涯雜談</a></li>
<li><a href="http://www.tianya.cn/publicforum/articleslist/0/worldlook.shtml" id="item國際觀察">國際觀察</a></li>
<li><a href="http://www.tianya.cn/publicforum/articleslist/0/news.shtml" id="item天涯時空">天涯時空</a></li>
<li><a href="http://www.tianya.cn/publicforum/articleslist/0/no06.shtml" id="item傳媒江湖">傳媒江湖</a></li>
…… //省略
</ul>
</div>
<div class="clear"></div>
</div>
<div class="nobackrgoundcolor">
<div class="bankuai_list">
<h3>文學讀書</h3>
<ul>
<li><a href="http://www.tianya.cn/techforum/articleslist/0/16.shtml" id="item蓮蓬鬼話">蓮蓬鬼話</a></li>
<li><a href="http://www.tianya.cn/publicforum/articleslist/0/no05.shtml" id="item煮酒論史">煮酒論史</a></li>
<li><a href="http://www.tianya.cn/publicforum/articleslist/0/culture.shtml" id="item舞文弄墨">舞文弄墨</a></li>
…….//省略
</ul>
</div>
<div class="clear"></div>
</div>
…….//省略
通過頁面源碼分析,發現每個大板塊都是在<div class="bankuai_list"></div>的包括之下,而大板塊下面的小版塊都是下面的形式包含的。
<li><a href="xxx" id="xxx">xxx</a></li>,這些規律就是webharvest爬數據的規則。
下面先給出全部的配置:(tianya.xml)
<config charset="utf-8">
<var-def name="start">
<html-to-xml>
<http url="http://www.tianya.cn/bbs/index.shtml" charset="utf-8" />
</html-to-xml>
</var-def>
<var-def name="ulList">
<xpath expression="//div[@class='bankuai_list']">
<var name="start" />
</xpath>
</var-def>
<file action="write" path="tianya/siteboards.xml" charset="utf-8">
<![CDATA[ <site> ]]>
<loop item="item" index="i">
<list><var name="ulList"/></list>
<body>
<xquery>
<xq-param name="item">
<var name="item"/>
</xq-param>
<xq-expression><![CDATA[
declare variable $item as node() external;
<board boardname="{normalize-space(data($item//h3/text()))}" boardurl="">
{
for $row in $item//li return
<board boardname="{normalize-space(data($row//a/text()))}" boardurl="{normalize-space(data($row/a/@href))}" />
}
</board>
]]></xq-expression>
</xquery>
</body>
</loop>
<![CDATA[ </site> ]]>
</file>
</config>
這個配置文件分為三個部分:
1.定義爬蟲入口:
<var-def name="start">
<html-to-xml>
<http url="http://www.tianya.cn/bbs/index.shtml" charset="utf-8" />
</html-to-xml>
</var-def>
爬蟲的入口URL是:http://www.tianya.cn/bbs/index.shtml
同時,指定了爬蟲的爬數據的編碼,這個編碼應該根據具體的頁面編碼來定,例如上面的入口頁面的編碼就是utf-8。其實,有很多的中文頁面的編碼是gbk或者gb2312,那麼這個地方的編碼就要相應設置,否則會出現數據亂碼。
2.定義數據的過濾規則:
<var-def name="ulList">
<xpath expression="//div[@class='bankuai_list']">
<var name="start" />
</xpath>
</var-def>
上面配置就是根據XPath從爬得的數據中篩選合適的內容。這裡需要得到所有的<div class="bankuai_list"></div>信息。有關XPath和XQuery的語法請網上查詢。
3.最後一步就是處理數據。可以寫入XML文件,也可以使用SetContextVar的方式把收集的數據塞到一個集合變量中,供Java代碼調用(比如:數據直接入庫)。
這裡是直接寫入XML文件,然後解析XML即可。
注意下面的for循環,這是XQuery的語法,提供遍歷的功能。由於大版面小版塊是一個樹狀結構,需要這種遍歷。
<board boardname="{normalize-space(data($item//h3/text()))}" boardurl="">
{
for $row in $item//li return
<board boardname="{normalize-space(data($row//a/text()))}" boardurl="{normalize-space(data($row/a/@href))}" />
}
</board>
相關的Java代碼如下:
/**
* Copyright(C):2009
* @author陳新漢
* Sep4,20093:24:58PM
*/
String configFile="tianya.xml";
ScraperConfiguration config = new ScraperConfiguration(configFile);
String targetFolder="c:\\chenxinhan";
Scraper scraper = new Scraper(config,targetFolder);
//設置爬蟲代理
scraper.getHttpClientManager().setHttpProxy("218.56.64.210","8080");
scraper.setDebug(true);
scraper.execute();
上面代碼執行完成後,收集的數據文件地址為:c:\chenxinhan\tianya\siteboards.xml