#r #web-scraping #rvest
Вопрос:
У меня есть фрейм данных, в одном из столбцов которого содержатся ссылки на веб-страницы, которые я хочу очистить с помощью rvest. Я хотел бы загрузить некоторые ссылки, сохранить их в другой колонке и загрузить с них некоторые тексты. Я пытался сделать это с помощью lapply
, но я добрался Error in UseMethod("xml_find_all") : no applicable method for 'xml_find_all' applied to an object of class "function"
до второго шага. Возможно, проблема может заключаться в том, что первые ссылки сохраняются в виде списка. Вы знаете, как я могу это решить?
Это мой MWE (в моем полном наборе данных у меня около 5000 ссылок, должен ли я использовать Sys.sleep
и как?)
library(rvest)
df <- structure(list(numeroAtto = c("2855", "2854", "327", "240", "82"
), testo = c("http://dati.camera.it/ocd/versioneTestoAtto.rdf/vta18_leg.18.pdl.camera.2855.18PDL0127540",
"http://dati.camera.it/ocd/versioneTestoAtto.rdf/vta18_leg.18.pdl.camera.327.18PDL0003550",
"http://dati.camera.it/ocd/versioneTestoAtto.rdf/vta18_leg.18.pdl.camera.327.18PDL0003550",
"http://dati.camera.it/ocd/versioneTestoAtto.rdf/vta18_leg.18.pdl.camera.240.18PDL0007740",
"http://dati.camera.it/ocd/versioneTestoAtto.rdf/vta18_leg.18.pdl.camera.82.18PDL0001750"
)), row.names = c(NA, 5L), class = "data.frame")
df$links_text <- lapply(df$testo, function(x) {
page <- read_html(x)
links <- html_nodes(page, '.value:nth-child(8) .fixed') %>%
html_text(trim = T)
})
df$text <- lapply(df$links_text, function(x) {
page1 <- read_html(x)
links1 <- html_nodes(page, 'p') %>%
html_text(trim = T)
})
Ответ №1:
Вы хотите links1 <- html_nodes(page, 'p')
сослаться page1
, а не page
.
[В противном случае (поскольку page
в среде функций нет объекта, он пытается применить html_nodes к функции utils page
]
С точки зрения Sys_sleep
, это довольно необязательно. Проверьте html-код страницы и посмотрите, есть ли в коде или пользовательском соглашении что-либо, запрещающее очистку. Если это так, то более любезное обращение к серверу может повысить ваши шансы на то, что вас не заблокируют!
Вы можете просто включить Sys.sleep(n)
в свою функцию, где вы создаете df$text
. n зависит от вас, мне повезло с 1-3 секундами, но это становится довольно медленным/долгим!
Комментарии:
1. Большое спасибо за вашу помощь! Я только что понял, что первый
lapply
возвращает список. В результате после второгоlapply
я получаю текст, который объединяет тексты, содержащиеся на всех веб-страницах. У вас есть какие-нибудь предложения?
Ответ №2:
Вы можете сделать это в одной sapply
команде и использовать tryCatch
для обработки ошибок.
library(rvest)
df$text <- sapply(df$testo, function(x) {
tryCatch({
x %>%
read_html() %>%
html_nodes('.value:nth-child(8) .fixed') %>%
html_text(trim = T) %>%
read_html %>%
html_nodes('p') %>%
html_text(trim = T) %>%
toString()
}, error = function(e) NA)
})
Комментарии:
1. Чем вам очень нравится, это работает! однако, когда я использую его для своего полного набора данных, я получаю
Error: Document is empty
. Может быть, какие-то ссылки не работают? Есть ли способ это исправить?2. Да, вы можете использовать
tryCatch
, см. Обновленный ответ @Edoardo