2010-05-03 84 views
7

我想從這個頁面獲取數據:使用OpenUri,我如何獲取重定向頁面的內容?

http://www.canadapost.ca/cpotools/apps/track/personal/findByTrackNumber?trackingNumber=0656887000494793 

但該頁面轉發到:

http://www.canadapost.ca/cpotools/apps/track/personal/findByTrackNumber?execution=eXs1 

所以,當我使用open,從OpenUri,試圖獲取數據,它拋出一個RuntimeError錯誤說HTTP redirection loop:

我真的不知道如何獲取該數據後重定向並引發該錯誤。

+0

是開放uri強制性的,你會不會同意另一個ruby技術? – 2010-05-07 10:28:14

+0

如果有必要,另一個紅寶石技術絕對沒問題。 – Shpigford 2010-05-07 11:44:12

+0

'open-uri'已經處理重定向。當遇到重定向時,它只是錯誤循環 – lulalala 2012-05-04 07:36:19

回答

22

你需要一個工具,如Mechanize。從它的描述:

機械化庫用於 自動與網站的交互。 機械化自動存儲和 發送cookie,跟隨重定向,可以 跟隨鏈接,並提交表格。可以填寫並提交表格 字段。 機械化還會跟蹤您訪問過的 網站作爲 歷史記錄。

這正是你所需要的。所以,

sudo gem install mechanize 

然後

require 'mechanize' 
agent = WWW::Mechanize.new 
page = agent.get "http://www.canadapost.ca/cpotools/apps/track/personal/findByTrackNumber trackingNumber=0656887000494793" 

page.content # Get the resulting page as a string 
page.body # Get the body content of the resulting page as a string 
page.search(".somecss") # Search for specific elements by XPath/CSS using nokogiri 

,你準備好搖滾搖滾樂。

1

該網站似乎正在做一些會話的重定向邏輯。如果您不發回它們在第一個請求中發送的會話cookie,您將以重定向循環結束。恕我直言,這是他們的一個糟糕的實施。

但是,我試圖將cookies傳回給他們,但我沒有得到它的工作,所以我不能完全確定這是所有這一切發生在這裏。

+0

對,這就是我要求的...因爲這是一個重定向,我如何從它重定向到的頁面獲取數據? – Shpigford 2010-05-04 11:43:08

+0

爲了讓我的觀點更加清晰,我重申了我的回答。我不只是說這是一個重定向,我還解釋了爲什麼你最終陷入了一個循環,希望現在應該是清楚的。 – Theo 2010-05-04 16:25:59

1

雖然機械化是一個奇妙的工具,我更喜歡「做飯」我自己的事情。

如果你認真解析你可以看看這段代碼。它每天都會在國際上爬行數千個站點,並且據我研究和調整,沒有一種更穩定的方法可以讓您根據自己的需求進行高度定製。

require "open-uri" 
require "zlib" 
require "nokogiri" 
require "sanitize" 
require "htmlentities" 
require "readability" 

def crawl(url_address) 
self.errors = Array.new 
begin 
    begin 
    url_address = URI.parse(url_address) 
    rescue URI::InvalidURIError 
    url_address = URI.decode(url_address) 
    url_address = URI.encode(url_address) 
    url_address = URI.parse(url_address) 
    end 
    url_address.normalize! 
    stream = "" 
    timeout(8) { stream = url_address.open(SHINSO_HEADERS) } 
    if stream.size > 0 
    url_crawled = URI.parse(stream.base_uri.to_s) 
    else 
    self.errors << "Server said status 200 OK but document file is zero bytes." 
    return 
    end 
rescue Exception => exception 
    self.errors << exception 
    return 
end 
# extract information before html parsing 
self.url_posted  = url_address.to_s 
self.url_parsed  = url_crawled.to_s 
self.url_host   = url_crawled.host 
self.status   = stream.status 
self.content_type  = stream.content_type 
self.content_encoding = stream.content_encoding 
self.charset   = stream.charset 
if stream.content_encoding.include?('gzip') 
    document = Zlib::GzipReader.new(stream).read 
elsif stream.content_encoding.include?('deflate') 
    document = Zlib::Deflate.new().deflate(stream).read 
#elsif stream.content_encoding.include?('x-gzip') or 
#elsif stream.content_encoding.include?('compress') 
else 
    document = stream.read 
end 
self.charset_guess = CharGuess.guess(document) 
if not self.charset_guess.blank? and (not self.charset_guess.downcase == 'utf-8' or not self.charset_guess.downcase == 'utf8') 
    document = Iconv.iconv("UTF-8", self.charset_guess, document).to_s 
end 
document = Nokogiri::HTML.parse(document,nil,"utf8") 
document.xpath('//script').remove 
document.xpath('//SCRIPT').remove 
for item in document.xpath('//*[translate(@src, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz")]') 
    item.set_attribute('src',make_absolute_address(item['src'])) 
end 
document = document.to_s.gsub(/<!--(.|\s)*?-->/,'') 
self.content = Nokogiri::HTML.parse(document,nil,"utf8") 
end