R - Очистка HTML-таблицы с помощью rvest, когда отсутствуют теги ‹tr›

Я пытаюсь очистить таблицу HTML с веб-сайта с помощью rvest. Единственная проблема заключается в том, что таблица, которую я пытаюсь очистить, не имеет тегов <tr>, кроме первой строки. Это выглядит так:

<tr> 
  <td>6/21/2015 9:38 PM</td>
  <td>5311 Lake Park</td>
  <td>UCPD</td>
  <td>African American</td>
  <td>Male</td>
  <td>Subject was causing a disturbance in the area.</td>
  <td>Name checked; no further action</td>
  <td>No</td>
</tr>

  <td>6/21/2015 10:37 PM</td>
  <td>5200 S Blackstone</td>
  <td>UCPD</td>
  <td>African American</td>
  <td>Male</td>
  <td>Subject was observed fighting in the McDonald's parking lot</td>
  <td>Warned; released</td>
  <td>No</td>
</tr>

И так далее. Итак, используя следующий код, я могу получить только первую строку в моем фрейме данных:

library(rvest)
mydata <- html_session("https://incidentreports.uchicago.edu/incidentReportArchive.php?startDate=06/01/2015&endDate=06/21/2015") %>%
    html_node("table") %>%
    html_table(header = TRUE, fill=TRUE)

Как я могу изменить это, чтобы html_table понимал, что строки являются строками, даже если у них нет открывающего тега <tr>? Или есть лучший способ сделать это?


person jonahshai    schedule 22.06.2015    source источник
comment
Почему бы сначала не заменить любой закрывающий </tr> на </tr><tr>, а затем удалить последний завершающий <tr>?   -  person Bram Vanroy    schedule 22.06.2015


Ответы (2)


Немного другой подход, чем у @ user227710, но в целом такой же. Это аналогично использует тот факт, что количество TD одинаково.

Однако при этом также собираются все инциденты (rbind каждая страница помещается в один incidents фрейм данных).

pblapply просто показывает индикаторы выполнения, поскольку это занимает несколько секунд. Совершенно необязательно, если только не в интерактивном сеансе.

library(rvest)
library(stringr)
library(dplyr)
library(pbapply)

url <- "https://incidentreports.uchicago.edu/incidentReportArchive.php?startDate=06/01/2015&endDate=06/21/2015"
pg <- read_html(url)

pg %>% 
  html_nodes("li.page-count") %>% 
  html_text() %>% 
  str_trim() %>% 
  str_split(" / ") %>%
  unlist %>% 
  as.numeric %>% 
  .[2] -> total_pages

pblapply(1:(total_pages), function(j) {

  # get "column names"
  # NOTE that you get legit column names for use with "regular" 
  # data frames this way

  pg %>% 
    html_nodes("thead > tr > th") %>% 
    html_text() %>% 
    make.names -> tcols

  # get all the TDs

  pg %>% 
    html_nodes("td") %>%
    as_list() -> tds

  # how many rows do we have? (shld be 5, but you never know)

  trows <- length(tds) / 7

  # the basic idea is to grab all the TDs for each row
  # then cbind them together and then rbind the whole thing
  # while keeping decent column names

  bind_rows(lapply(1:trows, function(i) {
    setNames(cbind.data.frame(lapply(1:7, function(j) { 
      html_text(tds[[(i-1)*7 + j]])
    }), stringsAsFactors=FALSE), tcols)
  })) -> curr_tbl

  # get next url

  pg %>% 
    html_nodes("li.next > a") %>% 
    html_attr("href") -> next_url

  if (j < total_pages) {
    pg <<- read_html(sprintf("https://incidentreports.uchicago.edu/%s", next_url))
  }

  curr_tbl

}) %>% bind_rows -> incidents

incidents

## Source: local data frame [62 x 7]
## 
##                            Incident                                  Location        Reported
## 1                             Theft       1115 E. 58th St. (Walker Bike Rack) 6/1/15 12:18 PM
## 2                       Information                          5835 S. Kimbark   6/1/15 3:57 PM
## 3                       Information                  1025 E. 58th St. (Swift)  6/2/15 2:18 AM
## 4   Non-Criminal Damage to Property                850 E. 63rd St. (Car Wash)  6/2/15 8:48 AM
## 5       Criminal Damage to Property 5631 S. Cottage Grove (Parking Structure)  6/2/15 7:32 PM
## 6  Information / Aggravated Robbery                4701 S. Ellis (Public Way)  6/3/15 2:11 AM
## 7                     Lost Property           5800 S. University  (Main Quad)  6/3/15 8:30 AM
## 8       Criminal Damage to Property         5505 S. Ellis (Parking Structure) 5/29/15 5:00 PM
## 9       Information / Armed Robbery        6300 S. Cottage Grove (Public Way)  6/3/15 2:33 PM
## 10                    Lost Property                1414 E. 59th St. (I-House)  6/3/15 2:28 PM
## ..                              ...                                       ...             ...
## Variables not shown: Occurred (chr), Comments...Nature.of.Fire (chr), Disposition (chr), UCPDI. (chr)
person hrbrmstr    schedule 22.06.2015

Спасибо всем! В итоге я получил некоторую помощь от другого пользователя R в автономном режиме, который предложил следующее решение. Он берет html, сохраняет его, добавляет в <tr> (так же, как предложил @Bram Vanroy) и превращает его обратно в объект html, который затем может быть скопирован во фрейм данных.

library(rvest)
myurl <- "https://incidentreports.uchicago.edu/incidentReportArchive.php?startDate=06/01/2015&endDate=06/21/2015"
download.file(myurl, destfile="myfile.html", method="curl")
myhtml <- readChar("myfile.html", file.info("myfile.html")$size)
myhtml <- gsub("</tr>", "</tr><tr>", myhtml, fixed = TRUE)
mydata <- html(myhtml)

mydf <- mydata %>%
  html_node("table") %>%
  html_table(fill = TRUE)

mydf <- na.omit(mydf)

Последняя строка - опустить некоторые странные строки NA, которые появляются с этим методом.

person jonahshai    schedule 23.06.2015