Веб-сканирование html таблиц переменной длины - как мне убедиться, что мои данные попадают в правильные столбцы при построении фрейма данных? - PullRequest
0 голосов
/ 20 июня 2020

Я (от начинающего до среднего пользователя R) пытаюсь найти в Интернете данные о большом количестве (~ 12 тыс.) Зданий в Берлине.

Информацию можно найти на веб-страницах ( по одной для каждой здание , итого 12k) агентства наследия Берлина, которые все выглядят как это (веб-сайт на немецком языке, данные, которые меня интересуют, - это таблица в центре, которая начинается с Obj .-Dok-Nr .: 09XXXXXXX и следующие строки, содержащие пригород, адрес et c.).

Все URL-адреса заканчиваются на obj_dok_nr=09xxxxxx (09097890-09010001), что соответствует внутреннему идентификатору здания. , каждое поле таблицы имеет следующий селектор css:

.denkmal_detail_head+ .denkmal_detail_body tr:nth-child(n) td+ td

, где n является целым числом, начиная с 1.

У меня уже есть все идентификаторы 09XXXXXXX в отдельных фрейм данных denkmal_df , который я построил из файла json, который я нашел в другом месте.

Я написал этот код для извлечения данных:

get_URL <- function(key) { #assemble an URL from a denkmal key
  url <- paste0("https://www.stadtentwicklung.berlin.de/denkmal/liste_karte_datenbank/de/denkmaldatenbank/daobj.php?obj_dok_nr=", key)
  return(url)
}

get_Data <- function(url, i, static_css_1, static_css_2) { #Webscraper core, needs to be more flexible, but gets the job done
  css_key <- paste0(static_css_1,i,static_css_2)#Assemble css key to extract information
  print(css_key)
  data <- url %>% read_html() %>% html_nodes(css = css_key ) %>% html_text() #extract information
  return(data)
}

web_data <- matrix(as.character(NA), nrow = 13, ncol = 13) %>% data.frame() #%>% as_tibble() # prepare Dataframe, faster than creating it in the loop # Why can't I create the tibble directly? matrix(NA, nrow = length(denkmal_df$key), ncol = 13) %>% tibble results in a tibble with one column
temp_data <- NA
css1 <- ".denkmal_detail_head tr:nth-child(" #define css structure # possible improvement: more flexibility
css2 <- ") td+ td"

for(key in 1:length(denkmal_df$keys)){ #loop over all the denkmal keys, using an index called key
      i <- 1
      temp_data <- NA
      url <- get_URL(denkmal_df$keys[key]) #retrieve the url by passing the actual denkmal key to the get_URL function
      print(url)
      while (is_empty(temp_data) == F){ #start scraping the website belonging to the current denkmal, until no information can be found (temp_data = empty)
        temp_data <- get_Data(url, i, css1, css2) #retrieve the first category of data, which is indexed on the website by a css path + a number (1 for the first item, 2 for the second...) -> i
        if (i >= ncol(web_data) & is_empty(temp_data) == F) { #check if all columns in the data frame are full, but we still got data from a new category
          web_data[key, i+1:i+5] <- as.character(NA) #expand dataframe with a bunch of NA columns
        }

        if (is_empty(temp_data) == T) {#writing empty values into a dataframe throws an error, so we convert to NA
          temp_data <- as.character(NA)
          web_data[key, i] <- temp_data
          temp_data <- character(0) # and back to empty, to exit the while loop
        }
        else {
          web_data[key, i] <- temp_data # write data to the data frame in row = key(corresponds to postion of the actual key), column = i (represents the category)
          i <- i+1 # increase i to extract the second/etc category, rinse and repeat until no categories are left (temp_data = empty)
        }

      }
    }

Пока он очищает данные в порядке, полученный фрейм данных - беспорядок . Так как некоторые html таблицы имеют больше записей, чем другие (сравните this и this , несколько адресов является обычным явлением), значения повсюду: (Примечание что некоторые были вырезаны ~ форматированием таблицы)

> as_tibble(web_data)
# A tibble: 13 x 13
   X1      X2          X3      X4       X5                                           X6           X7           X8          X9      X10          X11        X12    X13  
   <chr>   <chr>       <chr>   <chr>    <chr>                                        <chr>        <chr>        <chr>       <chr>   <chr>        <chr>      <chr>  <chr>
 1 090978~ Mitte       Gesund~ Putbuss~ 12                                           Swinemünder~ Gesamtanlage Schule & B~ NA      NA           NA         NA     NA   
 2 090978~ Charlotten~ Westend Messeda~ 11 & 12                                      Hammarskjöl~ Baudenkmal   Kongressge~ NA      NA           NA         NA     NA   
 3 090978~ Mitte       Tierga~ Rauchst~ 4 & 5 & 6                                    Stülerstraße 2 & 4        Thomas-Deh~ 1 & 3 ~ Gartendenkm~ Siedlungs~ NA     NA   
 4 090978~ Reinickend~ Tegel   Am Tege~ 2 & 4 & 6 & 8 & 8A & 8B & 8C & 8D & 8E & 10~ Gartendenkm~ Siedlungsgr~ NA          NA      NA           NA         NA     NA   
 5 090978~ Charlotten~ Wilmer~ Prager ~ 4 & 5                                        Prager Stra~ 13           Prinzregen~ 97      Asschaffenb~ Gesamtanl~ Stadt~ NA   
 6 090978~ Mitte       Tierga~ Reichpi~ 48 & 50                                      Gesamtanlage Forschungse~ NA          NA      NA           NA         NA     NA   
 7 090978~ Mitte       Tierga~ Rauchst~ 4 & 5 & 6                                    Stülerstraße 2 & 4        Thomas-Deh~ 1 & 3 ~ Gesamtanlage Wohnanlage NA     NA   
 8 090978~ Mitte       Tierga~ Pohlstr~ 77                                           Baudenkmal   Wohn- und G~ NA          NA      NA           NA         NA     NA   
 9 090978~ Mitte       Tierga~ Lützowu~ 1A & 1B & 2 & 2A & 3 & 3A & 4 & 4A & 5 & 5A  Gesamtanlage Wohnanlage   NA          NA      NA           NA         NA     NA   
10 090978~ Mitte       Tierga~ Lützows~ 44 & 44A & 45 & 45A & 45B & 45C & 45D & 45E~ Gesamtanlage Wohnanlage ~ NA          NA      NA           NA         NA     NA   

Мне нужно название каждой улицы (например, «Pohlstr (aße)», «Stülerstraße») для каждого здания в столбце со всеми названия других улиц, все типы зданий (например, «Wohnanlage», «Schule») в столбце et c. Как я могу этого добиться?

Я уже пробовал соскабливать целые html таблицы в фрейм данных, но это дало аналогичные результаты. У меня нет способа узнать максимальное количество записей, кроме как запустить все l oop для всех 12k html сайтов. (Кроме того, если мой существующий код можно как-то улучшить, не стесняйтесь давать советы

1 Ответ

1 голос
/ 20 июня 2020

На этой странице беспорядок, но с некоторыми хитрыми селекторами CSS это может помочь решить вашу проблему. На данной странице 11 домов, которые нужно разобрать.

Посмотрите, верно ли это хотя бы частично.

См. Комментарии для объяснения кода.

library(rvest)
library(dplyr)

url<-"https://www.stadtentwicklung.berlin.de/denkmal/liste_karte_datenbank/de/denkmaldatenbank/daobj.php?obj_dok_nr=09097874"
page <- read_html(url)
#select nodes
#find the denkmal_detail_body node after the  table.denkmal_detail_sub with 1 intermedidary
infolist<- page %>% html_nodes("table.denkmal_detail_sub + * + table.denkmal_detail_body")
houses <- infolist %>% html_table()

#convert the list of nodes into data frames
dfs<-lapply(houses, function(house){
   #transform to a single row dataframe
   df<-as.data.frame(t(house$X2))
   #rename the columns
   names(df) <-house$X1
   df
})
#bind into the answer
answer <-bind_rows(dfs)


answer

        Teil-Nr.: Sachbegriff:         Strasse:                                                  Hausnummer:
1  09097874,T,001   Stadtvilla Am Tegeler Hafen                                                            2
2  09097874,T,002   Stadtvilla Am Tegeler Hafen                                                            4
3  09097874,T,003   Stadtvilla  Am Tegelerhafen                                                            6
4  09097874,T,004   Stadtvilla Am Tegeler Hafen                                                            8
5  09097874,T,005   Wohnanlage Am Tegeler Hafen                                       8A & 8B & 8C & 8D & 8E
6  09097874,T,006   Stadtvilla Am Tegeler Hafen                                                           10
7  09097874,T,007   Stadtvilla Am Tegeler Hafen                                                           12
8  09097874,T,008   Wohnanlage Am Tegeler Hafen                             14 & 16 & 18 & 20 & 22 & 24 & 26
9  09097874,T,009   Wohnanlage Am Tegeler Hafen 28 & 28A & 28B & 28C & 28D & 28E & 28F & 28G & 28H & 30 & 32
10  09097874,T,10   Wohnanlage Am Tegeler Hafen                                       34 & 36 & 38 & 40 & 42
11 09097874,T,011   Stadtvilla Am Tegeler Hafen                                                           44
                                                                                      Entwurf:
1                              Moore, Charles Willard & Ruble, John & Yudell, Buzz (Architekt)
2                                                    Steinebach, Karl-Heinz & Weber, Friedrich
3                                                      Stern, Robert Arthur Morton (Architekt)
4                                                                           Tigermann, Stanley
5              Bangert, Dietrich & Jansen, Bernd & Scholz, Stefan & Schultes, Axel (Architekt)
6                                                                Portoghesi, Paolo (Architekt)
7                                                                            Grumbach, Antoine
8  Steinebach, Karl-Heinz & Weber, Friedrich & Poly, Regina (Architekt & Landschaftsarchitekt)
9                              Moore, Charles Willard & Ruble, John & Yudell, Buzz (Architekt)
10             Bangert, Dietrich & Jansen, Bernd & Scholz, Stefan & Schultes, Axel (Architekt)
11                                                                    Hejduk, John (Architekt)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...