使用Ruby程式實現web資訊抓取的教程_ruby專題

來源:互聯網
上載者:User

網站不再單單迎合人類讀者。許多網站現在支援一些 API,這些 API 使電腦程式能夠擷取資訊。螢幕抓取 —— 將 HTML 頁面解析為更容易理解的表單的省時技術 — 仍然很方便。但使用 API 簡化 Web 資料提取的機會在快速增多。根據 ProgrammableWeb 的資訊,在本文發表時,已存在 10,000 多個網站 API — 在過去的 15 個月中增加了 3,000 個。(ProgrammableWeb 本身提供了一個 API,可從其目錄中搜尋和檢索 API、mashup、成員概要檔案和其他資料。)

本文首先介紹現代的 Web 抓取並將它與 API 方法進行比較。然後通過 Ruby 樣本,展示如何使用 API 從一些流行的 Web 屬性中提取結構化資訊。您需要基本理解 Ruby 語言、具象狀態傳輸 (REST),以及 JavaScript 物件標記法 (JSON) 和 XML 概念。
抓取與 API

現在已有多種抓取解決方案。其中一些將 HTML 轉換為其他格式,比如 JSON,這樣提取想要的內容會更加簡單。其他解決方案讀取 HTML,您可將內容定義為 HTML 分層結構的一個函數,其中的資料已加了標記。一種此類解決方案是 Nokogiri,它支援使用 Ruby 語言解析 HTML 和 XML 文檔。其他開源抓取工具包括用於 JavaScript 的 pjscrape 和用於 Python 的 Beautiful Soup。pjscrape 實現一個命令列工具來抓取完全呈現的頁面,包括 JavaScript 內容。Beautiful Soup 完全整合到 Python 2 和 3 環境中。

假設您希望使用抓取功能和 Nokogiri 來識別 CrunchBase 所報告的 IBM 員工數量。第一步是理解 CrunchBase 上列出了 IBM 員工數量的特定 HTML 頁面的標記。圖 1 顯示了在 Mozilla Firefox 中的 Firebug 工具中開啟的此頁面。該圖的上半部分顯示了所呈現的 HTML,下半部分顯示了感興趣部分的 HTML 原始碼。

清單 1 中的 Ruby 指令碼使用 Nokogiri 從圖 1 中的網頁抓取員工數量。
清單 1. 使用 Nokogiri 解析 HTML (parse.rb)

#!/usr/bin/env rubyrequire 'rubygems'require 'nokogiri'require 'open-uri'# Define the URL with the argument passed by the useruri = "http://www.crunchbase.com/company/#{ARGV[0]}"# Use Nokogiri to get the documentdoc = Nokogiri::HTML(open(uri))# Find the link of interestlink = doc.search('tr span[1]')# Emit the content associated with that linkputs link[0].content

在 Firebug 顯示的 HTML 原始碼中(如 圖 1 所示),您可看到感興趣的資料(員工數量)嵌入在一個 HTML 唯一 ID <span> 標記內。還可看到 <span id="num_employees"> 標記是兩個 <span> ID 標記中的第一個。所以,清單 1 中的最後兩個指令是,使用 link = doc.search('tr span[1]') 請求第一個 <span> 標記,然後使用 puts link[0].content 發出這個已解析連結的內容。

CrunchBase 還公開了一個 REST API,它能夠訪問的資料比通過抓取功能訪問的資料要多得多。清單 2 顯示了如何使用該 API 從 CrunchBase 網站提取公司的員工數。
清單 2. 結合使用 CrunchBase REST API 和 JSON 解析 (api.rb)

#!/usr/bin/env rubyrequire 'rubygems'require 'json'require 'net/http'# Define the URL with the argument passed by the useruri = "http://api.crunchbase.com/v/1/company/#{ARGV[0]}.js"# Perform the HTTP GET request, and return the responseresp = Net::HTTP.get_response(URI.parse(uri))# Parse the JSON from the response bodyjresp = JSON.parse(resp.body)# Emit the content of interestputs jresp['number_of_employees']

在清單 2 中,您定義了一個 URL(公司名稱作為指令碼參數傳入)。然後使用 HTTP 類發出一個 GET 請求並返迴響應。響應被解析為一個 JSON 對象,您可通過一個 Ruby 資料結構引用感興趣的資料項目。

清單 3 中的控制台會話顯示了運行 清單 1 中的抓取指令碼和 清單 2 中基於 API 的指令碼的結果。
清單 3. 示範抓取和 API 方法

$ ./parse.rb ibm388,000$ ./api.rb ibm388000$ ./parse.rb cisco63,000$ ./api.rb cisco63000$ ./parse.rb paypal300,000$ ./api.rb paypal300000$

抓取指令碼運行時,您接收一個格式化的計數,而 API 指令碼會產生一個原始整數。如清單 3 所示,您可推廣每種指令碼的使用,從 CrunchBase 跟蹤的其他公司請求獲得員工數。每種方法提供的 URL 的一般結構使這種通用性成為可能。

那麼,我們使用 API 方法能獲得什嗎?對於抓取,您需要分析 HTML 以理解它的結構並識別要提取的資料。然後使用 Nokogiri 解析 HTML 並擷取感興趣的資料就會很簡單。但是,如果 HTML 文檔的結構發生變化,您可能需要修改指令碼才能正確解析新結構。根據 API 契約,API 方法不存在該問題。API 方法的另一個重要優點是,您可訪問通過介面(通過返回的 JSON 對象)公開的所有資料。通過 HTML 公開且可供人使用的 CrunchBase 資料要少得多。

現在看看如何使用其他一些 API 從 Internet 提取各類資訊,同樣要藉助 Ruby 指令碼。首先看看如何從一個社交網站收集個人資料。然後將看到如何通過其他 API 來源尋找更少的個人資料。

通過 LinkedIn 提取個人資料

LinkedIn 是一個面向專業職業的社交網路網站。它對聯絡其他開發人員,尋找工作,研究一家公司,或者加入一個群組,就有趣的主題進行協作很有用。LinkedIn 還整合了一個Recommendation Engine,可根據您的概要檔案推薦工作和公司。

LinkedIn 使用者可訪問該網站的 REST 和 JavaScript API,從而擷取可通過其人類可讀網站訪問的資訊:聯絡資訊、社交分享流、內容群組、通訊(訊息和聯絡邀請),以及公司和工作資訊。

要使用 LinkedIn API,您必須註冊您的應用程式。註冊後會獲得一個 API 金鑰和秘密秘鑰,以及一個使用者令牌和秘密秘鑰。LinkedIn 使用 OAuth 協議進行身分識別驗證。

執行身分識別驗證後,您可通過存取權杖對象發出 REST 請求。響應是一個典型的 HTTP 響應,所以您可將本文解析為 JSON 對象。然後可迭代該 JSON 對象來提取感興趣的資料。

清單 4 中的 Ruby 指令碼為進行身分識別驗證後的 LinkedIn 使用者提供了要關注的公司推薦和工作建議。
清單 4. 使用 LinkedIn API (lkdin.rb) 查看公司和工作建議

#!/usr/bin/rubyrequire 'rubygems'require 'oauth'require 'json'pquery = "http://api.linkedin.com/v1/people/~?format=json"cquery='http://api.linkedin.com/v1/people/~/suggestions/to-follow/companies?format=json'jquery='http://api.linkedin.com/v1/people/~/suggestions/job-suggestions?format=json' # Fill the keys and secrets you retrieved after registering your appapi_key = 'api key'api_secret = 'api secret'user_token = 'user token'user_secret = 'user secret' # Specify LinkedIn API endpointconfiguration = { :site => 'https://api.linkedin.com' } # Use the API key and secret to instantiate consumer objectconsumer = OAuth::Consumer.new(api_key, api_secret, configuration) # Use the developer token and secret to instantiate access token objectaccess_token = OAuth::AccessToken.new(consumer, user_token, user_secret)# Get the username for this profileresponse = access_token.get(pquery)jresp = JSON.parse(response.body)myName = "#{jresp['firstName']} #{jresp['lastName']}"puts "\nSuggested companies to follow for #{myName}"# Get the suggested companies to followresponse = access_token.get(cquery)jresp = JSON.parse(response.body)# Iterate through each and display the company namejresp['values'].each do | company |  puts " #{company['name']}"end# Get the job suggestionsresponse = access_token.get(jquery)jresp = JSON.parse(response.body)puts "\nSuggested jobs for #{myName}"# Iterate through each suggested job and print the company namejresp['jobs']['values'].each do | job |  puts " #{job['company']['name']} in #{job['locationDescription']}"endputs "\n"

清單 5 中的控制台會話顯示了運行 清單 4 中的 Ruby 指令碼的輸出。指令碼中對 LinkedIn API 的 3 次獨立調用有不同的輸出結果(一個用於身分識別驗證,其他兩個分別用於公司建議和工作建議連結)。
清單 5. 示範 LinkedIn Ruby 指令碼

$ ./lkdin.rbSuggested companies to follow for M. Tim Jones Open Kernel Labs, Inc. Linaro Wind River DDC-I Linsyssoft Technologies Kalray American Megatrends JetHead Development Evidence Srl Aizyc TechnologySuggested jobs for M. Tim Jones Kozio in Greater Denver Area Samsung Semiconductor Inc in San Jose, CA Terran Systems in Sunnyvale, CA Magnum Semiconductor in San Francisco Bay Area RGB Spectrum in Alameda, CA Aptina in San Francisco Bay Area CyberCoders in San Francisco, CA CyberCoders in Alameda, CA SanDisk in Longmont, CO SanDisk in Longmont, CO$

可將 LinkedIn API 與任何提供了 OAuth 支援的語言結合使用。

使用 Yelp API 檢索業務資料

Yelp 公開了一個富 REST API 來執行企業搜尋,包含評分、評論和地理搜尋(地段、城市、地理編碼)。使用 Yelp API,您可搜尋一種給定類型的企業(比如 “飯店”)並將搜尋限制在一個地理邊界內;一個地理座標附近;或者一個鄰居、地址或城市附近。JSON 響應包含了與條件匹配的企業的大量相關資訊,包括地址資訊、距離、評分、交易,以及其他類型的資訊(比如該企業的圖片、移動格式資訊等)的 URL。

像 LinkedIn 一樣,Yelp 使用 OAuth 執行身分識別驗證,所以您必須向 Yelp 註冊才能通過該 API 獲得一組用於身分識別驗證的憑據。指令碼完成身分識別驗證後,可構造一個基於 REST 的 URL 請求。在清單 6 中,我寫入程式碼了一個針對科羅拉多州 Boulder 的飯店請求。響應本文被解析到一個 JSON 對象中並進行迭代,從而發出想要的資訊。注意,我排除了已關閉的企業。
清單 6. 使用 Yelp API (yelp.rb) 檢索企業資料

#!/usr/bin/rubyrequire 'rubygems'require 'oauth'require 'json'consumer_key = 'your consumer key'consumer_secret = 'your consumer secret'token = 'your token'token_secret = 'your token secret'api_host = 'http://api.yelp.com'consumer = OAuth::Consumer.new(consumer_key, consumer_secret, {:site => api_host})access_token = OAuth::AccessToken.new(consumer, token, token_secret)path = "/v2/search?term=restaurants&location=Boulder,CO"jresp = JSON.parse(access_token.get(path).body)jresp['businesses'].each do | business |  if business['is_closed'] == false   printf("%-32s %10s %3d %1.1f\n",         business['name'], business['phone'],         business['review_count'], business['rating'])  endend

清單 7 中的控制台會話顯示了運行 清單 6 指令碼的樣本輸出。為了簡單一些,我只顯示了所返回的前面一組企業,而不是支援該 API 的限制/位移特性(以執行多個調用來檢索整個列表)。這段樣本輸出顯示了企業名稱、電話號碼、收到的評論數和平均評分。
清單 7. 示範 Yelp API Ruby 指令碼

$ ./yelp.rbFrasca Food and Wine       3034426966 189 4.5John's Restaurant         3034445232  51 4.5Leaf Vegetarian Restaurant    3034421485 144 4.0Nepal Cuisine           3035545828  65 4.5Black Cat Bistro         3034445500  72 4.0The Mediterranean Restaurant   3034445335 306 4.0Arugula Bar E Ristorante     3034435100  48 4.0Ras Kassa's Ethiopia Restaurant  3034472919 101 4.0L'Atelier             3034427233  58 4.0Bombay Bistro           3034444721  87 4.0Brasserie Ten Ten         3039981010 200 4.0Flagstaff House          3034424640  86 4.5Pearl Street Mall         3034493774  77 4.0Gurkhas on the Hill        3034431355  19 4.0The Kitchen            3035445973 274 4.0Chez Thuy Restaurant       3034421700  99 3.5Il Pastaio            3034479572 113 4.53 Margaritas           3039981234  11 3.5Q's Restaurant          3034424880  65 4.0Julia's Kitchen                 8 5.0$

Yelp 提供了一個具有出色文檔的 API,以及資料描述、樣本、錯誤處理等。儘管 Yelp API 很有用,但它的使用有一定的限制。作為軟體原始開發人員,您每天最多可執行 100 次 API 呼叫,出於測試用途可執行 1,000 次調用。如果您的應用程式滿足 Yelp 的顯示需求,每天可執行 10,000 次調用(也可能執行更多次)。

包含一個簡單 mashup 的域位置

下一個樣本將兩段原始碼串連起來,以產生資訊。在本例中,您要將一個 Web 網域名稱轉換為它的一般地理位置。清單 8 中的 Ruby 指令碼使用 Linux? host 命令和 OpenCrypt IP Location API Service 來檢索位置資訊。
清單 8. 檢索 Web 域的位置資訊

#!/usr/bin/env rubyrequire 'net/http'aggr = ""key = 'your api key here'# Get the IP address for the domain using the 'host' commandIO.popen("host #{ARGV[0]}") { | line | until line.eof?  aggr += line.gets end}# Find the IP address in the response from the 'host' commandpattern = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/if m = pattern.match(aggr)  uri = "http://api.opencrypt.com/ip/?IP=#{m[0]}&key=#{key}"  resp = Net::HTTP.get_response(URI.parse(uri))  puts resp.bodyend

在清單 8 中,您首先使用本地的 host 命令將網域名稱轉換為 IP 位址。(host 命令本身使用一個內部 API 和 DNS 解析將網域名稱解析為 IP 位址。)您使用一個簡單的Regex(和 match 方法)從 host 命令輸出中解析 IP 位址。有了 IP 位址,就可使用 OpenCrypt 上的 IP 位置服務來檢索一般地理位置資訊。OpenCrypt API 允許您執行最多 50,000 次免費 API 呼叫。

OpenCrypt API 呼叫很簡單:您構造的 URL 包含您要定位的 IP 位址和 OpenCrypt 註冊過程提供給您的密鑰。HTTP 響應本文包含 IP 位址、國家代碼和國家名稱。

清單 9 中的控制台會話顯示了兩個樣本網域名稱的輸出。
清單 9. 使用簡單的域位置指令碼

$ ./where.rb www.baynet.ne.jpIP=111.68.239.125CC=JPCN=Japan$ ./where.rb www.pravda.ruIP=212.76.137.2CC=RUCN=Russian Federation$

Google API 查詢

Web API 方面一個無可爭辯的優勝者是 Google。Google 擁有如此多的 API,以至於它提供了另一個 API 來查詢它們。通過 Google API Discovery Service,您可列出 Google 提供的可用 API 並提取它們的中繼資料。儘管與大部分 Google API 的互動需要進行身分識別驗證,但您可通過一個安全通訊端串連訪問查詢 API。出於此原因,清單 10 使用 Ruby 的 https 類來構造與安全連接埠的串連。已定義的 URL 指定了 REST 請求,而且響應採用了 JSON 編碼。迭代響應並發出一小部分首選的 API 資料。
清單 10. 使用 Google API Discovery Service (gdir.rb) 列出 Google API

#!/usr/bin/rubyrequire 'rubygems'require 'net/https'require 'json'url = 'https://www.googleapis.com/discovery/v1/apis'uri = URI.parse(url)# Set up a connection to the Google API Servicehttp = Net::HTTP.new( uri.host, 443 )http.use_ssl = truehttp.verify_mode = OpenSSL::SSL::VERIFY_NONE# Connect to the servicereq = Net::HTTP::Get.new(uri.request_uri)resp = http.request(req)# Get the JSON representationjresp = JSON.parse(resp.body)# Iterate through the API Listjresp['items'].each do | item | if item['preferred'] == true  name = item['name']  title = item['title']  link = item['discoveryLink']  printf("%-17s %-34s %-20s\n", name, title, link) endend

清單 11 中的控制台會話顯示了運行清單 10 中指令碼得到的響應樣本。
清單 11. 使用簡單的 Google 目錄服務 Ruby 指令碼

$ ./gdir.rbadexchangebuyer  Ad Exchange Buyer API       ./apis/adexchangebuyer/v1.1/restadsense      AdSense Management API       ./apis/adsense/v1.1/restadsensehost    AdSense Host API          ./apis/adsensehost/v4.1/restanalytics     Google Analytics API        ./apis/analytics/v3/restandroidpublisher Google Play Android Developer API ./apis/androidpublisher/v1/restaudit       Enterprise Audit API        ./apis/audit/v1/restbigquery     BigQuery API            ./apis/bigquery/v2/restblogger      Blogger API            ./apis/blogger/v3/restbooks       Books API             ./apis/books/v1/restcalendar     Calendar API            ./apis/calendar/v3/restcompute      Compute Engine API         ./apis/compute/v1beta12/restcoordinate    Google Maps Coordinate API     ./apis/coordinate/v1/restcustomsearch   CustomSearch API          ./apis/customsearch/v1/restdfareporting   DFA Reporting API         ./apis/dfareporting/v1/restdiscovery     APIs Discovery Service       ./apis/discovery/v1/restdrive       Drive API             ./apis/drive/v2/rest...storage      Cloud Storage API         ./apis/storage/v1beta1/resttaskqueue     TaskQueue API           ./apis/taskqueue/v1beta2/resttasks       Tasks API             ./apis/tasks/v1/resttranslate     Translate API           ./apis/translate/v2/resturlshortener   URL Shortener API         ./apis/urlshortener/v1/restwebfonts     Google Web Fonts Developer API   ./apis/webfonts/v1/restyoutube      YouTube API            ./apis/youtube/v3alpha/restyoutubeAnalytics YouTube Analytics API       ./apis/youtubeAnalytics/v1/rest$

清單 11 中的輸出顯示了 API 名稱、它們的標題,以及進一步分析每個 API 的 URL 路徑。

結束語

本文中的樣本示範了公用 API 在從 Internet 提取資訊方面的強大功能。與 Web 抓取和爬取 (spidering) 相比,Web API 提供了訪問有針對性的特定資訊的能力。Internet 上在不斷創造新價值,這不僅通過使用這些 API 來實現,還通過用新穎的方式組合它們,從而向越來越多的 Web 使用者提供新資料來實現。

但是請記住,使用 API 需要付出一定的代價。限制問題就常讓人抱怨。同樣,可能在不通知您的情況下更改 API 規則這一事實,因此在構建應用程式時必須加以考慮。最近,Twitter 更改了它的 API 來提供 “一種更加一致的體驗”。這一更改對許多可能被視為典型 Twitter 網頁用戶端競爭者的第三方應用程式而言,無疑是一場災難。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.