【问题标题】:R rvest Can't Get html_nodeR rvest 无法获取 html_node
【发布时间】:2020-09-01 06:59:35
【问题描述】:

我有一些使用rvest 包从网络上抓取我需要的数据的经验,但是我遇到了这个页面的问题:

https://www.nytimes.com/interactive/2020/us/covid-college-cases-tracker.html

如果您向下滚动一点,您会看到所有学校所在的部分。

我想要学校、案例和位置数据。我应该注意到有人在NYT GitHub 上询问将其发布为 csv 并且他们recommended that the data is all in the page and can just be pulled from there. 因此,我认为从这个页面上抓取是可以的。

但我无法让它工作。假设我只想从第一所学校的简单选择器开始。我使用检查器来查找 xpath。

我没有得到任何结果:

library(rvest)

URL <- "https://www.nytimes.com/interactive/2020/us/covid-college-cases-tracker.html"
pg <- read_html(URL)

# xpath copied from inspector
xpath_first_school <- '//*[@id="school100663"]'

node_first_school <- html_node(pg, xpath = xpath_first_school)

> node_first_school
{xml_missing}
<NA>

我收到{xml_missing}

不知不觉我还有很多事情要做来概括这一点并为所有人收集数据 学校,但是对于网络抓取,我通常尝试从简单而具体的开始,然后扩大范围。但即使我的简单测试也不起作用。有什么想法吗?

【问题讨论】:

  • 我查看了网站,甚至查看了浏览器 devtools 网络流量,但似乎没有一种简单的方法可以获取数据。也就是说,当调用read_html(甚至html_session)时,学校数据似乎不存在。然后在 http 对话中的某个时间点对其进行更新。但是,jsjsonplain 连接似乎都没有包含您正在寻找的数据,所以我怀疑他们非常小心:您可以在网页上看到数据,但是它们使得以编程方式抓取变得困难。
  • 虽然它很麻烦而且并非没有缺陷,但我怀疑一种前进的方式(因为 harvesting 它“简单地”对我不起作用)是尝试使用 @987654338 进行无头浏览器设置@。这有点出乎我的意料,但也许这会给你一些想法。
  • @r2evans,谢谢。 There is a site 显示如何使用 RSeleniumrvest 来获取此数据。我会对此进行研究,然后可能会发布作为答案。感谢您查看并确认我不只是未能使用更简单的方法!
  • 过去我推荐 RSelenium 太快了,可能是因为我达到了 的阈值“在合理的时间内无法通过 rvest 找到它“ ...所以不要完全放弃它..我所做的一切(tbh)是为Birmingham(其中一所学校,没有找到)或合理的所有下载(这三种类型的)grep - 可能指示非 json 数据源的 URL(查找 nyt.com,只找到图像和新闻元数据)。我的猜测是它在js 代码中被稍微混淆了......祝你好运,尼克。
  • r2evans,如果你想知道的话,@KKW,我在这方面与 Selenium 争论了一段时间,然后找到了一个解决方案,它允许我们读取页面的文本并解析一些 JSON。不是一个非常普遍的解决方案,但它确实可以解决这个问题。

标签: r web-scraping rvest


【解决方案1】:

设置 Rselenium 可能需要一些时间。首先你必须下载 chromedriver (https://chromedriver.chromium.org/),选择你当前 chrome 最接近的版本。然后解压到你的 R 工作目录。

我尝试使用一个名为 decapitated 的包,它可以抓取 javascript 呈现的网站,但因为该网站包含“显示更多”,需要在显示所有数据之前进行物理点击,所以我必须先使用 Rselenium 来“点击”它获取页面源然后使用rvest进行解析

代码:

library(rvest)
library(tidyverse)
library(RSelenium)

url <- "https://www.nytimes.com/interactive/2020/us/covid-college-cases-tracker.html"

driver <- rsDriver(browser = c("chrome"), chromever = "85.0.4183.87", port = 560L)
remote_driver <- driver[["client"]] 
remote_driver$navigate(url)

showmore <- remote_driver$findElement(using = "xpath", value = "//*[@id=\"showall\"]/p")
showmore$clickElement()

test <- remote_driver$getPageSource()

school <- read_html(test[[1]]) %>%
  html_nodes(xpath = "//*[contains(@id, \"school\")]/div[2]/h2") %>%
  html_text() %>%
  as.tibble()

case <- read_html(test[[1]]) %>%
  html_nodes(xpath = "//*[contains(@id, \"school\")]/div[3]/p") %>%
  html_text() %>%
  as.tibble() 

location <- read_html(test[[1]]) %>%
  html_nodes(xpath = "//*[contains(@id, \"school\")]/div[4]/p") %>%
  html_text() %>%
  as.tibble() 

combined_table <- bind_cols(school,case = case[2:nrow(case),],location = location[2:nrow(location),]) 
names(combined_table) <- c("school", "case", "location")

combined_table %>% view()

输出:

# A tibble: 913 x 3
   school                                      case  location              
   <chr>                                       <chr> <chr>                 
 1 University of Alabama at Birmingham*        972   Birmingham, Ala.      
 2 University of North Carolina at Chapel Hill 835   Chapel Hill, N.C.     
 3 University of Central Florida               727   Orlando, Fla.         
 4 University of Alabama                       568   Tuscaloosa, Ala.      
 5 Auburn University                           557   Auburn, Ala.          
 6 North Carolina State University             509   Raleigh, N.C.         
 7 University of Georgia                       504   Athens, Ga.           
 8 Texas A&M University                        500   College Station, Texas
 9 University of Texas at Austin               483   Austin, Texas         
10 University of Notre Dame                    473   Notre Dame, Ind.      
# ... with 903 more rows

希望这对你有用!

【讨论】:

  • 好的,越来越近了。我过去使用过Rselenium,它是这样的(使用带有Docker的Windows机器:shell("docker run -d -p 4445:4444 selenium/standalone-chrome"); remdr &lt;- remoteDriver(port = 4445L, browserName = "chrome"); remdr$open() remdr$navigate("https://www.nytimes.com/interactive/2020/us/covid-college-cases-tracker.html")等,等等......当我使用这种方法时,只需用@987654329从你的代码中替换remote_driver @ 在我的,我只得到前 15 所学校。当我尝试 rsDriver 方法时,它出错了。说版本未对齐。
  • 错误特别指出,Selenium message:session not created: This version of ChromeDriver only supports Chrome version 85. 如果我将chromver 更改为我的浏览器...rsDriver(browser = c("chrome"), chromever = "84.0.4147.89", port = 560L) 我得到:Error in chrome_ver(chromecheck[["platform"]], chromever) : version requested doesnt match versions available = 85.0.4183.38,85.0.4183.83,85.0.4183.87 注意,当我运行binman::list_versions("chromedriver") 时,我得到$win32 [1] "85.0.4183.38" "85.0.4183.83" "85.0.4183.87" 所以我不知道为什么我不能使用版本 85
  • 您的浏览器是 84 版本,是否下载了 chromedriver 84?
  • 我的 Chrome 版本是 84.0.4147.89。我按照说明here 下载了Windows file here。我运行driver &lt;- rsDriver(browser = c("chrome"), chromever = "84.0.4147.30", port = 560L) 并得到错误Error in chrome_ver(chromecheck[["platform"]], chromever) : version requested doesnt match versions available = 85.0.4183.38,85.0.4183.83,85.0.4183.87,它与我运行binman::list_versions("chromedriver") 时看到的相符
  • 有趣。 1)你的工作目录中有另一个 chromedriver.exe 吗? 2) 您是否尝试将 chromedriver.exe (ver 84) 直接放到您当前的工作目录中。 3)如果尝试了以上所有方法,也许将您的 Chrome 更新到最新版本并尝试 chromedriver 85 看看是否有效!抱歉,我在使用 Rselenium 时遇到了开关问题。设置确实需要一段时间
【解决方案2】:

所以我将在这里提供一个违反a very important rule described here 的答案,通常是一个丑陋的解决方案。但它是一个解决方案,让我们避免使用 Selenium。

要在此使用html_nodes,我们需要启动需要 Selenium 的 JS 操作。 @KWN 的解决方案似乎可以在他们的机器上运行,但我无法让 chromedriver 在我的机器上运行。我可以使用带有 Firefox 或 Chrome 的 Docker 获得几乎,但无法获得结果。所以我会先检查那个解决方案。如果失败了,试一试。差不多,这个网站有我需要的数据以 JSON 的形式公开。所以我提取了网站的文本,我使用正则表达式来隔离 JSON,然后 jsonlite 进行解析。

library(jsonlite)
library(rvest)
library(tidyverse)

url <- "https://www.nytimes.com/interactive/2020/us/covid-college-cases-tracker.html"

html_res <- read_html(url)

# get text
text_res <- html_res %>% 
  html_text(trim = TRUE)

# find the area of interest
# find the area of interest
data1 <- str_extract_all(text_res, "(?<=var NYTG_schools = ).*(?=;)")[[1]]

# get json into data frame
json_res <- fromJSON(data1)

# did it work?
glimpse(json_res)

Rows: 1,515
Columns: 16
$ ipeds_id    <chr> "100663", "199120", "132903", "100751"...
$ nytname     <chr> "University of Alabama at Birmingham",...
$ shortname   <chr> "U.A.B.", "North Carolina", "Central F...
$ city        <chr> "Birmingham", "Chapel Hill", "Orlando"...
$ state       <chr> "Ala.", "N.C.", "Fla.", "Ala.", "Ala."...
$ county      <chr> "Jefferson", "Orange", "Orange", "Tusc...
$ fips        <chr> "01073", "37135", "12095", "01125", "0...
$ lat         <dbl> 33.50199, 35.90491, 28.60258, 33.21402...
$ long        <dbl> -86.80644, -79.04691, -81.20223, -87.5...
$ logo        <chr> "https://static01.nyt.com/newsgraphics...
$ infected    <int> 972, 835, 727, 568, 557, 509, 504, 500...
$ death       <int> 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,...
$ dateline    <chr> "n", "n", "n", "n", "n", "n", "n", "n"...
$ ranking     <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,...
$ medicalnote <chr> "y", NA, NA, NA, NA, NA, NA, NA, NA, N...
$ coord       <list> [<847052.5, -406444.3>, <1508445.93, ...

【讨论】:

  • 这也有效。少说一些,也许可以尝试... data1
  • 谢谢你,这更漂亮。会做出改变。
猜你喜欢
  • 1970-01-01
  • 2021-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-01
  • 2016-07-12
相关资源
最近更新 更多