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