代码之家  ›  专栏  ›  技术社区  ›  ForceMagic

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

  •  0
  • ForceMagic  · 技术社区  · 7 年前

    抱歉,这似乎是个离题的问题,但请给我两分钟时间。我可能遗漏了一个小细节,但我对这一小段代码非常着迷:

    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变量。什么正在进行。在这里?我已经在这个代码上坐了一个小时了!(DuckDuckGo已经占据了互联网的一半)


    以防有人用Fan虚构来尝试,我得到的是:

    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 回复  |  直到 7 年前
        1
  •  1
  •   Mark Thomas    7 年前

    使用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"
    

    注意,括号 [] 其中包含 与评级目标的链接。这样就不需要计算跨度,因为跨度更脆。

    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]