2016-11-09 95 views
0
require 'rubygems' 
require 'nokogiri' 
require 'open-uri' 
url = 'https://www.trumba.com/calendars/smithsonian-events.xml' 
doc = Nokogiri::XML(open url) 

我試圖獲取基本設置信息等解析頁面的HTML內容:如何使用引入nokogiri

event_name 
categories 
sponsor 
venue 
event_location 
cost 

例如,對於event_name我有這樣的XPath:

"/html/body/div[2]/div[2]/div[1]/h3/a/span" 

而且使用它像:

puts doc.xpath "/html/body/div[2]/div[2]/div[1]/h3/a/span" 

這將返回零爲event_name

如果我在本地保存URL內容,那麼上面的XPath就可以工作。

除此之外,我還需要上述信息。我也檢查了其他XPath,但結果變成空白。

+0

您提供純xml的網址。但要嘗試找到它在其中找到HTML。文檔中沒有任何html。 – Aleksey

+0

然後如何使用nokogiri提取內容。 @Aleksey – Ajay

+0

不要使用像'「/ html/body/div [2]/div [2]/div [1]/h3/a/span」'這樣的完整選擇器。他們非常容易出錯。相反,找到所需節點的最短路徑並使用它。這樣,如果文檔佈局更改,選擇器仍然可以正常工作。現在,如果頁面發生了一些變化,你的代碼就會崩潰。 –

回答

1

提供的鏈接包含XML,因此您的XPath表達式應該與XML結構一起工作。

關鍵是文檔具有名稱空間。據我瞭解,所有的XPath表達式都應該記住並且指定命名空間。
爲了簡單的XPath表達式可以使用remove_namespaces!方法:

require 'nokogiri' 
require 'open-uri' 
url = 'https://www.trumba.com/calendars/smithsonian-events.xml' 
doc = Nokogiri::XML(open(url)); nil # nil is used to avoid huge output 

doc.remove_namespaces!; nil 
event = doc.xpath('//feed/entry[1]') # it will give you the first event 

event.xpath('./title').text # => "Conservation Clinics" 
event.xpath('./categories').text # => "Demonstrations,Lectures & Discussions" 

最有可能你想擁有的所有事件哈希陣列。
你可以不喜歡它:

doc.xpath('//feed/entry').reduce([]) do |memo, event| 
    event_hash = { 
    title: event.xpath('./title').text, 
    categories: event.xpath('./categories').text 
    # all other attributes you need ... 
    } 
    memo << event_hash 
end 

它會給你一個數組,如:

[ 
    {:title=>"Conservation Clinics", :categories=>"Demonstrations,Lectures & Discussions"}, 
    {:title=>"Castle Highlights Tour", :categories=>"Gallery Talks & Tours"}, 
    ... 
] 
+1

只有在確定沒有命名空間的標籤不會碰撞時,才推薦刪除名稱空間。使用CSS選擇器是一種更簡單的工作方式,並在文檔中介紹。請閱讀http://www.nokogiri.org/tutorials/searching_a_xml_html_document.html#namespaces到頁面末尾。 –

+0

@TheTinMan感謝您的評論。我不認爲CSS選擇器有這樣的權力。我會在閱讀後嘗試更新答案。 – Aleksey

+0

CSS並不像XPath那麼強大,但它們通常更具可讀性,並且使用Nokogiri實現的jQuery擴展,您可以做很多事情,並且仍然能夠理解選擇器的乍一看。 –

2

這是我怎麼會去這樣做:

require 'nokogiri' 
doc = Nokogiri::XML(open('/Users/gferguson/smithsonian-events.xml')) 
namespaces = doc.collect_namespaces 

entries = doc.search('entry').map { |entry| 
    entry_title = entry.at('title').text 
    entry_time_start, entry_time_end = ['startTime', 'endTime'].map{ |p| 
    entry.at('gd|when', namespaces)[p] 
    } 
    entry_notes = entry.at('gc|notes', namespaces).text 

    { 
    title: entry_title, 
    start_time: entry_time_start, 
    end_time: entry_time_end, 
    notes: entry_notes 
    } 

} 

,當運行結果爲entries是哈希陣列:

require 'awesome_print' 
ap entries [0, 3] 

# >> [ 
# >> [0] { 
# >>  :title  => "Conservation Clinics", 
# >>  :start_time => "2016-11-09T14:00:00Z", 
# >>  :end_time => "2016-11-09T17:00:00Z", 
# >>  :notes  => "Have questions about the condition of a painting, frame, drawing,\n print, or object that you own? Our conservators are available by\n appointment to consult with you about the preservation of your art.\n \n To request an appointment or to learn more,\n e-mail [email protected] and specify CLINIC in the subject line." 
# >> }, 
# >> [1] { 
# >>  :title  => "Castle Highlights Tour", 
# >>  :start_time => "2016-11-09T14:00:00Z", 
# >>  :end_time => "2016-11-09T14:45:00Z", 
# >>  :notes  => "Did you know that the Castle is the Smithsonian’s first and oldest building? Join us as one of our dynamic volunteer docents takes you on a tour to explore the highlights of the Smithsonian Castle. Come learn about the founding and early history of the Smithsonian; its original benefactor, James Smithson; and the incredible history and architecture of the Castle. Here is your opportunity to discover the treasured stories revealed within James Smithson's crypt, the Gre... 
# >> }, 
# >> [2] { 
# >>  :title  => "Exhibition Interpreters/Navigators (throughout the day)", 
# >>  :start_time => "2016-11-09T15:00:00Z", 
# >>  :end_time => "2016-11-09T15:00:00Z", 
# >>  :notes  => "Museum volunteer interpreters welcome visitors, answer questions, and help visitors navigate exhibitions. Interpreters may be stationed in several of the following exhibitions at various times throughout the day, subject to volunteer interpreter availability. <ul> \t<li><em>The David H. Koch Hall of Human Origins: What Does it Mean to be Human?</em></li> \t<li><em>The Sant Ocean Hall</em></li> </ul>" 
# >> } 
# >> ] 

我沒有試圖收集您所要求的具體信息,因爲event_name不存在,您所做的事情非常通用,一旦理解了一些規則就可以輕鬆完成。

XML通常非常重複,因爲它代表了數據表。表格的「單元格」可能會有所不同,但您可以使用重複來幫助您。在此代碼中

doc.search('entry') 

通過<entry>節點循環。然後,很容易查看它們以找到所需的信息。

XML使用名稱空間來幫助避免標記名稱衝突。起初,這些看起來確實很難,但Nokogiri爲文檔提供了collect_namespaces方法,該方法返回文檔中所有命名空間的散列。如果您正在查找名稱空間標籤,請將該散列作爲第二個參數傳遞。

Nokogiri允許我們使用XPath和CSS作爲選擇器。爲了便於閱讀,我幾乎總是使用CSS。ns|tag是告訴Nokogiri使用基於CSS的命名空間標籤的格式。再次,傳遞文檔中名稱空間的散列,Nokogiri將完成其餘部分。

如果您熟悉使用Nokogiri,您會看到上面的代碼與用於將<td>單元的內容拉到HTML <table>中的<tr>行的正常代碼非常相似。

您應該可以修改該代碼來收集所需的數據,而不會冒名稱空間衝突的風險。

+0

謝謝你的好的答案。當我試圖更新我的答案時,我正在努力應對命名空間。 – Aleksey