網絡爬蟲(web crawler)又稱爲網絡蜘蛛(web spider)是一段計算機程序,它從互聯網上按照一定的邏輯和算法抓取和下載互聯網的網頁,是搜索引擎的一個重要組成部分。一般的爬蟲從一部分start url開始,按照一定的策略開始爬取,爬取到的新的url在放入到爬取隊列之中,然後進行新一輪的爬取,直到抓取完畢爲止。
我們看一下crawler一般會遇到什麼樣的問題吧:
- 抓取的網頁量很大
- 網頁更新量也很大,一般的網站,比如新聞,電子商務網站,頁面基本是實時更新的
- 大部分的網頁都是動態的,多媒體,或者封閉的(facebook)
海量網頁的存在就意味着在一定時間之內,抓取只能的抓取其中的一部分,因此需要定義清楚抓取的優先級;網頁更新的頻繁,也就意味着需要抓取最新的網頁和保證鏈接的有效性,因此一個更有可能帶來新網頁的列表頁顯得尤爲重要;對於新聞網站,新的網站一般出現在首頁,或者在指定的分類網頁,但是對於淘寶來說,商品的更新就很難估計了;動態網頁怎麼辦呢?現在的網頁大都有JS和AJAX,抓取已經不是簡單的執行wget下載,現代的網頁結構需要我們的爬蟲更加智能,需要更靈活的應對網頁的各種情況。
因此,對一個通用的爬蟲個,我們要定義
- 抓取策略,那些網頁是我們需要去下載的,那些是無需下載的,那些網頁是我們優先下載的,定義清楚之後,能節省很多無謂的爬取
- 更新策略,監控列表頁來發現新的頁面;定期check頁面是否過期等等
- 抽取策略,我們應該如何的從網頁中抽取我們想要的內容,不僅僅包含最終的目標內容,還有下一步要抓取的url
- 抓取頻率,我們需要合理的去下載一個網站,卻又不失效率
抓取策略
使用URL的正則特徵是一個簡單但卻很高效的模式;對於定向抓取,一般的網站的URL有一定的特徵,比如可能僅僅關心 .html, .htm, .asp, .aspx, .php, .jsp, .jspx類型的網頁;或者是如果可以得到目標網站的正則,則可以大大的降低抓取的數量;又或者我們無需關心某一類網頁,比如我們不抓取bbs.taobao.com下面的內容;僅僅需要抓取淘寶的商品頁面(http://item.taobao.com/item.htm?id=\d+ )。通過URL的正則能極大的降低抓取數量;
也可以通過網頁的文本特徵來確定;不過要複雜得多了,一般需要一定數量已知頁面的訓練集合,然後提取頁面的文本特徵,然後通過向量空間模型或者其其他基於主題詞提取的模型計算目標網頁和訓練集網頁的距離,決定是否是目標網頁。
更新策略
Freshness:表示抓取到的網頁是否已經被修改
Age:表示抓取的網頁過期的時間
對於更新來說,目標是讓平均age時間越小,freshness越高;一般的更新策略有兩種:定期批量更新和按更新週期更新;定期批量更新指對一批URL,按照失效時間定期去刷新,按週期更新指的是按照頁面更新變化頻率而修正是更新頻率,一般來說,更新越頻繁的網頁更新也就越快。
抽取策略:
XPATH是一個簡單直觀,但是很有效的一個方案,XPATH能精準的定位網頁的任意一個位置,意味着我們可以很精準的抽取頁面上的任意位置,當面臨很多網站的時候,當然配置XPATH就是一個很艱鉅的任務,也許存在一個自適應的XPATH識別的方法。
JS和AJAX
在java下面,HtmlUnit是一個不錯的解決方案,HtmlUnit是Junit 的擴展測試框架之一,該框架模擬瀏覽器的行爲,開發者可以使用其提供的API對頁面的元素進行操作,套用官方網站的話HtmlUnit“是Java程序的瀏覽器”。HtmlUnit支持HTTP,HTTPS,COOKIE,表單的POST和GET方法,能夠對HTML文檔進行包裝,頁面的各種元素都可以被當作對象進行調用,另外對JavaScript的支持也比較好。一般來說,HtmlUnit是在java環境下解決JS的很好的選擇
WebKit包含一個網頁引擎WebCore和一個腳本引擎JavaScriptCore,它們分別對應的是KDE的KHTML和KJS;目前比較主流的瀏覽器Google Chrome和Apple的safari,都是基於WebKit的內核寫的。使用瀏覽器作爲抓取能更好的模擬用戶瀏覽的行爲,能夠天然的解決JS和AJAX等問題,問題可能就是性能是一個瓶頸,
抓取頻率
同時開啓N個線程抓取一個網站,相信很快就會被對方網站封掉;因此抓取的頻率也很重要;抓取網站同時不對對方網站造成壓力;在robot.txt協議裏面定義Crawl-delay來確定抓取的頻率也是一種網站的通用的做法,對於一般的抓取而言,10到20秒抓取一次是一個比較保險的頻率,也有提出10*t的抓取間隔(t是download時間)比較合理
定向抓取的框架
通用抓取架構,如下圖
多線程下載模塊(Multi-threaded downloader)
該模塊一般包含:
- 下載模塊,下載網頁,並應對一些web的一些錯誤,包括redirect等等
- DNS解析模塊,網頁數量很多的時候,我們需要一個本地的DNS解析模塊來維護domain到IP的映射
- 鏈接抽取模塊,抽取下一步要抓取的鏈接(follow link)
調度模塊(schedule)
調度模塊是抓取系統的核心,調度模塊從url隊列裏面選擇一批url喂到下載模塊下載;其中會涉及到
- url調度,調度模塊按照一定的策略,選取url進入抓取系統
- url除重,一定時期之內已經抓取的網頁,不再抓取
實例:使用開源的scrapy爬蟲抓取B2C站點的商品
Scrapy(http://scrapy.org/)是基於Twisted的異步處理框架,純python實現的爬蟲框架,用戶只需要定製開發幾個模塊就可以輕鬆的實現一個爬蟲,用來抓取網頁內容以及各種圖片,非常之方便,現在我們以scrapy爲例子,簡單配置一個抓取商品的例子。
Scrapy的安裝請參考 http://doc.scrapy.org/intro/install.html#intro-install
- 定義起始頁面:http://www.xxxx.com
- 定義詳情頁,例如:http://product.xxxx.com/product.htm?id=\d+
- 執行scrapy startproject mycrawler,新建一個mycrawler的工程
- 在mycrawler/mycrawler/spiders目錄下,寫抓取的python代碼:mycrawlerspider.py
from scrapy.selector import HtmlXPathSelector
from scrapy.spider import BaseSpider
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.utils.url import urljoin_rfc
from scrapy.http import Request
class MySpider(BaseSpider):
name = 'test'
allowed_domains = ['xxxx.com']
start_urls = [
'http://www.xxxx.com',
]
download_delay = 10
def parse(self, response):
for link in SgmlLinkExtractor(allow=" product.htm\?id=\d+").extract_links(response):
yield Request(link.url,callback=self.parse_detail)
hxs = HtmlXPathSelector(response)
for url in hxs.select('//a/@href').extract():
url = self._urljoin(response,url)
#print url
yield Request(url, callback=self.parse)
def parse_detail(self, response):
hxs = HtmlXPathSelector(response)
what_u_want= hxs.select("/xpath/text()").extract()[0]
print 'url=',response.url, what_u_want.strip()
return
def _urljoin(self, response, url):
"""Helper to convert relative urls to absolute"""
return urljoin_rfc(response.url, url, response.encoding)
簡單幾步,我們就可以抓取得到一個站點想要的頁面了,並且可以抽取指定xpath的內容。
一個簡單的定向爬蟲就搭建起來了,關鍵是一個能夠大規模的分佈式的爬蟲可能是一個挑戰,後續再進一步介紹如何在分佈式環境進行大規模的抓取,以及抓取遇到的一些更爲棘手的問題,see u
原文地址:http://www.searchtb.com/2011/01/an-introduction-to-crawler.html
如有版權問題請與原文作者聯繫