selectorgadget scraping paquete page hacer español con como r tags web-scraping rvest

paquete - web scraping con r



Raspado con rvest-completo con NA cuando la etiqueta no está presente (4)

Puede que no sea la forma más idiomática de hacerlo, pero puede usar lapply sobre los nodos .product_price como este:

r.precio.antes <- page_source %>% html_nodes(".product_price") %>% lapply(. %>% html_nodes(".normal_encontrado") %>% html_text() %>% ifelse(identical(., character(0)), NA, .)) %>% unlist

Esto devolverá NA siempre que no se encuentre el elemento .normal_encontrado .

r.precio.antes # [1] "/n S/. 2,799.00/n " # [2] NA length(r.precio.antes) # 2

Si quería desarrollar el código para hacerlo más claro, primero .product_price nodos .product_price :

product_nodes <- page_source %>% html_nodes(".product_price")

Entonces podría usar lapply de una manera más tradicional:

r.precio.antes <- lapply(product_nodes, function(pn) { pn %>% html_nodes(".normal_encontrado") %>% html_text() }) r.precio.antes <- unlist(r.precio.antes)

En su lugar, estoy usando la sintaxis magrittr para lapply , ver, por ejemplo, el final del párrafo de secuencias funcionales aquí .

Un último obstáculo es que si no se encuentra el elemento, este devolverá el character(0) lugar de NA como usted quería. Así que estoy agregando ifelse(identical(., character(0)), NA, .)) ,. ifelse(identical(., character(0)), NA, .)) la tubería dentro de la aplicación para arreglar eso.

Quiero analizar este HTML: y obtener estos elementos de él:

a) etiqueta p , con class: "normal_encontrado" .
b) div con class: "price" .

A veces, la etiqueta p no está presente en algunos productos. Si este es el caso, se debe agregar una NA al vector que recoge el texto de estos nodos.

La idea es tener 2 vectores con la misma longitud, y luego unirlos para hacer un data.frame . ¿Algunas ideas?

La parte HTML:

<html> <head></head> <body> <div class="product_price" id="product_price_186251"> <p class="normal_encontrado"> S/. 2,799.00 </p> <div id="WC_CatalogEntryDBThumbnailDisplayJSPF_10461_div_10" class="price"> S/. 2,299.00 </div> </div> <div class="product_price" id="product_price_232046"> <div id="WC_CatalogEntryDBThumbnailDisplayJSPF_10461_div_10" class="price"> S/. 4,999.00 </div> </div> </body> </html>

Código R:

library(rvest) page_source <- read_html("r.html") r.precio.antes <- page_source %>% html_nodes(".normal_encontrado") %>% html_text() r.precio.actual <- page_source %>% html_nodes(".price") %>% html_text()


Sube un nivel desde tu objetivo y lapply cada elemento padre:

library(xml2) library(rvest) pg <- read_html(''<html> <head></head> <body> <div class="product_price" id="product_price_186251"> <p class="normal_encontrado"> S/. 2,799.00 </p> <div id="WC_CatalogEntryDBThumbnailDisplayJSPF_10461_div_10" class="price"> S/. 2,299.00 </div> </div> <div class="product_price" id="product_price_232046"> <div id="WC_CatalogEntryDBThumbnailDisplayJSPF_10461_div_10" class="price"> S/. 4,999.00 </div> </div> </body> </html>'') prod <- html_nodes(pg, "div.product_price") do.call(rbind, lapply(prod, function(x) { norm <- tryCatch(xml_text(xml_node(x, "p.normal_encontrado")), error=function(err) {NA}) price <- tryCatch(xml_text(xml_node(x, "div.price")), error=function(err) {NA}) data.frame(norm, price, stringsAsFactors=FALSE) })) ## norm price ## 1 /n S/. 2,799.00/n /n S/. 2,299.00/n ## 2 <NA> /n S/. 4,999.00/n

No tengo idea si querías recortar las cuerdas o hacer cualquier otra cosa, pero esas maquinaciones son bastante fáciles.


Usando el paquete XML, xmlTreeParse la entrada con xmlTreeParse y luego use xpathSApply para interar sobre los nodos div clase product_price . Para cada nodo, la función anónima obtiene el valor de los subnodos div y p . La matriz de caracteres resultante m se vuelve a trabajar en un marco de datos DF y las columnas se limpian eliminando cualquier carácter que no sea un punto o dígito y también eliminando cualquier punto seguido de un no dígito. Copnvert resultado a numérico. Tenga en cuenta que no es necesario un procesamiento especial para el caso de p faltante.

# input Lines <- ''<html> <head></head> <body> <div class="product_price" id="product_price_186251"> <p class="normal_encontrado"> S/. 2,799.00 </p> <div id="WC_CatalogEntryDBThumbnailDisplayJSPF_10461_div_10" class="price"> S/. 2,299.00 </div> </div> <div class="product_price" id="product_price_232046"> <div id="WC_CatalogEntryDBThumbnailDisplayJSPF_10461_div_10" class="price"> S/. 4,999.00 </div> </div> </body> </html>'' # code to read input and produce a data.frame library(XML) doc <- xmlTreeParse(Lines, asText = TRUE, useInternalNodes = TRUE) m <- xpathSApply(doc, "//div[@class = ''product_price'']", function(node) { list(p = xmlValue(node[["p"]]), div = xmlValue(node[["div"]])) }) DF <- as.data.frame(t(m), stringsAsFactors = FALSE) # rework into data frame DF[] <- lapply(DF, function(x) as.numeric(gsub("[^.0-9]|[.]//D", "", x))) # clean

El resultado es:

> DF p div 1 2799 2299 2 NA 4999


Si no se encuentra la etiqueta, rvest devuelve un carácter (0). Asumiendo que encontrará como máximo un precio actual y un precio regular en cada div.product_price, puede usar esto:

pacman::p_load("rvest", "dplyr") get_prices <- function(node){ r.precio.antes <- html_nodes(node, ''p.normal_encontrado'') %>% html_text r.precio.actual <- html_nodes(node, ''div.price'') %>% html_text data.frame( precio.antes = ifelse(length(r.precio.antes)==0, NA, r.precio.antes), precio.actual = ifelse(length(r.precio.actual)==0, NA, r.precio.actual), stringsAsFactors=F ) } doc <- read_html(''test.html'') %>% html_nodes("div.product_price") lapply(doc, get_prices) %>% rbind_all

Editado: entendí mal los datos de entrada, así que cambié el guión para trabajar con una sola página html.