2014-08-27 229 views
0

我已經建立了一個使用open-uri和nokogiri的網頁爬蟲ruby腳本,我很新,但它都適用於我需要從中提取數據的幾個網站除了使用相對URL之外,其源代碼中包含完整的網址。紅寶石 - 從相對開放的絕對網址

腳本的功能是打開頁面,構建一個打開的頁面數組,然後從css(而不是xpath)中提取數據。

如何強制腳本使用完整的URL在他們相對的,它的被竊聽我一會兒實例,我似乎無法讓它運行

在我的情況,我想我需要在推送網址的時候添加一些內容,有誰能請我指出正確的方向嗎?這將非常感激!謝謝!

require 'open-uri' 
require 'nokogiri' 

PAGE_URL = "http://www.OMMITED.co.uk" 

page = Nokogiri::HTML(open(PAGE_URL, "User-Agent" => 「OMMITED「)) 

links = page.css("a") 

links_array = Array.new 

links.each{|link| 
     url = link['href'].nil? ? 'empty' : link['href'] 
     if url.include? 'category' and !url.include? '/all' 
       links_array.push url 
     end 
} 
+0

你可以使用正則表達式來檢查完全合格的URL,類似於/^[\ w] *:\/\ // - 如果它匹配,那麼前插根URL。在相對URL表示,它開始在服務器後的根路徑,而不是開始沒有斜線相對鏈接,匹配當前頁的目錄當中開始記住的「/」的精妙之處。我會寫一個答案,但我需要更多關於可用變量的知識。 (主要是當前完全限定的URL和當前頁面路徑。) – 2014-08-27 11:17:38

+0

編輯添加變量! – James 2014-08-27 13:58:42

回答

0

tl; dr:底部簡短回答。

OK,假設你有一個類變量叫做@url包含當前頁面的完全合格的URL:

require 'uri' 

def full_url(rel, url) 
    return rel if rel.match /^[\w]*:\/\// 
    uri = URI(url) 
    if rel[0] == '/' 
    "#{uri.scheme}://#{uri.host}#{rel}" 
    else 
    path = uri.path.split('/')[0..-2].select{|m| !m.empty?}.join('/') 
    "#{uri.scheme}://#{uri.host}/#{path}/#{rel}" 
    end 
end 

然後,您可以撥打:

links_array.push full_url(url, @url) 

你可以把方法的相同的類或某處的助手類。它使用Ruby URI庫來查找完全限定URL的相關部分,然後從相對路徑構造一個新的URL。

如果相對路徑以'/'開始,它應該直接在主機之後。

如果它不以'/'開始,那麼它需要與當前頁面位於相同的虛擬目錄中。因此,如果當前頁面是:

http://www.host.com/aaa/bbb/ccc 

和相對路徑是:

ddd 

則輸出應該是:

http://www.host.com/aaa/bbb/ddd 

然而,如果相對路徑是:

/ddd 

那麼輸出應該是:

http://www.host.com/ddd 

的代碼:

uri.path.split('/')[0..-2].select{|m| !m.empty?}.join('/') 

需要完整的URL的路徑,將其分解在 '/' 給出的陣列(['aaa','bbb', 'ccc']),然後刪除最後一個元素。 (['aaa','bbb'])。選擇刪除所有空白元素,然後再次將連接縫合起來。("aaa/bbb"

OR

你能做到這一點的枯燥方式:

require 'uri' 

URI.join("http://www.host.com/aaa/bbb/ccc", "/ddd").to_s 
# => "http://www.host.com/ddd" 

URI.join("http://www.host.com/aaa/bbb/ccc", "ddd").to_s 
# => "http://www.host.com/aaa/bbb/ddd" 

給出代碼:

links.each{|link| 
    url = link['href'].nil? ? 'empty' : link['href'] 
    if url.include? 'category' and !url.include? '/all' 
      links_array.push url 
    end 
} 

我會爲重新寫:

links.each do |link| 
    url = link['href'].nil? ? 'empty' : link['href'] 
    if url.include? 'category' && !url.include? '/all' 
    full_url = URI.join(PAGE_URL, url).to_s 
    puts full_url 
    links_array << url 
    puts links_array.inspect 
    end 
end 

注意:S在多態方面,多行塊應該使用do/end而不是{}。縮進應該是兩個空格。圓括號內不應有空格。運營商比推送更受青睞。始終使用& &在條件語句而不是and,它具有低得多的優先級,並可能導致的問題。見GitHub的風格指南:

https://github.com/styleguide/ruby

puts是根據您的意見還有,希望幫助你弄清楚爲什麼你的陣列是不是行爲。它應該是,根據你放在那裏的代碼。我寧願使用調試器寶石。 (或者,如果你對Ruby的2.X byebug)

+0

感謝您的回覆,我已經加你的代碼並添加這導致停止沒有這樣的文件或目錄的錯誤,我想指出,它是把兩個值加在一起的@url變量,但它似乎並沒有被打開我需要查看的URL數組,我會嘗試修復並回來確認您的解決方案正常工作!謝謝! – James 2014-08-27 13:52:20

+0

檢查答案的編輯結束,它顯示了一個更簡單,更乾淨的解決方案。 – 2014-08-27 13:58:10

+0

你最後的評論的鼓舞下,我來到了這個 'code' @full_url = URI.join(PAGE_URL,URL).to_s 提出@full_url links_array.push @full_url 結束 } '代碼' 它加入正確(賣出期權是打印完整的URL),但它並不像它傳遞到陣列中。你能在這裏看到任何可以解釋的錯誤嗎? – James 2014-08-27 15:28:47