Nokogiri正在回归根元素。为什么?

时间:2017-08-01 19:34:04

标签: ruby xpath nokogiri

对不起,这似乎是一个偏离主题的问题,但只需给我2分钟。我可能错过了一个小细节,但我对这一小段代码感到疯狂:

parsed = Nokogiri::HTML(open(url))

fullmeta = parsed.xpath('//*[@id="profile_top"]')[0]
if fullmeta.inner_html.to_s.include? "image"
    meta = fullmeta.xpath('//span[4]')[0]
else
    meta = fullmeta.xpath('//span[3]')[0]
end

puts meta.inner_html                    # This seems fine
puts meta.xpath('//a[1]')[0].inner_html # !!!

标有!!!的行是罪魁祸首。有些事情正在使该行从parsed的根元素重新执行XPath!我之前已经声明了几个XPath。什么。是。去。上。这里?我一直坐在这段代码上一个小时! (DuckDuckGo已经是互联网的一半了)

如果您需要XML,只需使用任何FanFiction故事页面即可。我正在为rails编写一个API,但这不是一个重要的事实。

万一有人尝试使用FanFiction,这就是我得到的:

Rated: <a class="xcontrast_txt" href="https://www.fictionratings.com/" target="rating">Fiction  T</a> - English - Humor/Adventure - Chapters: 15   - Words: 55,643 - Reviews: <a href="/r/12135694/">22</a> - Favs: 5 - Follows: 8 - Updated: <span data-xutime="1501553985">17h</span> - Published: <span data-xutime="1473081239">9/5/2016</span> - id: 12135694 
FanFiction

最后一行应该说Fiction T

1 个答案:

答案 0 :(得分:1)

使用XPath的全部功能通常意味着您不必停止和迭代,您只需使用单个表达式直接获取所需内容即可。这允许您外化,存储变量或以其他方式组织表达式并更轻松地维护它们,即使XML发生更改。使用XPath,您甚至可以在表达式中包含一些逻辑。

您是否想要获得故事的评分?请注意,有一个target=rating属性,因此您可以关闭该属性,而不是计算span元素。

doc.xpath('//*[@id="profile_top"]/span/a[@target="rating"]/text()')

#=> "Fiction M"

我建议的另一件事是使用HTTParty或Mechanize,如果你还没有。他们有不同的优势。 HTTParty为您提供了一种简单的方法来创建一个带有提取和解析的漂亮的面向对象的客户端。 Mechanize专注于抓取,但它内置了Nokogiri,您可以访问底层的Nokogiri文档,然后开始执行XPath。

修改 在下面的评论中添加其他几个。

language = doc.xpath('//*[@id="profile_top"]/span[a[@target="rating"]]/text()').to_s.split(' - ')[1]
#=> "English"

请注意,括号[]可以读作&#34;其中包含&#34;所以我们正在寻找包含带有评级目标的链接的span 。这样你就不需要计算跨度,这更加脆弱。

genres = doc.xpath('//*[@id="profile_top"]/span[a[@target="rating"]]/text()').to_s.split(' - ')[2].split('/')
#=> ["Humor", "Adventure"]

id = doc.xpath('//*[@id="profile_top"]/span[a[@target="rating"]]/text()').to_s.split(' - ')[5].split(': ')
#=> "12596791"

published = DateTime.strptime(doc.xpath('//*[@id="profile_top"]//span/@data-xutime').first.value, '%s')
#=> 2017-08-01T20:03:19+00:00

等等。我建议将XPath放在类似哈希的内容中,这样您就可以引用更具描述性的xpath_for[:rating],而不是在整个代码中对它们进行硬编码。