使用 Ruby / Nokogiri 解析随机类名

Posted

技术标签:

【中文标题】使用 Ruby / Nokogiri 解析随机类名【英文标题】:Using Ruby / Nokogiri to parse randomized class names 【发布时间】:2021-02-19 12:00:15 【问题描述】:

我一直在手工计算各个州的美国总统选举投票的剩余百分比。有这么多的更新和状态——这越来越累了。那么为什么不自动化这个过程呢?

这是我正在查看的内容:

问题是类名是随机的。例如,这是我感兴趣的:<td class="jsx-3768461732 votes votes-row">2,450,186</td>

在 irb 中玩耍,我尝试在“votes votes-row”上使用通配符,因为这仅在我需要在文档中出现时出现:

require 'nokogiri'
require 'open-uri'
doc = Nokogiri::html(open("https://www.politico.com/2020-election/results/georgia/"))
votes = doc.css("[td*='votes-row']")

...没有结果 (=> [])

我做错了什么以及如何解决?我对 xpath 没意见——我只是想确保在文档中其他地方所做的更改不会影响找到这些元素。

【问题讨论】:

如果您查看politico.com/2020-election/results/georgia 的来源并在其中找到,似乎没有投票结果。也许这些类是用JS添加的? 【参考方案1】:

可能有更好的方法,但是...

require 'nokogiri'
require 'open-uri'
doc = Nokogiri::HTML(open("https://www.politico.com/2020-election/results/georgia/"))
votes = doc.css('tr[class*="candidate-row"]').map  |row| row.css('td').map  |cell| cell.content  
biden_row = votes.find_index  |row| row[0] =~ /biden/i 
trump_row = votes.find_index  |row| row[0] =~ /trump/i 
biden_votes = votes[biden_row][1].split('%')[1]
trump_votes = votes[trump_row][1].split('%')[1]

编辑:来自 HTML 源代码的相关表格如下所示:

<table class="jsx-1526769828 candidate-table">
  <thead class="jsx-3554868417 table-head">
    <tr class="jsx-3554868417">
      <th class="table-header jsx-3554868417 candidate-name">
        <h5 class="jsx-3554868417">Candidate</h5>
      </th>
      <th class="table-header jsx-3554868417 percent">
        <h5 class="jsx-3554868417">Pct.</h5>
      </th>
      <th class="table-header jsx-3554868417 vote-bar"></th>
    </tr>
  </thead>
  <tbody class="jsx-2085888330 table-head">
    <tr class="jsx-2677388595 candidate-row">
      <td class="jsx-3948343365 candidate-name name-row">
        <div class="jsx-1912693590 name-only candidate-short-name">Biden</div>
        <div class="jsx-3948343365 candidate-party-tag">
          <div class="jsx-1420258095 party-label dem">dem</div>
        </div>
        <div class="jsx-3948343365 candidate-winner-check"></div>
      </td>
      <td class="jsx-3830922081 percent percent-row">
        <div class="candidate-percent-only jsx-3830922081">49.4%</div>
        <div class="candidate-votes-next-to-percent jsx-3830922081">2,450,193</div>
      </td>
      <td class="jsx-3458171655 vote-bar vote-bar-row">
        <div style="width:49.4%" class="jsx-3458171655 bar dem"></div>
      </td>
    </tr>
    <tr class="jsx-2677388595 candidate-row">
      <td class="jsx-3948343365 candidate-name name-row">
        <div class="jsx-1912693590 name-only candidate-short-name">Trump*</div>
        <div class="jsx-3948343365 candidate-party-tag">
          <div class="jsx-1420258095 party-label gop">gop</div>
        </div>
        <div class="jsx-3948343365 candidate-winner-check"></div>
      </td>
      <td class="jsx-3830922081 percent percent-row">
        <div class="candidate-percent-only jsx-3830922081">49.4%</div>
        <div class="candidate-votes-next-to-percent jsx-3830922081">2,448,635</div>
      </td>
      <td class="jsx-3458171655 vote-bar vote-bar-row">
        <div style="width:49.4%" class="jsx-3458171655 bar gop"></div>
      </td>
    </tr>
  </tbody>
</table>

因此,您可能可以使用候选投票的下一个百分比来获得该值。例如:

require 'nokogiri'
require 'open-uri'
doc = Nokogiri::HTML(open("https://www.politico.com/2020-election/results/georgia/"))
votes = doc.css('tr[class*="candidate-row"]').map do |row|
  [
    row.css('div[class*="candidate-short-name"]').first.content,
    row.css('div[class*="candidate-votes-next-to-percent"]').first.content
  ]
end
# => [["Biden", "2,450,193"], ["Trump*", "2,448,635"]]

【讨论】:

那么javascript毕竟不是一个因素吗? doc.css('td[class*="votes"]').size 为 0,并且 votes-row 没有出现在源代码中,所以我猜这些类必须被添加在 JS 中。候选行确实出现在源代码中,因此您可以将其与 Nokogiri 一起使用

以上是关于使用 Ruby / Nokogiri 解析随机类名的主要内容,如果未能解决你的问题,请参考以下文章

[翻译][Ruby教程]Nokogiri - 解析HTML/XML文档 / Parsing an HTML/XML Document

如何使用 Nokogiri 解析 HTML 表格?

Nokogiri:解析和更新 Plist 中的值

ruby 使用Nokogiri的简单Ruby刮刀

如何使用 Nokogiri 在 TMX 中搜索道具元素

MacOs (M1 Arm64) 无法加载 Nokogiri - 使用系统默认 Ruby