API抓取第三方資料

1-1念恍、網(wǎng)絡(luò)爬蟲(web crawler)

如果想要抓天氣資訊,在Terminal里面執(zhí)行:
gem install rest-client
成功會看到Successfully installed rest-client-2.0.1的信息瞬浓。

接著開一個irb實驗看看胳赌,執(zhí)行irb后逃呼,一行行輸入以下代碼:

require 'rest-client'
response = RestClient.get "http://www.weather.com.cn/weather1d/101010100.shtml"
response.body

資料顯示很亂,因為回傳的內(nèi)容是HTML給瀏覽器顯示的岗憋,我們只看氣溫:

require 'nokogiri'
doc = Nokogiri::HTML.parse(response.body)
doc.css(".today .tem").map{ |x| x.text }  # 得到 ["\n13°C\n", "\n2°C\n", "\n"] 

透過Nokogiri這個庫我們解析HTML,透過CSS selector從文件中對比出想要的資訊锚贱。這就是網(wǎng)絡(luò)爬蟲(web crawler), 但這樣很辛苦仔戈,程式容易壞掉。所以用API存取資料拧廊。


1-2监徘、什么是API?

API(Application Programming Interface)講的就是程序跟程序的接口,定義接口叫什么名字吧碾、要傳什么參數(shù)進去凰盔、它會回傳什么東西回來、可能會發(fā)生的錯誤等等倦春。

在寫 Ruby 程序的時候户敬,我們會呼叫庫(library)的方法,這時候 API 指的是方法(method)的名字睁本、參數(shù)尿庐、回傳值等等,例如 Ruby Hash 的 API 文件呢堰。
對 Web 應(yīng)用來說抄瑟,客戶端和服務(wù)器之間是用 HTTP 通訊協(xié)定:抓資料的一方叫做 Client 客戶端,送出 HTTP request枉疼,在之前的課程中锐借,這個角色就是瀏覽器问麸,在這堂課中,我們會自己撰寫 Ruby 程序作為客戶端钞翔⊙下簦回傳資料的一方叫做 server 服務(wù)端,回傳 HTTP response布轿,服務(wù)端例如我們已經(jīng)學過的 Ruby on Rails哮笆。

Web 應(yīng)用的 API 就是在定義網(wǎng)址 URL 長怎樣、請求的 HTTP 方法(GET或POST等)是什么汰扭、要傳什么參數(shù)過去稠肘、返回的資料格式又是什么。這份教材要示范的萝毛,就是屬于這一種 API项阴。
其中返回格式最常用的是 JSON 或 XML。這兩種是最常見的資料交換格式笆包,專門用來讓機器之間交換資料用的环揽,只有純粹的資料,不像 HTML 有沒有雜七雜八的排版資訊庵佣。一個 JSON 字串例如:
{ "id": 123, "name": "foobar"}

就是在描述一個哈希歉胶,不同程式語言都可以產(chǎn)生和解析這一個字串,讓我們在 irb
中實驗看看巴粪,我們可以把任意的 Ruby 資料通今,轉(zhuǎn)成 JSON 字串:
require 'json'{ :id => 123, :name => "foobar" }.to_json # => "{\"id\":123,\"name\":\"foobar\"}"

你可以再開另一個 Terminal,再進入 irb
肛根,把剛剛的 JSON 字串貼上來
require 'json'JSON.parse( "{\"id\":123,\"name\":\"foobar\"}" ) # => {"id"=>123, "name"=>"foobar"}

這樣就又把 JSON 字串又轉(zhuǎn)回 Ruby 了辫塌。
所以如果能有 Web API 提供 JSON 資料的話,就可以透過程式語言直接解析拿到純粹的資料派哲,非常方便又可靠璃氢。


1-3、注冊聚合數(shù)據(jù)狮辽,拿到API Key

讓我們找找看有沒有提供天氣 API 的服務(wù)商一也,找到了由聚合數(shù)據(jù)提供的 全國天氣預(yù)報 API,請先注冊喉脖,然后申請?zhí)鞖忸A(yù)報數(shù)據(jù):

然后就可以拿到 API Key椰苟,請記下這個憑證,等會呼叫 API 時會用到:

API 服務(wù)商都會要求你先注冊树叽,然后呼叫 API 時需要帶著這個 API Key 參數(shù)舆蝴,用來記錄呼叫者和使用次數(shù)。

1-4、安裝Postman進行初步測試

要怎么對 Web API 進行手動的測試呢? 我們來裝一個 Chrome Extension 叫做 Postman洁仗,這就是一個萬用的表單工具层皱。
首先進入 Chrome 選單上的 Windows > Extensions,然后安裝 Postman

透過這個工具赠潦,我們可以指定 URL 地址叫胖、HTTP 方法和要傳遞的參數(shù)。讓我們實驗看她奥。根據(jù) 全國天氣預(yù)報 文檔 的說明瓮增,讓我們試試看來抓「支持城市列表」

在 Postman 中輸入接口的 URL 地址和參數(shù):

點擊 Send 就可以看到結(jié)果了:

1-5、用rest-client抓下來看

接下來實驗 Ruby 客戶端哩俭,用 Ruby 程序來抓取上述的資料绷跑。
進入 irb

require 'rest-client'require 'json'response = RestClient.get "http://v.juhe.cn/weather/citys", :params => { :key => "請換成你的Key" } data = JSON.parse(response.body)

這個 data 變量就是單純的 Ruby 哈希資料了,是全部的城市凡资。接下來我們可以觀察一下這個資料的樣子砸捏,文檔上面也有范例:
data.keys # => ["resultcode", "reason", "result", "error_code"]data["result"][0] # => {"id"=>"1", "province"=>"北京", "city"=>"北京", "district"=>"北京"}

2-2初始專案,建立City Model

在 Terminal 下輸入:

 rails new api_exercise
 cd api_exercise
 git init 

編輯 Gemfile 加上gem 'rest-client'隙赁,然后執(zhí)行 bundle

執(zhí)行 rails g model city

編輯 city 的 migration 檔案 db/migrate/201703XXXXXXXX_create_cities.rb

 class CreateCities < ActiveRecord::Migration[5.0]
   def change
     create_table :cities do |t|
+      t.string :juhe_id
+      t.string :province
+      t.string :city
+      t.string :district
+      t.string :current_temp
       t.timestamps
     end
+    add_index :cities, :juhe_id
   end
 end

然后rake db:migrate

2-3 抓取區(qū)城市資料儲存下來

新增 lib/tasks/dev.rake垦藏,放在這個目錄下的 rake 檔案是用來編寫任務(wù)腳本,讓我們在 Terminal 中可以執(zhí)行它:

lib/tasks/dev.rake

namespace :dev do
  task :fetch_city => :environment do
    puts "Fetch city data..."
    response = RestClient.get "http://v.juhe.cn/weather/citys", :params => { :key => "你申請的key放這里" }
    data = JSON.parse(response.body)
    data["result"].each do |c|
      existing_city = City.find_by_juhe_id( c["id"] )
      if existing_city.nil?
        City.create!( :juhe_id => c["id"], :province => c["province"],
                      :city => c["city"], :district => c["district"] )
      end
    end
    puts "Total: #{City.count} cities"
  end
end

執(zhí)行 bundle exec rake dev:fetch_city就會執(zhí)行這個任務(wù)鸳谜,把 2574 筆城市存進數(shù)據(jù)庫。

juhe_id 這個欄位的目的是存下第三方那邊的 id式廷,這樣我們之后在更新數(shù)據(jù)的時候咐扭,就可以進行比對、避免重復(fù)新增滑废。


2-4 在畫面顯示出來

編輯 config/routes.rb
新增一行 ·resources :cities·

config/routes.rb

Rails.application.routes.draw do+ resources :cities end 

執(zhí)行rails g controller cities

編輯 app/controllers/cities_controller.rb

app/controllers/cities_controller.rb

class CitiesController < ApplicationController
+ def index
+ @cities = City.all
+ end 
end

新增 app/views/cities/index.html.erb

app/views/cities/index.html.erb

<table class="table">
<tr>
  <th>Juhe ID</th>
  <th>Province</th>
  <th>City</th>
  <th>District</th>
  <th>Temp</th>
</tr>
<% @cities.each do |city| %>
  <tr>
    <td><%= city.juhe_id %></td>
    <td><%= city.province %></td>
    <td><%= city.city %></td>
    <td><%= city.district %></td>
    <td></td>
  </tr>
<% end %>
</table>

啟動服務(wù)器rails s
蝗肪,打開瀏覽器 http://localhost:3000/cities
就會看到城市資料了。

這里省略了安裝 Bootstrap 的步驟蠕趁,如果沒安裝也沒關(guān)系薛闪,畫面會有差異而已。

2-5 更新城市天氣

我們希望存下來當前溫度俺陋。根據(jù) 文檔 的說明豁延,可以找到氣溫的 API 說明。
首先修改 config/routes.rb
腊状,新增一個操作:

config/routes.rb
- resources :cities+ resources :cities do+ member do+ post :update_temp+ end+ end

在畫面上放一個按鈕诱咏,編輯 app/views/cities/index.html.erb

- <td></td>
+ <td>
+   <%= city.current_temp %>
+   <%= link_to "更新溫度", update_temp_city_path(city), :method => :post %>
+ </td>

新增一個 action,編輯 app/controller/cities_controller.rb

def update_temp
    city = City.find(params[:id])
    response = RestClient.get "http://v.juhe.cn/weather/index", 
                              :params => { :cityname => city.juhe_id, :key => "你申請的key放這里" }
    data = JSON.parse(response.body)
    city.update( :current_temp => data["result"]["sk"]["temp"] )
    redirect_to cities_path
end

這樣點擊「更新溫度」后缴挖,就會更新氣溫了袋狞。

2-6保護API Key

在串接第三方應(yīng)用時,第三方的 API Key 我們不希望寫死在程式碼里面,一來是因為我們不想把這些敏感的 keys 放到版本控制系統(tǒng)里面苟鸯。二來是因為將來布署的時候同蜻,在 production 環(huán)境下,api key 會另外申請一個不一樣早处,因此我們希望容易抽換湾蔓。

新增 config/juhe.yml 作為設(shè)定檔,內(nèi)容如下:

 development:
  api_key: "你申請的key放這里"
production:
  api_key: "之后布署上production的話陕赃,key放這里"

編輯 config/application.rb卵蛉,在最下面插入一行:

# (略)
JUHE_CONFIG = Rails.application.config_for(:juhe)

編輯 app/controller/cities_controller.rblib/tasks/dev.rake,把 "你申請的key放這里" 置換成 JUHE_CONFIG["api_key"] 即可么库。

(以上操作完成后要重啟rails s才會生效)

要注意:

  • YAML 格式使用空白縮排來表達資料的階層關(guān)系傻丝,請務(wù)必縮排整齊
  • YAML 格式會區(qū)分數(shù)字和字串,例如 01234 會看成 1234诉儒,如果要確保被解析成字串葡缰,請加上引號,例如"01234"
  • 讀出來的 Hash 是用字串 key忱反,不是 symbol key泛释。是 JUHE_CONFIG["api_key"]而不是 JUHE_CONFIG[:api_key]
    接著我們要告訴 Git 不要 commit 這個檔案,這樣就不用擔心 git push 會把 api key 洩漏出去温算。

編輯.gitignore怜校,插入一行

config/juhe.yml

依照慣例,你可以復(fù)制一個 juhe.yml.example 檔案放進版本控制系統(tǒng)里面注竿,這可以給你同事當作范例參考茄茁,內(nèi)容例如:

config/juhe.yml.example

development:
  api_key: "<juhe api key>"

一些數(shù)據(jù)網(wǎng)站:
https://www.juhe.cn
http://apistore.baidu.com
https://www.haoduoshuju.com
http://www.pm25.in/api_doc
https://github.com/toddmotto/public-apis
http://opendatachina.com/en/projects/
END

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市巩割,隨后出現(xiàn)的幾起案子裙顽,更是在濱河造成了極大的恐慌,老刑警劉巖宣谈,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件愈犹,死亡現(xiàn)場離奇詭異,居然都是意外死亡闻丑,警方通過查閱死者的電腦和手機漩怎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嗦嗡,“玉大人扬卷,你說我怎么就攤上這事∷崆眨” “怎么了怪得?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵咱枉,是天一觀的道長。 經(jīng)常有香客問我徒恋,道長蚕断,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任入挣,我火速辦了婚禮亿乳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘径筏。我一直安慰自己葛假,他們只是感情好,可當我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布滋恬。 她就那樣靜靜地躺著聊训,像睡著了一般。 火紅的嫁衣襯著肌膚如雪恢氯。 梳的紋絲不亂的頭發(fā)上带斑,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天,我揣著相機與錄音勋拟,去河邊找鬼勋磕。 笑死,一個胖子當著我的面吹牛敢靡,可吹牛的內(nèi)容都是我干的挂滓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼啸胧,長吁一口氣:“原來是場噩夢啊……” “哼赶站!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起吓揪,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤亲怠,失蹤者是張志新(化名)和其女友劉穎所计,沒想到半個月后柠辞,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡主胧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年叭首,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片踪栋。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡焙格,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出夷都,到底是詐尸還是另有隱情眷唉,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站冬阳,受9級特大地震影響蛤虐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜肝陪,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一驳庭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧氯窍,春花似錦饲常、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至熊楼,卻和暖如春霹娄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鲫骗。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工犬耻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人执泰。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓枕磁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親术吝。 傳聞我的和親對象是個殘疾皇子计济,可洞房花燭夜當晚...
    茶點故事閱讀 44,947評論 2 355

推薦閱讀更多精彩內(nèi)容