一、背景
在當(dāng)前信息空前爆炸的時代,人們不再擔(dān)心信息的匱乏,而是為篩選有用的信息付出大量的代價。那么如何采集有用的信息呢?現(xiàn)在有RSS、博客等服務(wù),但是并不能完全滿足我們的需求,因為很多信息并不是以格式化的數(shù)據(jù)形式提供出來,于是聰明的工程師想出了精確搜索的方法,從而出現(xiàn)大量的垂直搜索網(wǎng)站(比如酷訊),確實火了一把。當(dāng)然我們無法得知他們是怎么實現(xiàn)的,但是我們也可以實現(xiàn)這種精確采集,開源的Web-Harvest就是類似的技術(shù),之前曾經(jīng)接觸過,故寫出來分享給大家。
二、WebHarvest簡介
Web-Harvest是一個用Java 寫的開源的Web 數(shù)據(jù)提取工具。它提供了一種從所需的頁面上提取有用數(shù)據(jù)的方法。為了達到這個目的,你可能需要用到如XSLT,XQuery,和正則表達式等操作text/xml 的相關(guān)技術(shù)。Web-Harvest 主要著眼于目前仍占大多數(shù)的基于HMLT/XML 的頁面內(nèi)容。另一方面,它也能通過寫自己的Java 方法來輕易擴展其提取能力。
Web-Harvest 的主要目的是加強現(xiàn)有數(shù)據(jù)提取技術(shù)的應(yīng)用。它的目標不是創(chuàng)造一種新方法,而是提供一種更好地使用和組合現(xiàn)有方法的方式。它提供了一個處理器集用于處理數(shù)據(jù)和控制流程,每一個處理器被看作是一個函數(shù),它擁有參數(shù)和執(zhí)行后同樣有結(jié)果返回。而且處理是被組合成一個管道的形式,這樣使得它們可以以鏈式的形式來執(zhí)行,此外為了更易于數(shù)據(jù)操作和重用,Web-Harvest 還提供了變量上下方用于存儲已經(jīng)聲明的變量。以下的圖表就描述了這種管道式處理器的執(zhí)行情況:
上述流程的執(zhí)行結(jié)果可以存儲在執(zhí)行中創(chuàng)建的文件中或者是編程時的上下文環(huán)境中使用。
一、配置語言
每個提取過程都被定義在了一個或多個基于XML 的配置文件中,而且被描述為特定的或是結(jié)構(gòu)化的XML 元素中。為了更好地說明,下面列舉了一個配置文件來進行說明:
<configcharset=”gbk”>
<!–頁面爬取開始,按照關(guān)鍵詞:“玩具”來搜索 –>
<var-defname=”start” >
<html-to-xml>
<http url=”http://www.baidu.com/s?wd=玩具“/>
</html-to-xml>
</var-def>
<!–獲取競價排名的企業(yè)網(wǎng)站列表 –>
<var-defname=”urlList” >
<xpath expression=”//div[@class='r']“>
<var name=”start”/>
</xpath>
</var-def>
<!–循環(huán) urlList ,并把結(jié)果寫入到XML文件中 –>
<fileaction=”write” path=”baidu/catalog.xml” charset=”utf-8″>
<![CDATA[<catalog> ]]>
<loopitem=”item” index=”i”>
<list><var name=”urlList”/></list>
<body>
<xquery>
<xq-param name=”item” type=”node()”><varname=”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>
上述的配置文件包含了三段。
第一段的執(zhí)行步驟:
2. 清除下載內(nèi)容里面的HTML 以產(chǎn)生XHTML;
3.
第二段的執(zhí)行步驟:
1. 用XPath 表達式從所給的URL 里面提取搜索結(jié)果;
2. 用一個新的變量“urlList”來保存上面的搜索結(jié)果;
第三段是利用上一段的搜索結(jié)果來提取相應(yīng)的信息:
1. 循環(huán)里面迭代每一個item;
2. 獲取每個item的name和url;
3. 將其保存在文件系統(tǒng)里;
有了配置文件(把該配置文件保存為:baidu.xml),我們再往前一步,寫幾行代碼:
importjava.io.IOException;
importorg.webharvest.definition.ScraperConfiguration;
importorg.webharvest.runtime.Scraper;
public class Test {
public static void main(String[] args) throws IOException {
ScraperConfiguration config = newScraperConfiguration(”c:/baidu.xml”);
Scraper scraper = newScraper(config, “c:/tmp/”);
scraper.setDebug(true);
long startTime = System.currentTimeMillis();
scraper.execute();
System.out.println(”time elapsed: ” +(System.currentTimeMillis() - startTime));
}
}
讓我們執(zhí)行一下,看看結(jié)果:
<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>
是不是很酷。爬蟲就這么簡單。
二、深入考慮
不知道大家看到上面的配置、代碼和結(jié)果是否感覺很熟悉。是否和Java通過Ibatis讀取數(shù)據(jù)庫數(shù)據(jù)的方式類似。
那我們是否可以實現(xiàn)這樣的機制呢,把整個互聯(lián)網(wǎng)作為我們的龐大的數(shù)據(jù)庫,我們隨意的讀取。
Web-Harvest提供了一個 ScraperContext , 可以在該上下文中設(shè)置Java對象,可以通過Java對象收集相應(yīng)的結(jié)果數(shù)據(jù),(比如:設(shè)置Map,可以通過Map收集數(shù)據(jù))
Scraper 提供了這樣的方法:
scraper.getContext().put(“resDataSet”, new ResultDataSet());
ResultDataSet是收集數(shù)據(jù)的Java對象。
那么我們就可以這么做:
a) 首先設(shè)置要訪問的網(wǎng)頁的路徑
scraper.getContext().put(“startPageHref”, “http://www.baidu.com/s?cl=3&wd=兒童玩具“);
b) 第二步,設(shè)置要收集返回數(shù)據(jù)的容器
scraper.getContext().put(“resDataSet”, new ResultDataSet());
c) 在配置文件中就可以這樣設(shè)置數(shù)據(jù)
${resDataSet.addRecord(“searchResult”,“totalSearchResult”,totalSearchResult)};
d) 爬取操作執(zhí)行完畢后,即可返回數(shù)據(jù):
ResultDataSet resultDataSet = (ResultDataSet)scraper.getContext().get(“resDataSet”);
Ok,我們就可以隨心所欲的使用這些數(shù)據(jù),詳細請看附件。
三、分頁機制處理
a) 來由介紹
現(xiàn)在的信息量很大,在展示的時候都是通過分頁處理的。比如:
那我們怎么處理呢?分頁提取數(shù)據(jù)我們得明確幾件事情
1. 分頁器的處理,比如:頁碼、頁大小、記錄數(shù)或頁數(shù)。
2. “下一頁”的地址的構(gòu)造
3. 每頁數(shù)據(jù)的爬取
不同的網(wǎng)站的分頁機制都不一樣,我們?nèi)绾翁幚砟???dāng)然我們不能通過硬編碼的方式來處理,我們就通過Web-Harvest的配置文件來實現(xiàn)。
Web-Harvest 本身的配置文件結(jié)構(gòu)為:
<config charset=”gbk”>
配置信息
</config>
對這個結(jié)構(gòu)進行擴展:
<web-harvest-config>
<!–生成分頁器配置 –>
<configcharset=”gbk” id=”pagination”>
配置信息
</config>
<!–組裝下一頁地址 –>
<configcharset=”gbk” id=”urlnav”>
配置信息
</config>
<!–抓取列表數(shù)據(jù) –>
<configcharset=”gbk” id=”listData”>
配置信息
</config>
</web-harvest-config>
我們就可以通過三個config項來處理
l 第一步,通過 id=”pagination”的配置生成分頁器
l 第二步,通過已經(jīng)生成的分頁器加上 id=”urlnav” 的配置構(gòu)造下一頁的URL
l 第三步,通過 id=”listData”的配置提取需要的數(shù)據(jù)
一、Web-Harvest的優(yōu)缺點
優(yōu)點:
l Web-Harvest是一個使用比較方便的抓取信息的API庫,目前是1.0版本
l 擴展性好,只要修改配置文件即可
l 上手較快,使用方便。
l
缺點:
l 處理過程比較多,對應(yīng)的速度較慢
二、其他使用過或者正在嘗試的精確抓取數(shù)據(jù)的方式
a) 使用HTMLParser
HTMLParser可以分析HTML 源碼中的TAG(比如Table,DIV等),還可以自己定義TAG(比如:ENET),通過查找特定的Tag,提取相應(yīng)的數(shù)據(jù)。由于沒有很多的中間處理過程,速度較快,缺點是有很多的硬編碼,難以擴展?;蛟S能找出一個特定的表達式可以快速的提取數(shù)據(jù)。
b) 使用HTMLClean
該方式還是走HTML->XML的路線,首先通過HtmlClean把抓取的網(wǎng)頁內(nèi)容轉(zhuǎn)化為XML格式數(shù)據(jù),然后通過XPATH、XSL等方式對XML數(shù)據(jù)進行轉(zhuǎn)化,達到收集數(shù)據(jù)的目的。Web-Harvest是類似的方式,但是我們可以精簡化,提高抓取的效率。
三、使用爬蟲碰到的問題
a) 網(wǎng)站對頻繁抓取數(shù)據(jù)的爬蟲進行IP限制問題
考慮使用IP代理,但是速度難以忍受,故現(xiàn)在在考慮分布式的抓取數(shù)據(jù)的方式
四、相關(guān)參考
http://web-harvest.sourceforge.net