使用javascript进行rvest web抓取

时间:2018-05-17 00:36:05

标签: javascript html css r rvest

我正在尝试使用rvestFiveThirtyEight获取每日预测,但我感兴趣的对象似乎是一个javascript对象,我甚至很难找到寻找的位置和内容。 (虽然我在过去几天试图教育自己,但我并不精通CSS或Javascript。)

通过检查网页元素和CSS选择器,我发现了以下内容:

  • 要查看的位置是<div id="polling-avg-chart">,所以我尝试了

    library(rvest)
    url <- 
      "https://projects.fivethirtyeight.com/election-2016/national-primary-polls/democratic/"
    
    url %>% 
      read_html() %>% 
      html_nodes("#polling-avg-chart")
    

    没有太大的成功。输出只是

      

    {xml_nodeset(1)}

         

    [1]&lt; \ div id =&#34; polling-avg-chart&#34;&gt;&lt; / div&gt; \ n

  • 单个民意调查结果中的点位于<g style="clip-path: url("#line-clippoll_avg");"> ... </g>,您可以在其中看到502个数字位置。我猜我必须将每个节点的cxcy翻译成适当的百分比,这由<g class="flag-box" transform="translate(30, 161.44093322753096)">...</g>完成,依此类推。

  • 但是,我没有看到预测线的基础数据,而不是点。

  • 当我将光标悬停在图表上时,我看到<line class="hover-date-line hide-line">之类的内容发生了变化,<path class="link" d="M 0 171.40106812500002 C 15 171.40106812500002 15 170.94093803735575 30 170.94093803735575"></path>之类的值发生了变化,我猜这些值是什么&#39} ; s创建每日预测线。
  • 但是这些价值存储的地方,以及如何将其转化为像克林顿和26.6%桑德斯那样的事情。对我来说仍然是一个谜。

我确实阅读了其他一些SO帖子,例如this,但它们似乎都不适用于这个特定问题。在整洁的数据框架中获得预测百分比的最佳方法是什么?

2 个答案:

答案 0 :(得分:1)

这里的图表几乎肯定是用d3.js或它上面的包装器构建的。 d3非常适合构建基于svg的数据可视化,因为它可以帮助您构建比例尺以将值(例如40%)映射到屏幕上的展示位置(例如您看到的内容,例如cx=100)。问题是你需要知道那些尺度是什么,以便获得基础数据,并且尺度可能是动态的,并且会根据屏幕尺寸等而变化。

相反,由于数据位于下表中,您可以轻松地将其删除。该表位于标识为div的{​​{1}}元素内,并且具有类latest-polls

我正在使用t-polls和CSS选择器html_node将表格转换为数据框,清理名称,并将数字列转换为实际的数字列。接下来你可以做更多的事情,比如格式化日期,但希望这能让你开始。

html_table

答案 1 :(得分:1)

另一种方法是直接获取资源。

在浏览器中,打开开发人员工具(Chrome / Chromium中的 F12 ),前往&#34;网络&#34;,刷新( F5 ),然后查看看起来像一个格式很好的JSON。当我们找到它时,我们会复制链接地址(右键单击资源&gt;复制链接地址)。

enter image description here

library(httr)
library(tidyr)
library(purrr)
library(dplyr)
library(ggplot2)

url <- "https://projects.fivethirtyeight.com/election-2016/national-primary-polls/USA.json"

r <- GET(url)

整个数据都存在。权重也是如此,因此您可以重新计算这些平均值。绘制的数据位于"model"

dat <- 
  jsonlite::fromJSON(content(r, as = "text")) %>% 
  map(purrr::pluck, "model") %>% 
  bind_rows(.id = "party") %>% 
  mutate_all(readr::parse_guess)

# # A tibble: 5,288 x 5
#    party candidate_name state forecastdate poll_avg
#    <chr> <chr>          <chr> <date>          <dbl>
#  1 D     Sanders        USA   2016-07-01       36.5
#  2 D     Clinton        USA   2016-07-01       55.4
#  3 D     Sanders        USA   2016-06-30       37.0
#  4 D     Clinton        USA   2016-06-30       54.6
#  5 D     Sanders        USA   2016-06-29       37.0
#  6 D     Clinton        USA   2016-06-29       54.9
#  7 D     Sanders        USA   2016-06-28       37.2
#  8 D     Clinton        USA   2016-06-28       54.4
#  9 D     Sanders        USA   2016-06-27       37.4
# 10 D     Clinton        USA   2016-06-27       53.9
# # ... with 5,278 more rows

重现图表:

dat %>% 
  filter(candidate_name %in% c("Clinton", "Kasich", "Sanders", "Trump")) %>% 
  ggplot(aes(forecastdate, poll_avg)) +
  geom_line(aes(col = candidate_name)) +
  facet_wrap(~party)

enter image description here

如果你喜欢互动:

library(dygraphs)
library(htmltools)

foo <- dat %>% 
  filter(candidate_name %in% c("Clinton", "Kasich", "Sanders", "Trump")) %>% 
  split(.$party) %>% 
  map(~ {
    select(.x, forecastdate, candidate_name, poll_avg) %>% 
      spread(candidate_name, poll_avg) %>% 
      {xts(.[-1], .[[1]])} %>%
      dygraph(group = "poll-model") %>% 
      dyRangeSelector()
  })

browsable(tagList(foo))

enter image description here