iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 16
5
Modern Web

只要有心,人人都可以做卡米狗系列 第 16

第十六天:做一個最簡單的爬蟲

一直以來,我們都是用瀏覽器發出 HTTP request,打到我們的 Rails Server,然後我們的 Rails Server 再傳回 HTTP Response

我們還沒有試過用 Rails Server 發出 HTTP request,今天就來試一下。

用 Rails 發 HTTP request

Routes

config/routes.rb 加入

  get '/kamigo/sent_request', to: 'kamigo#sent_request'

Action

app/controllers/kamigo_controller.rb 加入

  def sent_request
    uri = URI('http://localhost:3000/kamigo/response_body')
    response = Net::HTTP.get(uri)
    render plain: response
  end

這是最簡單能發出 Request 的方法,我們先把網址字串轉換成 URI 物件,透過 Net::HTTP.get 這個方法,他會接受一個網址,然後把 ResponseBody 部分以字串的形式傳回。在這段程式裡面我們只能看到傳入網址跟最終結果,我們不能調整 Request HeaderRequest Body,也不能觀察 Response Header

我讓他連去 http://localhost:3000/kamigo/response_body,這是我們昨天作好的東西。

在瀏覽器開啟網址

網址:http://localhost:3000/kamigo/sent_request
開啟網址後會看到:

虎哇花哈哈哈

小黑框的顯示結果

Started GET "/kamigo/sent_request" for 127.0.0.1 at 2018-01-04 01:06:38 +0800
Processing by KamigoController#sent_request as HTML
Started GET "/kamigo/response_body" for 127.0.0.1 at 2018-01-04 01:06:39 +0800
Processing by KamigoController#show_response_body as */*
===這是設定前的response.body:===
  Rendering text template
  Rendered text template (0.0ms)
===這是設定後的response.body:虎哇花哈哈哈===
Completed 200 OK in 344ms (Views: 9.2ms)


  Rendering text template
  Rendered text template (0.0ms)
Completed 200 OK in 1400ms (Views: 2.7ms)

突然想到有個東西還沒講,那就是 Ruby 的函數。

Ruby 的函數

一個函數可以把一個東西變成另一個東西,或者把多個東西變成另一個東西。

舉個例:我們來作一個函數,輸入是一句話,我們要把這句話變成韓文。

函數宣告

  def translate_to_korean(message)
    "#{message}油~"
  end

一個函數裡面可以寫一段程式,最後一行程式的執行結果就會是函數的傳回值。

不管傳入什麼,我們就在後面加上油~

函數呼叫

  translate_to_korean('愛老虎')

你想要使用小括號或者使用空白框住傳入的參數都可以。

  translate_to_korean '愛老虎'

結果

  "愛老虎油~"

成功翻譯成韓文!

把翻譯韓文的功能加入到上面的爬蟲

修改 Action

  def sent_request
    uri = URI('http://localhost:3000/kamigo/response_body')
    response = Net::HTTP.get(uri)
    render plain: translate_to_korean(response)
  end

開啟網頁

壞掉囉,錯誤訊息是 incompatible character encodings: ASCII-8BIT and UTF-8

下面那個深灰色區域是給我們除錯用的,有點類似 irb,我們可以在下面輸入一點東西:

我輸入了 message,看看 message 的值是什麼,結果看到是這樣:

>>  message
=> "\xE8\x99\x8E\xE5\x93\x87\xE8\x8A\xB1\xE5\x93\x88\xE5\x93\x88\xE5\x93\x88"
>>  

因為我們獲得的 response 字串的編碼是 ASCII-8BIT,沒辦法直接跟 UTF-8 編碼的 "油~" 加在一起。

所以修正的方法就是把 response 字串轉碼為 UTF-8 即可:

再次修改 Action

  def sent_request
    uri = URI('http://localhost:3000/kamigo/response_body')
    response = Net::HTTP.get(uri).force_encoding("UTF-8")
    render plain: translate_to_korean(response)
  end

在字串後面寫 .force_encoding("UTF-8") 就可以把編碼轉為 UTF-8 格式了。

再次開啟網頁

虎哇花哈哈哈油~

玩樂時間結束,來作點正事,目前的寫法沒辦法觀察 requestresponse,我們需要能觀察 requestresponse 的寫法。

能觀察 request 和 response 的寫法

修改 Action

  def sent_request
    uri = URI('http://localhost:3000/kamigo/eat')
    http = Net::HTTP.new(uri.host, uri.port)
    http_request = Net::HTTP::Get.new(uri)
    http_response = http.request(http_request)

    render plain: JSON.pretty_generate({
      request_class: request.class,
      response_class: response.class,
      http_request_class: http_request.class,
      http_response_class: http_response.class
    })
  end

越來越複雜了。通常要作到細膩的控制,就要寫比較多的程式碼。

我們先觀察一下這四個物件:requestresponsehttp_requesthttp_response,前兩個是 Rails 內建的,後兩個是我們在 Action 中定義的,為了能夠同時輸出 4 個字串,我用一個雜湊陣列把想看的字串都放進去,然後使用
JSON.pretty_generate 幫我排成比較好閱讀的格式,讓我們來看一下個別對應的類別:

開啟網頁

{
  "request_class": "ActionDispatch::Request",
  "response_class": "ActionDispatch::Response",
  "http_request_class": "Net::HTTP::Get",
  "http_response_class": "Net::HTTPOK"
}

圖解

昨天我們學的是 14,今天學 23,這裡的四個物件,都是屬於不同的類別,所以我們可能需要不同的語法去存取他們。

今天只要了解到這裡就行了。

總結

  • 不是只有瀏覽器才能發出 HTTP Request,網頁伺服器一樣可以發出 HTTP Request
  • 今天學會了宣告函數和呼叫函數的正確觀念。

明天講怎麼讓別人能連到你作的網站。


上一篇
第十五天:從 Rails 認識 HTTP 協定
下一篇
第十七天:怎麼讓別人連到我作好的網站?
系列文
只要有心,人人都可以做卡米狗33
0
cyrc
iT邦新手 5 級 ‧ 2018-01-19 13:43:12

執行request時,偶爾會跳出Net::ReadTimeout,網頁重整後又正常,請問對於這個問題有相關線索或解法嗎:P
https://ithelp.ithome.com.tw/upload/images/20180119/20107520RGAmf9l0Uc.jpg

郭佳甯 iT邦新手 5 級 ‧ 2018-01-19 14:41:28 檢舉

QQ timeout 的話應該觀察被打的 server 的時間花在哪裡,建議看 log。

2
laapnda
iT邦新手 5 級 ‧ 2018-04-22 14:45:34

求救 是我打錯了甚麼嗎
https://ithelp.ithome.com.tw/upload/images/20180422/20109610zVsMNDidBE.jpg
https://ithelp.ithome.com.tw/upload/images/20180422/20109610I7kSRkSSJt.jpg

看更多先前的回應...收起先前的回應...
laapnda iT邦新手 5 級 ‧ 2018-04-24 02:52:50 檢舉

上網爬文後 發現加入 require 'net/http' 即可
不過不太懂為什麼

郭佳甯 iT邦新手 5 級 ‧ 2018-04-25 02:39:52 檢舉

我也不懂,應該不用加這個才對阿

laapnda iT邦新手 5 級 ‧ 2018-04-25 23:18:19 檢舉

不加入貌似 Net就會錯誤的樣子/images/emoticon/emoticon02.gif

陳同學 iT邦新手 5 級 ‧ 2018-05-16 14:21:05 檢舉

我也有相同狀況

目前我也是卡在這裡,
開啟網頁顯示錯誤訊息
NameError in One5110Controller#sent_request
uninitialized constant One5110Controller::Net

反紅文字也是

	response = Net::HTTP.get(uri)

https://ithelp.ithome.com.tw/upload/images/20180611/201027197ZLzBIJMbq.jpg

郭佳甯 iT邦新手 5 級 ‧ 2018-06-13 00:35:37 檢舉

QQ

小群 iT邦新手 5 級 ‧ 2018-06-27 18:19:54 檢舉

您好我有購買您的書籍,同樣在142頁,Net的語法一直不能支援,目前有解決方法嗎?
NameError in KamigoController#sent_request
uninitialized constant KamigoController::NET

問題也是出在這裡

解法似乎是在application_controller.rb中加入

require 'net/http'

還請問大大為什麼會這樣QQ 謝謝

郭佳甯 iT邦新手 5 級 ‧ 2018-06-29 14:15:24 檢舉

應該是安裝的環境版本號有差異的關係,這個 require 的功能是指明要載入 'net/http' 裡面的程式碼檔案。

小群 iT邦新手 5 級 ‧ 2018-06-29 17:22:57 檢舉

剛剛我測試過除了第一行要加入require 'net/http'
NET要改成Net才能運作,供各位參考。
response = Net::HTTP.get(uri)

0
such0305
iT邦新手 5 級 ‧ 2018-04-28 16:39:53

請問米大~
呼叫函數這個部分應該在哪裡進行?
我在翻譯韓文那個步驟無法成功翻譯,而且切至瀏覽器也沒有產生錯誤
是因為我沒有呼叫函數的關係嗎QAQ
謝謝米大

看更多先前的回應...收起先前的回應...
郭佳甯 iT邦新手 5 級 ‧ 2018-04-29 01:33:16 檢舉

可以看一下你完整的 controller 檔案內容嗎

such0305 iT邦新手 5 級 ‧ 2018-04-29 23:18:19 檢舉

https://ithelp.ithome.com.tw/upload/images/20180429/20109721XsM3ZNRN0v.jpg

such0305 iT邦新手 5 級 ‧ 2018-04-29 23:19:24 檢舉

我的controller 內容在這

郭佳甯 iT邦新手 5 級 ‧ 2018-05-06 22:07:48 檢舉

那你開啟 http://localhost:3000/baiqi0729/sent_request 頁面後看到的是什麼呢

原來我是router打錯單字,謝謝大大,換樓上問題了哈哈 繼續研究

0
freyr949487
iT邦新手 5 級 ‧ 2018-06-09 17:56:57


1

這種要怎麼解決?查過其他網址都無果

郭佳甯 iT邦新手 5 級 ‧ 2018-06-13 00:36:05 檢舉

你好像多輸入了一個 . 阿~

0
vpower1201
iT邦新手 5 級 ‧ 2018-10-19 15:41:48

請問版大 我這邊是遇到甚麼問題 比對過都沒錯啊 但是沒辦法連結https://ithelp.ithome.com.tw/upload/images/20181019/20112690aiCmPFy9Kx.jpg

看更多先前的回應...收起先前的回應...
郭佳甯 iT邦新手 5 級 ‧ 2018-10-19 15:43:26 檢舉

試試在整個程式碼的第一行加入
require 'net/http'

版大 可以了 謝謝您!
所以在程式碼要先要求NET跟HTTP的運作嗎??

郭佳甯 iT邦新手 5 級 ‧ 2018-10-19 23:02:28 檢舉

正常情況應該不用加這個
這個 require 的功能是指明要載入 'net/http' 裡面的程式碼檔案。

那如果增加require 對後續的程式有任何影響嗎??

另外請問一下 函數呼叫是要打在哪裡= =??

https://ithelp.ithome.com.tw/upload/images/20181227/20114225tD2gKjMEZb.jpg

只是我發現網站要跑很久才會顯示

0
basara
iT邦新手 5 級 ‧ 2019-05-22 07:34:46

米大您好 您在這張圖片中整理了 request 和 response 的四個物件,並發現有四個不同類別,但是似乎沒有進一步處理,請問您歸類這四個類別的目的是為了什麼?
https://ithelp.ithome.com.tw/upload/images/20190522/20117766E4SatDGAm3.jpg

郭佳甯 iT邦新手 5 級 ‧ 2019-05-22 10:04:42 檢舉

說明這是4種不同的東西 千萬不要以為他們是同一種

basara iT邦新手 5 級 ‧ 2019-05-23 23:07:19 檢舉

好的 我了解了 謝謝您

0
ashuidg
iT邦新手 5 級 ‧ 2019-07-18 11:35:53

版大您好,想請教遇到undefined local variable or method http_request該如何解決呢?
https://ithelp.ithome.com.tw/upload/images/20190718/20119125C8LnBwScDb.jpg

郭佳甯 iT邦新手 5 級 ‧ 2019-07-18 11:37:21 檢舉

你前面的 http_request = Net::HTTP::Get.new(uri) 程式碼不見了?

ashuidg iT邦新手 5 級 ‧ 2019-07-18 11:49:41 檢舉

對欸!!感謝~~

我要留言

立即登入留言