【问题标题】:Scraping HTML Text from a <dl> Tag从 <dl> 标签中抓取 HTML 文本
【发布时间】:2017-11-30 11:46:24
【问题描述】:

我有一个从带有议程的网站下载的描述列表,我正在尝试创建一个 data.frame,但没有成功。 描述列表的结构如下:

<dl>
<dt> (which contains a <p = "day"> for day)
<dd> (which contains a <p = "hour"> for hour and a <p = "event"> for the event)

我设法用以下代码提取了这些数据:

library(rvest)
url <- read_html("www.mypage.com")
day <- data.frame(day = html_text(html_nodes(url, '.day')))
hour <- data.frame(hour = html_text(html_nodes(url, '.hour')))
event <- data.frame(event = html_text(html_nodes(url, '.event')))

day$ID <- seq.int(nrow(day))
hour$ID <- seq.int(nrow(hour))
event$ID <- seq.int(nrow(event))

然后我通过按 ID 连接它们创建了一个数据框。

问题是当我有这个时:

<dl>
<dt>
<dd>
<dd>
<dd>

每天不止一个事件。 考虑到同一个&lt;dt&gt; 可能有多个&lt;dd&gt;,我该如何创建我的data.frame?谢谢!

【问题讨论】:

  • 不共享 URL(通常)是为了避免显示您正在执行非法/不道德的活动,或者它是一个内部页面。后者可以理解,前者则不然。您没有提供 HTML 的可重现 sn-p(在没有内容的情况下重复 &lt;dd&gt;s 没有帮助),并且可能有其他节点类或 ID 可以提供帮助。因此,请至少确定目标 URL 的性质(我们中的一些人不会帮助内容窃贼)并包含更好的示例数据或提供 URL。
  • 哦,对不起...我正在为葡萄牙共和国总统的议程做数据。议程在这里:presidencia.pt/?idc=11&fano=2016

标签: r web-scraping rvest


【解决方案1】:

dl/dt/dd 抓取是“为什么 HTML 创建者要对我们这样做”之类的事情之一。这会让你得到你想要的:

library(rvest)
library(tidyverse)

pg <- read_html("http://www.presidencia.pt/?idc=11&fano=2016")

# grab ALL the dt/dd elements under each dl into one big node list
entries <- html_nodes(pg, xpath=".//dl[@id='ms_agend3']/*")

# this finds all of the "dt" elements
starts <- which(xml_name(entries) == "dt")

# this tells us where ^^ "dd"'s stop
ends <- c(starts[-1]-1, length(entries))

# it took 30s for me, so progress bars make the time pass visually
pb <- progress_estimated(length(starts))

# now we iterate over the start/end pairs
map2_df(starts, ends, ~{

  pb$tick()$print() # tick off the progress bar

  # we're only going to work on the part of the node list for this dt/dd set
  start <- .x
  end <- .y

  # get the day
  dt <- html_text(entries[start], trim=TRUE)

  # now iterate over each associated dd and pull out the info
  map_df((start+1):end, ~{
    data_frame(
      hour = html_text(html_node(entries[.x], "div.hora"), trim=TRUE),
      text = html_text(html_node(entries[.x], "div.texto"), trim=TRUE),
    )
  }) %>% 
    mutate(day = dt) # add the day in

}) %>% 
  select(day, hour, text) -> agenda # rearrange and store

由于它制作数据框的方式有点慢,但它会捕获议程的日期/小时/文本(包括我认为是信息或全天事件的空白时间)。

这个:

pb <- progress_estimated(length(starts))
map2_df(starts, ends, ~{

  pb$tick()$print()

  start <- .x
  end <- .y

  data_frame(
    hour = html_text(html_nodes(entries[(start+1):end], "div.hora"), trim=TRUE),
    text = html_text(html_nodes(entries[(start+1):end], "div.texto"), trim=TRUE),
    day = html_text(entries[start], trim=TRUE)
  )

}) %>% 
  select(day, hour, text) -> agenda

就我的眼睛告诉我而言,速度更快,并且产生相同的结果。

【讨论】:

  • 太棒了!!!!想了想花了将近三天的时间才找到解决办法!!!非常感谢。谢谢。
  • 这是最棘手的刮擦方法之一。 XPath 2.0 使它更容易(有点),但 R 或 Python 中的常见抓取库不支持它。我很高兴xml2 提供了足够的功能来使这些变通办法成为可能。
猜你喜欢
  • 2020-02-24
  • 1970-01-01
  • 2020-08-21
  • 2017-05-16
  • 1970-01-01
  • 1970-01-01
  • 2021-05-05
  • 2018-11-26
相关资源
最近更新 更多