如何使用 Nokogiri 和 Ruby 从带有隐藏元素的动态折叠 table 中提取数据

How to extract data from dynamic collapsing table with hidden elements using Nokogiri and Ruby

我正在尝试浏览以下网站: https://www.cdc.gov/coronavirus/2019-ncov/cases-updates/cases-in-us.html

获取有关冠状病毒的所有州统计数据。

我的以下代码有效:

require 'nokogiri'
require 'open-uri'
require 'httparty'
require 'pry'

  url = "https://www.cdc.gov/coronavirus/2019-ncov/cases-updates/cases-in-us.html"
  doc = Nokogiri::HTML.parse(open(url))
  total_cases = doc.css("span.count")[0].text
  total_deaths = doc.css("span.count")[1].text
  new_cases = doc.css("span.new-cases")[0].text
  new_deaths = doc.css("span.new-cases")[1].text

但是,我无法进入折叠的 data/gridcell 数据。

我尝试通过 class .aria-label 和 .rt-tr-group class 进行搜索。任何帮助,将不胜感激。谢谢。

该页面正在使用 AJAX 加载其数据。

在这种情况下,您可以使用 Watir 通过浏览器获取页面

如此处回答:

另一种方法是直接从API获取数据。

您可以通过检查浏览器控制台上的网络选项卡来查看其他端点

我复制了你的代码并发现了你可能犯的一些错误

require 'HTTParty'

将不起作用。你需要使用

require 'httparty'

其次,您的变量 url 值应该有引号,即

url = "https://www.cdc.gov/coronavirus/2019-ncov/cases-updates/cases-in-us.html"

除此之外,它对我来说效果很好。

此外,如果您正在尝试获取 Covid-19 数据,您可能需要使用这些 API

For US Count For US Daily Count For US Count - States

您可以了解有关 API 的更多信息here

虽然 已经指出了问题,但它没有提供加载数据所需的步骤。

就像链接答案中已经说过的那样,数据是异步加载的。这意味着数据不存在于初始页面上,而是通过 JavaScript 引擎执行代码加载。

打开浏览器开发工具后,转到 "Network" 选项卡。您可以清除所有请求,然后刷新页面。您将看到所有请求的列表。如果您正在寻找异步加载的数据,最有趣的请求通常是 "json" 或 "xml".

类型的请求

浏览请求时,您会发现您要查找的数据位于:

https://www.cdc.gov/coronavirus/2019-ncov/json/us-cases-map-data.json

因为这是 JSON 你不需要 "nokogiri" 来解析它。

require 'httparty'
require 'json'

response = HTTParty.get('https://www.cdc.gov/coronavirus/2019-ncov/json/us-cases-map-data.json')
data = JSON.parse(response.body)

当执行上面的代码时你会得到异常:

JSON::ParserError ...

这似乎是 Byte Order Mark (BOM) 未被 HTTParty 删除的。很可能是因为响应未指定 UTF-8 字符集。

response.body[0]
#=> ""
format '%X', response.body[0].ord
#=> "FEFF"

为了正确处理 BOM Ruby 2.7 添加了 set_encoding_by_bom method to IO which is also available on StringIO.

require 'httparty'
require 'json'
require 'stringio'

response = HTTParty.get('https://www.cdc.gov/coronavirus/2019-ncov/json/us-cases-map-data.json')
body = StringIO.new(response.body)
body.set_encoding_by_bom
data = JSON.parse(body.gets(nil))
#=> [{"Jurisdiction"=>"Alabama", "Range"=>"10,001 to 20,000", "Cases Reported"=>10145,  ...

如果您还没有使用 Ruby 2.7,您可以使用替代品来删除 BOM,但是前者可能是更安全的选择:

data = JSON.parse(response.body.force_encoding('utf-8').sub(/\A\xEF\xBB\xBF/, ''))