2012年3月4日 星期日
WebHarvest採集網路數據
一、背景
在當前信息空前爆炸的時代,人們不再擔心信息的匱乏,而是為篩選有用的信息付出大量的代價。那麼如何採集有用的信息呢?
現在有 RSS、博客等服務,但是並不能完全滿足我們的需求,因為很多信息並不是以格式化的數據形式提供出來,於是聰明的工程師想出了精確搜索的方法,從而出現大量的垂直搜索網站 (比如酷訊),確實火了一把。當然我們無法得知他們是怎麼實現的,但是我們也可以實現這種精確採集,開源的 Web-Harvest 就是類似的技術,之前曾經接觸過,故寫出來分享給大家。
二、WebHarvest 簡介
Web-Harvest 是一個用 Java 寫的開源的 Web 數據提取工具。它提供了一種從所需的頁面上提取有用數據的方法。為了達到這個目的,你可能需要用到如 XSLT, XQuery, 和正則表達式等操作 text/xml 的相關技術。 Web-Harvest 主要著眼於目前仍佔大多數的基於 HMLT/XML 的頁面內容。另一方面,它也能通過寫自己的 Java 方法來輕易擴展其提取能力。
Web-Harvest 的主要目的是加強現有數據提取技術的應用。它的目標不是創造一種新方法,而是提供一種更好地使用和組合現有方法的方式。它提供了一個處理器集用於處理數據和控制流程,每一個處理器被看作是一個函數,它擁有參數和執行後同樣有結果返回。而且處理是被組合成一個管道的形式,這樣使得它們可以以鍊式的形式來執行,此外為了更易於數據操作和重用,Web-Harvest 還提供了變量上下方用於存儲已經聲明的變量。
上述流程的執行結果可以存儲在執行中創建的文件中或者是編程時的上下文環境中使用。
一、配置語言
每個提取過程都被定義在了一個或多個基於 XML 的配置文件中,而且被描述為特定的或是結構化的 XML 元素中。為了更好地說明,下面列舉了一個配置文件來進行說明:
<config charset="gbk">
<!– 頁面爬取開始,按照關鍵詞:"玩具"來搜索–>
<var-def name="start" >
<html-to-xml>
<http url="http://www.baidu.com/s?wd=玩具"/>
</html-to-xml>
</var-def>
<!– 獲取競價排名的企業網站列表–>
<var-def name="urlList" >
<xpath expression="//div[@class='r']">
<var name="start"/>
</xpath>
</var-def>
<!– 循環urlList ,並把結果寫入到XML文件中–>
<file action="write" path="baidu/catalog.xml" charset="utf-8″>
<![CDATA[ <catalog> ]]>
<loop item="item" index="i">
<list><var name="urlList"/></list>
<body>
<xquery>
<xq-param name="item" type="node()"><var name="item"/></xq-param>
<xq-expression><![CDATA[
declare variable $item as node() external;
let $name := data($item//span/font[1]/text()[1])
let $url := data($item//span/font[2]/text())
return
<website>
<name>{normalize-space($name)}</name>
<url>{normalize-space($url)}</url>
</website>
]]></xq-expression>
</xquery>
</body>
</loop>
<![CDATA[ </catalog> ]]>
</file></config>
上述的配置文件包含了三段。
第一段的執行步驟:1. 下載 http://www.baidu.com/s?wd=玩具 裡面的內容;2. 清除下載內容裡面的 HTML 以產生 XHTML;
第二段的執行步驟:1. 用 XPath 表達式從所給的 URL 裡面提取搜索結果;2. 用一個新的變量 "urlList" 來保存上面的搜索結果;
第三段是利用上一段的搜索結果來提取相應的信息:1. 循環裡面迭代每一個 item;2. 獲取每個 item 的 name 和 url;3. 將其保存在文件系統裡;
有了配置文件 (把該配置文件保存為:baidu.xml),我們再往前一步,寫幾行代碼:import java.io.IOException;import org.webharvest.definition.ScraperConfiguration;import org.webharvest.runtime.Scraper;public class Test {
public static void main(String[] args) throws IOException {
ScraperConfiguration config = new ScraperConfiguration("c:/baidu.xml");
Scraper scraper = new Scraper(config, "c:/tmp/");
scraper.setDebug(true);
long startTime = System.currentTimeMillis();
scraper.execute();
System.out.println("time elapsed: " + (System.currentTimeMillis() - startTime));
}}
讓我們執行一下,看看結果:<catalog>
<website>
<name>上海麗強 專業大型</name>
<url>www.liqiang-toy.com</url>
</website>
<website>
<name>多樣型大型</name>
<url>www.yonglangplay.com</url>
</website>
<website>
<name>童博士卡通</name>
<url>www.tbs88.com</url>
</website>
<website>
<name>芝麻街</name>
<url>c49.txooo.js.cn</url>
</website>
<website>
<name>童博士, 中國平價學生用品..</name>
<url>www.cfsj8.cn</url>
</website>
<website>
<name>充氣</name>
<url>www.xmcaili.com</url>
</website>
<website>
<name>找木製</name>
<url>www.tengyuetoys.com</url>
</website>
<website>
<name>米多迪</name>
<url>b146.txooo.com</url>
</website></catalog>
是不是很酷。爬蟲就這麼簡單。
二、深入考慮
不知道大家看到上面的配置、代碼和結果是否感覺很熟悉。是否和 Java 通過 Ibatis 讀取數據庫數據的方式類似。
那我們是否可以實現這樣的機制呢,把整個互聯網作為我們的龐大的數據庫,我們隨意的讀取。
Web-Harvest 提供了一個 ScraperContext,可以在該上下文中設置 Java 對象,可以通過 Java 對象收集相應的結果數據,(比如:設置 Map,可以通過 Map 收集數據)Scraper 提供了這樣的方法:
scraper.getContext().put("resDataSet", new ResultDataSet());ResultDataSet 是收集數據的 Java 對象。
那麼我們就可以這麼做:
1. 首先設置要訪問的網頁的路徑scraper.getContext().put("startPageHref", "http://www.baidu.com/s?cl=3&wd=兒童玩具");
2. 第二步,設置要收集返回數據的容器scraper.getContext().put("resDataSet", new ResultDataSet());
3. 在配置文件中就可以這樣設置數據${resDataSet.addRecord("searchResult","totalSearchResult",totalSearchResult)};d) 爬取操作執行完畢後,即可返回數據:ResultDataSet resultDataSet = (ResultDataSet)scraper.getContext().get("resDataSet");Ok,我們就可以隨心所欲的使用這些數據,詳細請看附件。
三、分頁機制處理
1. 來由介紹現在的信息量很大,在展示的時候都是通過分頁處理的。
2. 實現機制那我們怎麼處理呢?分頁提取數據我們得明確幾件事情a. 分頁器的處理,比如:頁碼、頁大小、記錄數或頁數。b. "下一頁"的地址的構造c. 每頁數據的爬取不同的網站的分頁機制都不一樣,我們如何處理呢?當然我們不能通過硬編碼的方式來處理,我們就通過 Web-Harvest 的配置文件來實現。
Web-Harvest 本身的配置文件結構為:<config charset="gbk">
配置信息
</config>對這個結構進行擴展:<web-harvest-config>
<!– 生成分頁器配置 –>
<config charset="gbk" id="pagination">
配置信息
</config>
<!– 組裝下一頁地址 –>
<config charset="gbk" id="urlnav">
配置信息
</config>
<!– 抓取列表數據 –>
<config charset="gbk" id="listData">
配置信息
</config></web-harvest-config>
我們就可以通過三個config項來處理
第一步,通過 id="pagination" 的配置生成分頁器
第二步,通過已經生成的分頁器加上 id="urlnav" 的配置構造下一頁的 URL
第三步,通過 id="listData" 的配置提取需要的數據
一、Web-Harvest的優缺點
優點:1. Web-Harvest 是一個使用比較方便的抓取信息的 API 庫,目前是 1.0 版本2. 擴展性好,只要修改配置文件即可3. 上手較快,使用方便。
缺點:1. 處理過程比較多,對應的速度較慢
二、其他使用過或者正在嘗試的精確抓取數據的方式
1. 使用 HTMLParserHTMLParser 可以分析 HTML 源碼中的 TAG (比如 Table,DIV 等),還可以自己定義 TAG (比如:ENET),通過查找特定的 Tag,提取相應的數據。由於沒有很多的中間處理過程,速度較快,缺點是有很多的硬編碼,難以擴展。或許能找出一個特定的表達式可以快速的提取數據。
2. 使用 HTMLClean該方式還是走 HTML->XML 的路線,首先通過 HtmlClean 把抓取的網頁內容轉化為 XML 格式數據,然後通過 XPATH、XSL 等方式對 XML 數據進行轉化,達到收集數據的目的。 Web-Harvest 是類似的方式,但是我們可以精簡化,提高抓取的效率。
三、使用爬蟲碰到的問題
1. 網站對頻繁抓取數據的爬蟲進行IP限制問題考慮使用 IP 代理,但是速度難以忍受,故現在在考慮分佈式的抓取數據的方式。
訂閱:
張貼留言 (Atom)
沒有留言:
張貼留言