抓住包含文本nokogiri xpath的元素

时间:2013-05-10 18:17:53

标签: ruby-on-rails ruby ruby-on-rails-3 screen-scraping nokogiri

仍在学习如何使用nokogiri,到目前为止可以通过css元素抓取。有一个页面我想要抓http://www.bbc.co.uk/sport/football/results,我想得到巴克莱高级联赛的所有结果,可以通过Ajax调用,但是对于我读过的nokogiri来说这是不可能的。

所以我提供的链接对于所有不同的联赛都有很多结果,所以我只能抓住名为Barclays Premier League的那些包含在

中的链接。
class="competition-title"

到目前为止,我可以抓住所有结果

def get_results # Get me all results
 doc = Nokogiri::HTML(open(RESULTS_URL))
 days = doc.css('#results-data h2').each do |h2_tag|
 date = Date.parse(h2_tag.text.strip).to_date
  matches = h2_tag.xpath('following-sibling::*[1]').css('tr.report')
  matches.each do |match|
    home_team = match.css('.team-home').text.strip
    away_team = match.css('.team-away').text.strip
    score = match.css('.score').text.strip
 Result.create!(home_team: home_team, away_team: away_team, score: score, fixture_date: date)
end

任何帮助表示赞赏

修改

好吧所以好像我可以使用一些ruby,使用select?不知道如何实施。以下示例

.select{|th|th.text =~ /Barclays Premier League/}

或者更多的读数表示可以使用xpath

matches = h2_tag.xpath('//th[contains(text(), "Barclays Premier League")]').css('tr.report')

matches = h2_tag.xpath('//b/a[contains(text(),"Barclays")]/../following-sibling::*[1]').css('tr.report')

已尝试过xpath方式,但明显错误,因为没有保存

由于

2 个答案:

答案 0 :(得分:2)

我更喜欢一种方法,您可以深入了解您的需求。查看来源,您需要匹配详细信息:

    <td class='match-details'>
        <p>
            <span class='team-home teams'><a href='...'>Brechin</a></span>
            <span class='score'><abbr title='Score'> 0-2 </abbr></span>
            <span class='team-away teams'><a href='...'>Alloa</a></span>
        </p>
    </td>

您需要p元素中的三个文本内容项。你只需要#34;巴克莱英超联赛&#34;。

查看来源,请注意上面所需的元素恰好位于包含该联盟的 分数的表格中。多方便啊!该表格可以通过<th>元素联系&#34;巴克莱英超联赛&#34;来识别。然后你要做的就是使用XPath识别该表:

matches = doc.xpath('//table[.//th[contains(., "Barclays Premier League")]]//td/p')

td/p已足够,因为匹配详细信息是唯一包含p的内容,但您可以根据需要将该类添加到td

然后,您完全按照您的方式获取信息:

matches.each do |match|
  home_team = match.css('.team-home').text.strip
  away_team = match.css('.team-away').text.strip
  score = match.css('.score').text.strip
  ...
end

剩下的一项任务:获取每场比赛的日期。回顾一下源代码,您可以回到第一个包含的表,并看到前面的第一个h2节点有它。你可以在XPath中表达这个:

date = match.at_xpath('ancestor::table[1]/preceding-sibling::h2[1]').text

全部放在一起

def get_results    
  doc = Nokogiri::HTML(open(RESULTS_URL))
  matches = doc.xpath('//table[.//th[contains(., "Barclays Premier League")]]//td/p')
  matches.each do |match|
    home_team = match.css('.team-home').text.strip
    away_team = match.css('.team-away').text.strip
    score = match.css('.score').text.strip
    date = Date.parse(match.at_xpath('ancestor::table[1]/preceding-sibling::h2[1]').text).to_date
    Results.create!(home_team: home_team, away_team: away_team, score: score, fixture_date: date)
  end
end

答案 1 :(得分:1)

只是为了好玩,这就是我如何改变@Mark Thomas的解决方案:

def get_results    
  doc = Nokogiri::HTML(open(RESULTS_URL))
  doc.search('h2.table-header').each do |h2|
    date = Date.parse(h2.text).to_date
    next unless h2.at('+ table th[2]').text['Barclays Premier League']
    h2.search('+ table tbody tr').each do |tr|
      home_team = tr.at('.team-home').text.strip
      away_team = tr.at('.team-away').text.strip
      score = tr.at('.score').text.strip
      Results.create!(home_team: home_team, away_team: away_team, score: score, fixture_date: date)
    end
  end
end

通过迭代那些h2,你得到:

优点:

  • 将日期拉出循环
  • 更简单的表达(你可能不会太担心那些 但想想那个跟在你后面的人。)

缺点:

  • 一些额外的代码字节