您好,登錄后才能下訂單哦!
閱讀本文大概需要 10 分鐘。
爬蟲(chóng)是做什么的?是幫助我們來(lái)快速獲取有效信息的。然而做過(guò)爬蟲(chóng)的人都知道,解析是個(gè)麻煩事。
比如一篇新聞吧,鏈接是這個(gè):https://news.ifeng.com/c/7kQcQG2peWU,頁(yè)面預(yù)覽圖如下:
我們需要從頁(yè)面中提取出標(biāo)題、發(fā)布人、發(fā)布時(shí)間、發(fā)布內(nèi)容、圖片等內(nèi)容。一般情況下我們需要怎么辦?寫(xiě)規(guī)則。
那么規(guī)則都有什么呢?懟正則,懟 CSS 選擇器,懟 XPath。我們需要對(duì)標(biāo)題、發(fā)布時(shí)間、來(lái)源等內(nèi)容做規(guī)則匹配,更有甚者再需要正則表達(dá)式來(lái)輔助一下。我們可能就需要用 re、BeautifulSoup、pyquery 等庫(kù)來(lái)實(shí)現(xiàn)內(nèi)容的提取和解析。
但如果我們有成千上萬(wàn)個(gè)不同樣式的頁(yè)面怎么辦呢?它們來(lái)自成千上萬(wàn)個(gè)站點(diǎn),難道我們還需要對(duì)他們一一寫(xiě)規(guī)則來(lái)匹配嗎?這得要多大的工作量啊。另外這些萬(wàn)一弄不好還會(huì)解析有問(wèn)題。比如正則表達(dá)式在某些情況下匹配不了了,CSS、XPath 選擇器選錯(cuò)位了也會(huì)出現(xiàn)問(wèn)題。
想必大家可能見(jiàn)過(guò)現(xiàn)在的瀏覽器有閱讀模式,比如我們把這個(gè)頁(yè)面用 Safari 瀏覽器打開(kāi),然后開(kāi)啟閱讀模式,看看什么效果:
頁(yè)面一下子變得非常清爽,只保留了標(biāo)題和需要讀的內(nèi)容。原先頁(yè)面多余的導(dǎo)航欄、側(cè)欄、評(píng)論等等的統(tǒng)統(tǒng)都被去除了。它怎么做到的?難道是有人在里面寫(xiě)好規(guī)則了?那當(dāng)然不可能的事。其實(shí),這里面就用到了智能化解析了。
那么本篇文章,我們就來(lái)了解一下頁(yè)面的智能化解析的相關(guān)知識(shí)。
所謂爬蟲(chóng)的智能化解析,顧名思義就是不再需要我們針對(duì)某一些頁(yè)面來(lái)專(zhuān)門(mén)寫(xiě)提取規(guī)則了,我們可以利用一些算法來(lái)計(jì)算出來(lái)頁(yè)面特定元素的位置和提取路徑。比如一個(gè)頁(yè)面中的一篇文章,我們可以通過(guò)算法計(jì)算出來(lái),它的標(biāo)題應(yīng)該是什么,正文應(yīng)該是哪部分區(qū)域,發(fā)布時(shí)間是什么等等。
其實(shí)智能化解析是非常難的一項(xiàng)任務(wù),比如說(shuō)你給人看一個(gè)網(wǎng)頁(yè)的一篇文章,人可以迅速找到這篇文章的標(biāo)題是什么,發(fā)布時(shí)間是什么,正文是哪一塊,或者哪一塊是廣告位,哪一塊是導(dǎo)航欄。但給機(jī)器來(lái)識(shí)別的話,它面臨的是什么??jī)H僅是一系列的 HTML 代碼而已。那究竟機(jī)器是怎么做到智能化提取的呢?其實(shí)這里面融合了多方面的信息。
比如標(biāo)題。一般它的字號(hào)是比較大的,而且長(zhǎng)度不長(zhǎng),位置一般都在頁(yè)面上方,而且大部分情況下它應(yīng)該和 title 標(biāo)簽里的內(nèi)容是一致的。
比如正文。它的內(nèi)容一般是最多的,而且會(huì)包含多個(gè)段落 p 或者圖片 img 標(biāo)簽,另外它的寬度一般可能會(huì)占用到頁(yè)面的三分之二區(qū)域,并且密度(字?jǐn)?shù)除以標(biāo)簽數(shù)量)會(huì)比較大。
比如時(shí)間。不同語(yǔ)言的頁(yè)面可能不同,但時(shí)間的格式是有限的,如 2019-02-20 或者 2019/02/20 等等,也有的可能是美式的記法,順序不同,這些也有特定的模式可以識(shí)別。
比如廣告。它的標(biāo)簽一般可能會(huì)帶有 ads 這樣的字樣,另外大多數(shù)可能會(huì)處于文章底部、頁(yè)面?zhèn)葯?,并可能包含一些特定的外鏈?nèi)容。
另外還有一些特點(diǎn)就不再一一贅述了,這其中包含了區(qū)塊位置、區(qū)塊大小、區(qū)塊標(biāo)簽、區(qū)塊內(nèi)容、區(qū)塊疏密度等等多種特征,另外很多情況下還需要借助于視覺(jué)的特征,所以說(shuō)這里面其實(shí)結(jié)合了算法計(jì)算、視覺(jué)處理、自然語(yǔ)言處理等各個(gè)方面的內(nèi)容。如果能把這些特征綜合運(yùn)用起來(lái),再經(jīng)過(guò)大量的數(shù)據(jù)訓(xùn)練,是可以得到一個(gè)非常不錯(cuò)的效果的。
未來(lái)的話,頁(yè)面也會(huì)越來(lái)越多,頁(yè)面的渲染方式也會(huì)發(fā)生很大的變化,爬蟲(chóng)也會(huì)越來(lái)越難做,智能化爬蟲(chóng)也將會(huì)變得越來(lái)越重要。
目前工業(yè)界,其實(shí)已經(jīng)有落地的算法應(yīng)用了。經(jīng)過(guò)我的一番調(diào)研,目前發(fā)現(xiàn)有這么幾種算法或者服務(wù)對(duì)頁(yè)面的智能化解析做的比較好:
Diffbot,國(guó)外的一家專(zhuān)門(mén)來(lái)做智能化解析服務(wù)的公司,https://www.diffbot.com
Boilerpipe,Java 語(yǔ)言編寫(xiě)的一個(gè)頁(yè)面解析算法,https://github.com/kohlschutter/boilerpipe
Embedly,提供頁(yè)面解析服務(wù)的公司,https://embed.ly/extract
Readability,是一個(gè)頁(yè)面解析算法,但現(xiàn)在官方的服務(wù)已經(jīng)關(guān)閉了,https://www.readability.com/
Mercury,Readability 的替代品,https://mercury.postlight.com/
Goose,Java 語(yǔ)音編寫(xiě)的頁(yè)面解析算法,https://github.com/GravityLabs/goose
那么這幾種算法或者服務(wù)到底哪些好呢,Driffbot 官方曾做過(guò)一個(gè)對(duì)比評(píng)測(cè),使用 Google 新聞的一些文章,使用不同的算法依次摘出其中的標(biāo)題和文本,然后與真實(shí)標(biāo)注的內(nèi)容進(jìn)行比較,比較的指標(biāo)就是文字的準(zhǔn)確率和召回率,以及根據(jù)二者計(jì)算出的 F1 分?jǐn)?shù)。
其結(jié)果對(duì)比如下:
Service/Software | Precision | Recall | F1-Score |
Diffbot | 0.968 | 0.978 | 0.971 |
Boilerpipe | 0.893 | 0.924 | 0.893 |
Readability | 0.819 | 0.911 | 0.854 |
AlchemyAPI | 0.876 | 0.892 | 0.850 |
Embedly | 0.786 | 0.880 | 0.822 |
Goose | 0.498 | 0.815 | 0.608 |
經(jīng)過(guò)對(duì)比我們可以發(fā)現(xiàn),Diffbot 的準(zhǔn)確率和召回率都獨(dú)占鰲頭,其中的 F1 值達(dá)到了 0.97,可以說(shuō)準(zhǔn)確率非常高了。另外接下來(lái)比較厲害的就是 Boilerpipe 和 Readability,Goose 的表現(xiàn)則非常差,F(xiàn)1 跟其他的算法差了一大截。下面是幾個(gè)算法的 F1 分?jǐn)?shù)對(duì)比情況:
有人可能好奇為什么 Diffbot 這么厲害?我也查詢(xún)了一番。Diffbot 自 2010 年以來(lái)就致力于提取 Web 頁(yè)面數(shù)據(jù),并提供許多 API 來(lái)自動(dòng)解析各種頁(yè)面。其中他們的算法依賴(lài)于自然語(yǔ)言技術(shù)、機(jī)器學(xué)習(xí)、計(jì)算機(jī)視覺(jué)、標(biāo)記檢查等多種算法,并且所有的頁(yè)面都會(huì)考慮到當(dāng)前頁(yè)面的樣式以及可視化布局,另外還會(huì)分析其中包含的圖像內(nèi)容、CSS 甚至 Ajax 請(qǐng)求。另外在計(jì)算一個(gè)區(qū)塊的置信度時(shí)還考慮到了和其他區(qū)塊的關(guān)聯(lián)關(guān)系,基于周?chē)臉?biāo)記來(lái)計(jì)算每個(gè)區(qū)塊的置信度。
總之,Diffbot 也是一直致力于這一方面的服務(wù),整個(gè) Diffbot 就是頁(yè)面解析起家的,現(xiàn)在也一直專(zhuān)注于頁(yè)面解析服務(wù),準(zhǔn)確率高也就不足為怪了。
但它們的算法開(kāi)源了嗎?很遺憾,并沒(méi)有,而且我也沒(méi)有找到相關(guān)的論文介紹它們自己的具體算法。
所以,如果想實(shí)現(xiàn)這么好的效果,那就使用它們家的服務(wù)就好了。
接下來(lái)的內(nèi)容,我們就來(lái)說(shuō)說(shuō)如何使用 Diffbot 來(lái)進(jìn)行頁(yè)面的智能解析。另外還有 Readability 算法也非常值得研究,我會(huì)寫(xiě)專(zhuān)門(mén)的文章來(lái)介紹 Readability 及其與 Python 的對(duì)接使用。
首先我們需要注冊(cè)一個(gè)賬號(hào),它有 15 天的免費(fèi)試用,注冊(cè)之后會(huì)獲得一個(gè) Developer Token,這就是使用 Diffbot 接口服務(wù)的憑證。
接下來(lái)切換到它的測(cè)試頁(yè)面中,鏈接為:https://www.diffbot.com/dev/home/,我們來(lái)測(cè)試一下它的解析效果到底是怎樣的。
這里我們選擇的測(cè)試頁(yè)面就是上文所述的頁(yè)面,鏈接為:https://news.ifeng.com/c/7kQcQG2peWU,API 類(lèi)型選擇 Article API,然后點(diǎn)擊 Test Drive 按鈕,接下來(lái)它就會(huì)出現(xiàn)當(dāng)前頁(yè)面的解析結(jié)果:
這時(shí)候我們可以看到,它幫我們提取出來(lái)了標(biāo)題、發(fā)布時(shí)間、發(fā)布機(jī)構(gòu)、發(fā)布機(jī)構(gòu)鏈接、正文內(nèi)容等等各種結(jié)果。而且目前來(lái)看都十分正確,時(shí)間也自動(dòng)識(shí)別之后做了轉(zhuǎn)碼,是一個(gè)標(biāo)準(zhǔn)的時(shí)間格式。
接下來(lái)我們繼續(xù)下滑,查看還有什么其他的字段,這里我們還可以看到有 html 字段,它和 text 不同的是,它包含了文章內(nèi)容的真實(shí) HTML 代碼,因此圖片也會(huì)包含在里面,如圖所示:
另外最后面還有 images 字段,他以列表形式返回了文章套圖及每一張圖的鏈接,另外還有文章的站點(diǎn)名稱(chēng)、頁(yè)面所用語(yǔ)言等等結(jié)果,如圖所示:
當(dāng)然我們也可以選擇 JSON 格式的返回結(jié)果,其內(nèi)容會(huì)更加豐富,例如圖片還返回了其寬度、高度、圖片描述等等內(nèi)容,另外還有各種其他的結(jié)果如面包屑導(dǎo)航等等結(jié)果,如圖所示:
經(jīng)過(guò)手工核對(duì),發(fā)現(xiàn)其返回的結(jié)果都是完全正確的,準(zhǔn)確率相當(dāng)之高!
所以說(shuō),如果你對(duì)準(zhǔn)確率要求沒(méi)有那么非常非常嚴(yán)苛的情況下,使用 Diffbot 的服務(wù)可以幫助我們快速地提取頁(yè)面中所需的結(jié)果,省去了我們絕大多數(shù)的手工勞動(dòng),可以說(shuō)是非常贊了。
但是,我們也不能總在網(wǎng)頁(yè)上這么試吧。其實(shí) Diffbot 也提供了官方的 API 文檔,讓我們來(lái)一探究竟。
Driffbot 提供了多種 API,如 Analyze API、Article API、Disscussion API 等。
下面我們以 Article API 為例來(lái)說(shuō)明一下它的用法,其官方文檔地址為:https://www.diffbot.com/dev/docs/article/,API 調(diào)用地址為:
https://api.diffbot.com/v3/article
我們可以用 GET 方式來(lái)進(jìn)行請(qǐng)求,其中的 Token 和 URL 都可以以參數(shù)形式傳遞給這個(gè) API,其必備的參數(shù)有:
token:即 Developer Token
url:即要解析的 URL 鏈接
另外它還有幾個(gè)可選參數(shù):
fields:用來(lái)指定返回哪些字段,默認(rèn)已經(jīng)有了一些固定字段,這個(gè)參數(shù)可以指定還可以額外返回哪些可選字段
paging:如果是多頁(yè)文章的話,如果將這個(gè)參數(shù)設(shè)置為 false 則可以禁止多頁(yè)內(nèi)容拼接
maxTags:可以設(shè)置返回的 Tag 最大數(shù)量,默認(rèn)是 10 個(gè)
tagConfidence:設(shè)置置信度的閾值,超過(guò)這個(gè)值的 Tag 才會(huì)被返回,默認(rèn)是 0.5
discussion:如果將這個(gè)參數(shù)設(shè)置為 false,那么就不會(huì)解析評(píng)論內(nèi)容
timeout:在解析的時(shí)候等待的最長(zhǎng)時(shí)間,默認(rèn)是 30 秒
callback:為 JSONP 類(lèi)型的請(qǐng)求而設(shè)計(jì)的回調(diào)
這里大家可能關(guān)注的就是 fields 字段了,在這里我專(zhuān)門(mén)做了一下梳理,首先是一些固定字段:
type:文本的類(lèi)型,這里就是 article 了
title:文章的標(biāo)題
text:文章的純文本內(nèi)容,如果是分段內(nèi)容,那么其中會(huì)以換行符來(lái)分隔
html:提取結(jié)果的 HTML 內(nèi)容
date:文章的發(fā)布時(shí)間,其格式為 RFC 1123
estimatedDate:如果日期時(shí)間不太明確,會(huì)返回一個(gè)預(yù)估的時(shí)間,如果文章超過(guò)兩天或者沒(méi)有發(fā)布日期,那么這個(gè)字段就不會(huì)返回
author:作者
authorUrl:作者的鏈接
discussion:評(píng)論內(nèi)容,和 Disscussion API 返回結(jié)果一樣
humanLanguage:語(yǔ)言類(lèi)型,如英文還是中文等
numPages:如果文章是多頁(yè)的,這個(gè)參數(shù)會(huì)控制最大的翻頁(yè)拼接數(shù)目
nextPages:如果文章是多頁(yè)的,這個(gè)參數(shù)可以指定文章后續(xù)鏈接
siteName:站點(diǎn)名稱(chēng)
publisherRegion:文章發(fā)布地區(qū)
publisherCountry:文章發(fā)布國(guó)家
pageUrl:文章鏈接
resolvedPageUrl:如果文章是從 pageUrl 重定向過(guò)來(lái)的,則返回此內(nèi)容
tags:文章的標(biāo)簽或者文章包含的實(shí)體,根據(jù)自然語(yǔ)言處理技術(shù)和 DBpedia 計(jì)算生成,是一個(gè)列表,里面又包含了子字段:
label:標(biāo)簽名
count:標(biāo)簽出現(xiàn)的次數(shù)
score:標(biāo)簽置信度
rdfTypes:如果實(shí)體可以由多個(gè)資源表示,那么則返回相關(guān)的 URL
type:類(lèi)型
uri:Diffbot Knowledge Graph 中的實(shí)體鏈接
images:文章中包含的圖片
videos:文章中包含的視頻
breadcrumb:面包屑導(dǎo)航信息
diffbotUri:Diffbot 內(nèi)部的 URL 鏈接
以上的預(yù)定字段就是如果可以返回那就會(huì)返回的字段,是不能定制化配置的,另外我們還可以通過(guò) fields 參數(shù)來(lái)指定擴(kuò)展如下可選字段:
quotes:引用信息
sentiment:文章的情感值,-1 到 1 之間
links:所有超鏈接的頂級(jí)鏈接
querystring:請(qǐng)求的參數(shù)列表
好,以上便是這個(gè) API 的用法,大家可以申請(qǐng)之后使用這個(gè) API 來(lái)做智能化解析了。
下面我們用一個(gè)實(shí)例來(lái)看一下這個(gè) API 的用法,代碼如下:
import requests, json
url = 'https://api.diffbot.com/v3/article'
params = {
'token': '77b41f6fbb24495113d52836528fa',
'url': 'https://news.ifeng.com/c/7kQcQG2peWU',
'fields': 'meta'
}
response = requests.get(url, params=params)
print(json.dumps(response.json(), indent=2, ensure_ascii=False))
這里首先定義了 API 的鏈接,然后指定了 params 參數(shù),即 GET 請(qǐng)求參數(shù)。
參數(shù)中包含了必選的 token、url 字段,也設(shè)置了可選的 fields 字段,其中 fields 為可選的擴(kuò)展字段 meta 標(biāo)簽。
我們來(lái)看下運(yùn)行結(jié)果,結(jié)果如下:
{
"request": {
"pageUrl": "https://news.ifeng.com/c/7kQcQG2peWU",
"api": "article",
"fields": "sentiment, meta",
"version": 3
},
"objects": [
{
"date": "Wed, 20 Feb 2019 02:26:00 GMT",
"images": [
{
"naturalHeight": 460,
"width": 640,
"diffbotUri": "image|3|-1139316034",
"url": "http://e0.ifengimg.com/02/2019/0219/1731DC8A29EB2219C7F2773CF9CF319B3503D0A1_size382_w690_h560.png",
"naturalWidth": 690,
"primary": true,
"height": 426
},
// ...
],
"author": "中國(guó)新聞網(wǎng)",
"estimatedDate": "Wed, 20 Feb 2019 06:47:52 GMT",
"diffbotUri": "article|3|1591137208",
"siteName": "ifeng.com",
"type": "article",
"title": "故宮,你低調(diào)點(diǎn)!故宮:不,實(shí)力已不允許我繼續(xù)低調(diào)",
"breadcrumb": [
{
"link": "https://news.ifeng.com/",
"name": "資訊"
},
{
"link": "https://news.ifeng.com/shanklist/3-35197-/",
"name": "大陸"
}
],
"humanLanguage": "zh",
"meta": {
"og": {
"og:time ": "2019-02-20 02:26:00",
"og:image": "https://e0.ifengimg.com/02/2019/0219/1731DC8A29EB2219C7F2773CF9CF319B3503D0A1_size382_w690_h560.png",
"og:category ": "鳳凰資訊",
"og: webtype": "news",
"og:title": "故宮,你低調(diào)點(diǎn)!故宮:不,實(shí)力已不允許我繼續(xù)低調(diào)",
"og:url": "https://news.ifeng.com/c/7kQcQG2peWU",
"og:description": " “我的名字叫紫禁城,快要600歲了,這上元的夜啊,總是讓我沉醉,這么久了卻從未停止?!?nbsp; “重"
},
"referrer": "always",
"description": " “我的名字叫紫禁城,快要600歲了,這上元的夜啊,總是讓我沉醉,這么久了卻從未停止?!?nbsp; “重",
"keywords": "故宮 紫禁城 故宮博物院 燈光 元宵節(jié) 博物館 一票難求 元之 中新社 午門(mén) 杜洋 藏品 文化 皇帝 清明上河圖 元宵 千里江山圖卷 中英北京條約 中法北京條約 天津條約",
"title": "故宮,你低調(diào)點(diǎn)!故宮:不,實(shí)力已不允許我繼續(xù)低調(diào)_鳳凰資訊"
},
"authorUrl": "https://feng.ifeng.com/author/308904",
"pageUrl": "https://news.ifeng.com/c/7kQcQG2peWU",
"html": "<p>“我的名字叫紫禁城,快要600歲了,這上元的夜啊,總是讓我沉醉,這么久了卻從未停止。...</blockquote> </blockquote>",
"text": "“我的名字叫紫禁城,快要600歲了,這上元的夜啊,總是讓我沉醉,這么久了卻從未停止。”\n“...",
"authors": [
{
"name": "中國(guó)新聞網(wǎng)",
"link": "https://feng.ifeng.com/author/308904"
}
]
}
]
}
可見(jiàn)其返回了如上的內(nèi)容,是一個(gè)完整的 JSON 格式,其中包含了標(biāo)題、正文、發(fā)布時(shí)間等等各種內(nèi)容。
可見(jiàn),不需要我們配置任何提取規(guī)則,我們就可以完成頁(yè)面的分析和抓取,得來(lái)全不費(fèi)功夫。
另外 Diffbot 還提供了幾乎所有語(yǔ)言的 SDK 支持,我們也可以使用 SDK 來(lái)實(shí)現(xiàn)如上功能,鏈接為:https://www.diffbot.com/dev/docs/libraries/,如果大家使用 Python 的話,可以直接使用 Python 的 SDK 即可,Python 的 SDK 鏈接為:https://github.com/diffbot/diffbot-python-client。
這個(gè)庫(kù)并沒(méi)有發(fā)布到 PyPi,需要自己下載并導(dǎo)入使用,另外這個(gè)庫(kù)是使用 Python 2 寫(xiě)的,其實(shí)本質(zhì)上就是調(diào)用了 requests 庫(kù),如果大家感興趣的話可以看一下。
下面是一個(gè)調(diào)用示例:
from client import DiffbotClient,DiffbotCrawl
diffbot = DiffbotClient()
token = 'your_token'
url = 'http://shichuan.github.io/javascript-patterns/'
api = 'article'
response = diffbot.request(url, token, api)
通過(guò)這行代碼我們就可以通過(guò)調(diào)用 Article API 來(lái)分析我們想要的 URL 鏈接了,返回結(jié)果是類(lèi)似的。
具體的用法大家直接看下它的源碼注釋就一目了然了,還是很清楚的。
好,以上便是對(duì)智能化提取頁(yè)面原理的基本介紹以及對(duì) Diffbot 的用法的講解,后面我會(huì)繼續(xù)介紹其他的智能化解析方法以及一些相關(guān)實(shí)戰(zhàn),希望大家可以多多關(guān)注。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。