用 rvest 从 html 中抓取对象
Scrape object from html with rvest
我是使用 r 进行网络抓取的新手,我正在尝试获取可能不是文本的每日更新对象。 url 是
here 并且我想在页面末尾提取日常情况 table 。这个对象的class是
class="aem-GridColumn aem-GridColumn--default--12 aem-GridColumn--offset--default--0"
我对 html 和 css 没有真正的经验,所以如果您对我如何从网页中提取对象有任何有用的资源或建议,我将不胜感激,因为 SelectorGadget
在这种情况下指示“未找到有效路径。”
如果不从事编写网络爬虫的工作,我认为这应该对您有所帮助:
library(rvest)
url = 'https://covid19.public.lu/en.html'
source = read_html(url)
selection = html_nodes( source , '.cmp-gridStat__item-container' ) %>% html_node( '.number' ) %>% html_text() %>% toString()
可能有更优雅的方法可以有效地做到这一点,但当我需要像这样的蛮力时,我会尝试将其分解成小部分。
- 使用 httr 库获取原始 html。
- 使用str_extract from the stringr库从html中提取特定的数据。
- 我同时使用 positive lookbehind and lookahead 正则表达式来获取我需要的确切数据。它基本上采用 "?<=text_right_before).+?(?=text_right_after)
的形式
library(httr)
library(stringr)
r <- GET("https://covid19.public.lu/en.html")
html<-content(r, "text")
normal_care=str_extract(html, regex("(?<=Normal care: ).+?(?=<br>)"))
intensive_care=str_extract(html, regex("(?<=Intensive care: ).+?(?=</p>)"))
我们可以使用vroom
包
转换从Daily situation update
获得的文本
library(rvest)
library(vroom)
url = 'https://covid19.public.lu/en.html'
df = url %>%
read_html() %>%
html_nodes('.cmp-gridStat__item-container') %>%
html_text2()
vroom(df, delim = '\n', col_names = F)
# A tibble: 22 x 1
X1
<chr>
1 369 People tested positive for COVID-19
2 Per 100.000 inhabitants: 58,13
3 Unvaccinated: 91,20
编辑:
html_element
对比 html_elemnts
html_elemnts
(html_nodes) 的噘嘴是,
[1] "369 People tested positive for COVID-19\n\nPer 100.000 inhabitants: 58,13\n\nUnvaccinated: 91,20\n\nVaccinated: 41,72\n\nRatio Unvaccinated / Vaccinated: 2,19\n\n "
[2] "4 625 Number of PCR tests performed\n\nPer 100.000 inhabitants: 729\n\nPositivity rate in %: 7,98\n\nReproduction rate: 0,97"
[3] "80 Hospitalizations\n\nNormal care: 57\nIntensive care: 23\n\nNew deaths: 1\nTotal deaths: 890"
[4] "6 520 Vaccinations per day\n\nDose 1: 785\nDose 2: 468\nComplementary dose: 5 267"
[5] "960 315 Total vaccines administered\n\nDose 1: 452 387\nDose 2: 395 044\nComplementary dose: 112 884"
html_element
(html_node)` 的
[1] "369 People tested positive for COVID-19\n\nPer 100.000 inhabitants: 58,13\n\nUnvaccinated: 91,20\n\nVaccinated: 41,72\n\nRatio Unvaccinated / Vaccinated: 2,19\n\n "
如您所见,html_nodes
returns 所有与节点关联的值,而 html_node
仅 returns 第一个节点。因此,前者会为您获取真正有用的所有节点。
html_text
对比 html_text2
html_text2
保留了字符串中的断点,通常是\n
和\b
。这些在处理字符串时很有用。
更多信息在 rvest
文档中,
https://cran.r-project.org/web/packages/rvest/rvest.pdf
我想知道您是否可以从他们的任何 public API 中获得相同的数据。如果您只是想要一个带有 table 的 pdf(加上许多其他 table 有用的信息),您可以使用 API 来提取。
如果你想要一个 DataFrame(类似于网页),你可以编写一个用户定义的函数,在 pdftools
的帮助下,从 pdf 重建 table。需要付出更多努力,但由于您已经有了其他关于使用 rvest
的答案,我想我会看看这个。我查看了 tabularize
,但这并不是特别有效。
更有可能的是,您可以将几个 API 数据集放在一起以获得完整内容,而无需解析我使用的 pdf publication,例如有一个 Excel 电子表格给出了案例编号。
N.B。网页中有一些底部计算未包括在下面。我只处理了 pdf 中的测试信息 table。
Rapports 记者:
https://data.public.lu/en/datasets/covid-19-rapports-journaliers/#_
https://download.data.public.lu/resources/covid-19-rapports-journaliers/20211210-165252/coronavirus-rapport-journalier-10122021.pdf
API 数据集:
https://data.public.lu/api/1/datasets/#
library(tidyverse)
library(jsonlite)
## https://data.library.virginia.edu/reading-pdf-files-into-r-for-text-mining/
# install.packages("pdftools")
library(pdftools)
r <- jsonlite::read_json("https://data.public.lu/api/1/datasets/#")
report_index <- match(TRUE, map(r$data, function(x) x$slug == "covid-19-rapports-journaliers"))
latest_daily_covid_pdf <- r$data[[report_index]]$resources[[1]]$latest # coronavirus-rapport-journalier
filename <- "covd_daily.pdf"
download.file(latest_daily_covid_pdf, filename, mode = "wb")
get_latest_daily_df <- function(filename) {
data <- pdf_text(filename)
text <- data[[1]] %>% strsplit(split = "\n{2,}")
web_data <- text[[1]][3:12]
df <- map(web_data, function(x) strsplit(x, split = "\s{2,}")) %>%
unlist() %>%
matrix(nrow = 10, ncol = 5, byrow = T) %>%
as_tibble()
colnames(df) <- text[[1]][2] %>%
strsplit(split = "\s{2,}") %>%
map(function(x) gsub("(.*[a-z])\d+", "\1", x)) %>%
unlist()
title <- text[[1]][1] %>%
strsplit(split = "\n") %>%
unlist() %>%
tail(1) %>%
gsub("\s+", " ", .) %>%
gsub(" TOTAL", "", .)
colnames(df)[2:3] <- colnames(df)[2:3] %>% paste(title, ., sep = " ")
colnames(df)[4:5] <- colnames(df)[4:5] %>% paste("TOTAL", ., sep = " ")
colnames(df)[1] <- "Metric"
clean_col <- function(x) {
gsub("\s+|,", "", x) %>% as.numeric()
}
clean_col2 <- function(x) {
gsub("\n", " ", gsub("([a-z])(\d+)", "\1", x))
}
df <- df %>% mutate(across(.cols = -c(colnames(df)[1]), clean_col),
Metric = clean_col2(Metric)
)
return(df)
}
View(get_latest_daily_df(filename))
输出:
备用:
如果您只想提取项目然后处理,您可以将每一列提取为列表中的项目。替换 br 元素,使这些元素中的内容以逗号分隔的列表结尾:
library(rvest)
library(magrittr)
library(stringi)
library(xml2)
page <- read_html("https://covid19.public.lu/en.html")
xml_find_all(page, ".//br") %>% xml_add_sibling("span", ",") #This method from @hrbrmstr
xml_find_all(page, ".//br") %>% xml_remove()
columns <- page %>% html_elements(".cmp-gridStat__item")
map(columns, ~ .x %>%
html_elements("p") %>%
html_text(trim = T) %>%
gsub("\n\s{2,}", " ", .)
%>%
stri_remove_empty())
我是使用 r 进行网络抓取的新手,我正在尝试获取可能不是文本的每日更新对象。 url 是 here 并且我想在页面末尾提取日常情况 table 。这个对象的class是
class="aem-GridColumn aem-GridColumn--default--12 aem-GridColumn--offset--default--0"
我对 html 和 css 没有真正的经验,所以如果您对我如何从网页中提取对象有任何有用的资源或建议,我将不胜感激,因为 SelectorGadget
在这种情况下指示“未找到有效路径。”
如果不从事编写网络爬虫的工作,我认为这应该对您有所帮助:
library(rvest)
url = 'https://covid19.public.lu/en.html'
source = read_html(url)
selection = html_nodes( source , '.cmp-gridStat__item-container' ) %>% html_node( '.number' ) %>% html_text() %>% toString()
可能有更优雅的方法可以有效地做到这一点,但当我需要像这样的蛮力时,我会尝试将其分解成小部分。
- 使用 httr 库获取原始 html。
- 使用str_extract from the stringr库从html中提取特定的数据。
- 我同时使用 positive lookbehind and lookahead 正则表达式来获取我需要的确切数据。它基本上采用 "?<=text_right_before).+?(?=text_right_after) 的形式
library(httr)
library(stringr)
r <- GET("https://covid19.public.lu/en.html")
html<-content(r, "text")
normal_care=str_extract(html, regex("(?<=Normal care: ).+?(?=<br>)"))
intensive_care=str_extract(html, regex("(?<=Intensive care: ).+?(?=</p>)"))
我们可以使用vroom
包
Daily situation update
获得的文本
library(rvest)
library(vroom)
url = 'https://covid19.public.lu/en.html'
df = url %>%
read_html() %>%
html_nodes('.cmp-gridStat__item-container') %>%
html_text2()
vroom(df, delim = '\n', col_names = F)
# A tibble: 22 x 1
X1
<chr>
1 369 People tested positive for COVID-19
2 Per 100.000 inhabitants: 58,13
3 Unvaccinated: 91,20
编辑:
html_element
对比 html_elemnts
html_elemnts
(html_nodes) 的噘嘴是,
[1] "369 People tested positive for COVID-19\n\nPer 100.000 inhabitants: 58,13\n\nUnvaccinated: 91,20\n\nVaccinated: 41,72\n\nRatio Unvaccinated / Vaccinated: 2,19\n\n "
[2] "4 625 Number of PCR tests performed\n\nPer 100.000 inhabitants: 729\n\nPositivity rate in %: 7,98\n\nReproduction rate: 0,97"
[3] "80 Hospitalizations\n\nNormal care: 57\nIntensive care: 23\n\nNew deaths: 1\nTotal deaths: 890"
[4] "6 520 Vaccinations per day\n\nDose 1: 785\nDose 2: 468\nComplementary dose: 5 267"
[5] "960 315 Total vaccines administered\n\nDose 1: 452 387\nDose 2: 395 044\nComplementary dose: 112 884"
html_element
(html_node)` 的
[1] "369 People tested positive for COVID-19\n\nPer 100.000 inhabitants: 58,13\n\nUnvaccinated: 91,20\n\nVaccinated: 41,72\n\nRatio Unvaccinated / Vaccinated: 2,19\n\n "
如您所见,html_nodes
returns 所有与节点关联的值,而 html_node
仅 returns 第一个节点。因此,前者会为您获取真正有用的所有节点。
html_text
对比 html_text2
html_text2
保留了字符串中的断点,通常是\n
和\b
。这些在处理字符串时很有用。
更多信息在 rvest
文档中,
https://cran.r-project.org/web/packages/rvest/rvest.pdf
我想知道您是否可以从他们的任何 public API 中获得相同的数据。如果您只是想要一个带有 table 的 pdf(加上许多其他 table 有用的信息),您可以使用 API 来提取。
如果你想要一个 DataFrame(类似于网页),你可以编写一个用户定义的函数,在 pdftools
的帮助下,从 pdf 重建 table。需要付出更多努力,但由于您已经有了其他关于使用 rvest
的答案,我想我会看看这个。我查看了 tabularize
,但这并不是特别有效。
更有可能的是,您可以将几个 API 数据集放在一起以获得完整内容,而无需解析我使用的 pdf publication,例如有一个 Excel 电子表格给出了案例编号。
N.B。网页中有一些底部计算未包括在下面。我只处理了 pdf 中的测试信息 table。
Rapports 记者:
https://data.public.lu/en/datasets/covid-19-rapports-journaliers/#_ https://download.data.public.lu/resources/covid-19-rapports-journaliers/20211210-165252/coronavirus-rapport-journalier-10122021.pdf
API 数据集:
https://data.public.lu/api/1/datasets/#
library(tidyverse)
library(jsonlite)
## https://data.library.virginia.edu/reading-pdf-files-into-r-for-text-mining/
# install.packages("pdftools")
library(pdftools)
r <- jsonlite::read_json("https://data.public.lu/api/1/datasets/#")
report_index <- match(TRUE, map(r$data, function(x) x$slug == "covid-19-rapports-journaliers"))
latest_daily_covid_pdf <- r$data[[report_index]]$resources[[1]]$latest # coronavirus-rapport-journalier
filename <- "covd_daily.pdf"
download.file(latest_daily_covid_pdf, filename, mode = "wb")
get_latest_daily_df <- function(filename) {
data <- pdf_text(filename)
text <- data[[1]] %>% strsplit(split = "\n{2,}")
web_data <- text[[1]][3:12]
df <- map(web_data, function(x) strsplit(x, split = "\s{2,}")) %>%
unlist() %>%
matrix(nrow = 10, ncol = 5, byrow = T) %>%
as_tibble()
colnames(df) <- text[[1]][2] %>%
strsplit(split = "\s{2,}") %>%
map(function(x) gsub("(.*[a-z])\d+", "\1", x)) %>%
unlist()
title <- text[[1]][1] %>%
strsplit(split = "\n") %>%
unlist() %>%
tail(1) %>%
gsub("\s+", " ", .) %>%
gsub(" TOTAL", "", .)
colnames(df)[2:3] <- colnames(df)[2:3] %>% paste(title, ., sep = " ")
colnames(df)[4:5] <- colnames(df)[4:5] %>% paste("TOTAL", ., sep = " ")
colnames(df)[1] <- "Metric"
clean_col <- function(x) {
gsub("\s+|,", "", x) %>% as.numeric()
}
clean_col2 <- function(x) {
gsub("\n", " ", gsub("([a-z])(\d+)", "\1", x))
}
df <- df %>% mutate(across(.cols = -c(colnames(df)[1]), clean_col),
Metric = clean_col2(Metric)
)
return(df)
}
View(get_latest_daily_df(filename))
输出:
备用:
如果您只想提取项目然后处理,您可以将每一列提取为列表中的项目。替换 br 元素,使这些元素中的内容以逗号分隔的列表结尾:
library(rvest)
library(magrittr)
library(stringi)
library(xml2)
page <- read_html("https://covid19.public.lu/en.html")
xml_find_all(page, ".//br") %>% xml_add_sibling("span", ",") #This method from @hrbrmstr
xml_find_all(page, ".//br") %>% xml_remove()
columns <- page %>% html_elements(".cmp-gridStat__item")
map(columns, ~ .x %>%
html_elements("p") %>%
html_text(trim = T) %>%
gsub("\n\s{2,}", " ", .)
%>%
stri_remove_empty())