我正在为教育目标抓取一个网页。
我得到以下值:producto
(产品),precio_antes
(price_before),precio_actual
(price_now)和marca
(品牌)。
我把产品弄对了,但是:
precio_antes
对所有商品返回S / 1,399.00 precio_actual
返回所有项目的NA。marca
为所有项目返回“ lg”。预期输出:
| ecommerce | marca | producto | precio_antes | precio_actual | |
|-----------|-------|------------------------------------------|--------------|---------------|---|
| wong | lg | LG Smart TV 49" Full HD 49LK5400 | S/1,399.00 | S/1,299.00 | |
| wong | lg | LG Smart TV 60" 4K UHD 60UK6200 ThinQ AI | S/2,599.00 | S/2,299.00 | |
当前输出
| ecommerce | marca | producto | precio_antes | precio_actual | |
|-----------|-------|------------------------------------------|--------------|---------------|---|
| wong | lg | LG Smart TV 49" Full HD 49LK5400 | S/1,399.00 | NA | |
| wong | lg | LG Smart TV 60" 4K UHD 60UK6200 ThinQ AI | S/1,399.00 | NA | |
我正在使用RSelenium
,我认为我的CSS选择器技能需要提高。
library(RSelenium)
library(rvest)
library(dplyr)
library(stringr)
#start RSelenium
rD <- rsDriver(port = 4570L, browser = "chrome", version = "latest", chromever = "75.0.3770.90",
geckover = "latest", iedrver = NULL, phantomver = "2.1.1",
verbose = TRUE, check = TRUE)
remDr <- rD[["client"]]
#navigate to your page
remDr$navigate("https://www.wong.pe/tecnologia/televisores/tv")
#scroll down 10 times, waiting for the page to load at each time
for(i in 1:10){
remDr$executeScript(paste("scroll(0,",i*10000,");"))
Sys.sleep(3)
}
#get the page html
page_source<-remDr$getPageSource()
product_info <- function(node){
precio_antes <- html_nodes(node, 'span.product-prices__value') %>% html_text
precio_actual <- html_nodes(node, 'span.product-prices__value product-prices__value--best-price') %>% html_text
marca <- html_nodes(node,"p.brand") %>% html_text
producto <- html_nodes(node,"a.product-item__name") %>% html_text
precio_antes <- gsub("\\S\\/\\. ", "", precio_antes)
precio_actual <- gsub("\\S\\/\\. ", "", precio_actual)
data.frame(
ecommerce = "wong",
marca = ifelse(length(marca)==0, NA, marca),
producto = producto,
precio_antes = ifelse(length(precio_antes)==0, NA, precio_antes),
precio_actual = ifelse(length(precio_actual)==0, NA, precio_actual),
stringsAsFactors=F
)
}
doc <- read_html(iconv(page_source[[1]]), to="UTF-8") %>%
html_nodes("div.category-shelf-wrapper")
wong_tvs <- lapply(doc, product_info) %>%
bind_rows()
奖金:
即使使用以下命令,我也无法以正确的方式获取西班牙语字符:
LG Control Remoto Mágico AN-MR18BA #Should be Mágico
doc <- read_html(iconv(page_source[[1]]), to="UTF-8") %>%
html_nodes("div.category-shelf-wrapper")
为什么?
答案 0 :(得分:1)
编辑添加了一个很好的规范,谢谢!
我假设您想使用输出中的NA
再次跟踪缺少的元素。
按照这个假设,与其他问题类似,我将再次选择父元素。
可以找到父元素,例如通过xpath:/html/body/div/div/div/div/div/div/div/div/ul/li/div/div[@class = 'product-item__bottom']
。
之后,您只需要将结果拆分为所需的格式即可。
可复制的示例:
library(RSelenium)
rD <- rsDriver()
remDr <- rD$client
url = "https://www.wong.pe/tecnologia/televisores"
remDr$navigate(url)
productElems = remDr$findElements(
using = "xpath",
value = "/html/body/div/div/div/div/div/div/div/div/ul/li/div/div[@class = 'product-item__bottom']"
)
productInfoRaw = sapply(
X = productElems,
FUN = function(elem) elem$getElementText()
)
splittedRaw = sapply(productInfoRaw, strsplit, split = "\n")
splitted = lapply(splittedRaw, function(split){
if(length(split) == 5 & "Online" %in% split){
split[7] = split[4]
split[4] = NA
}
return(split)
})
infos = data.frame(
ecommerce = "wong",
marca = sapply(splitted, "[", 2),
producto = sapply(splitted, "[", 1),
precio_antes = sapply(splitted, "[", 4),
precio_actual = sapply(splitted, "[", 7)
)
head(infos)
输出:
> head(infos)
ecommerce marca producto precio_antes precio_actual
1 wong LG LG Smart TV 49" Full HD 49LK5400 S/1,399.00 S/1,299.00
2 wong LG LG Smart TV 60" 4K UHD 60UK6200 ThinQ AI S/2,599.00 S/2,299.00
3 wong LG LG Control Remoto Mágico AN-MR18BA <NA> S/199.00
4 wong AOC AOC Smart TV 32'' HD LE32S5970S Linux S/799.00 S/599.00
5 wong LG LG Smart TV 43" FHD 43LK5400 S/1,199.00 S/999.00
6 wong HISENSE Hisense Televisor LED 32'' HD H3218H4IP S/1,299.00 S/499.00
答案 1 :(得分:1)
硒很慢,只能作为不得已的手段。在这种情况下,由于目录API是公开的,因此没有必要。该API还提供了更丰富,结构良好的数据。一次可以请求50个项目,因此您可以递增0、50等,直到返回的内容的总长度小于50,然后可以按名称和/或整数位置提取所需的信息。
URL中的数字1000144和1000098表示部门和类别,可以从https://www.wong.pe/tecnologia/televisores/tv的HTML中的script
节点中提取。在这里我没有这样做,只是为了简化操作,但如果您想使用更适应性的刮板,则有可能。
您也可以使用glue
代替paste0
。可以使用map_df
代替lapply
,然后使用do.call
和rbind
绑定行。可以将bind_cols
与cbind
一起使用,而不是as.data.frame
。我喜欢这些函数,因为它们简化了事情,避免了类型强制问题,并总体上提高了代码的可读性,但是没有什么可以阻止您使用基本的R函数。
为简单起见,我保留了原始变量名。您可以使用names(tvs_df) <- …
更改它们,也可以使用map_df
调用set_names(…)
之后,即map_df(…) %>% set_names(…)
:
library(httr) # for `GET`
library(glue) # for `glue`, which allows cleaner syntax than `paste0`
library(purrr) # for `map_df` to map over list and return as dataframe
library(dplyr) # for `bind_cols`
i <- 0
cont_list <- list()
# Send requests and append data `cont_list` until fewer than 50 items returned.
repeat {
url <- glue("https://www.wong.pe/api/catalog_system/pub/products/search/",
"?&fq=C:/1000144/1000098/&_from={i}&_to={i + 49}")
cont <- content(GET(url))
cont_list <- c(cont_list, cont)
if (length(cont) < 50) break
i <- i + 50
}
# Names of desired data.
datl <- list(l1 = c("brand", "productName"),
l2 = c("Price", "ListPrice", "AvailableQuantity"))
# Extract data
tvs_df <- map_df(cont_list,
~ bind_cols(source = "wong.pe", .[datl$l1],
.$items[[1]]$sellers[[1]]$commertialOffer[datl$l2]))
哪个返回:
# A tibble: 54 x 6
source brand productName Price ListPrice AvailableQuantity
<chr> <chr> <chr> <dbl> <dbl> <int>
1 wong.pe LG "LG Smart TV 49\" Full HD 49LK5400" 1299 1399 276
2 wong.pe LG "LG Smart TV 60\" 4K UHD 60UK6200 ThinQ AI" 2299 2599 18
3 wong.pe LG LG Control Remoto Mágico AN-MR18BA 199 199 37
4 wong.pe AOC AOC Smart TV 32'' HD LE32S5970S Linux 599 799 90
5 wong.pe LG "LG Smart TV 43\" FHD 43LK5400" 999 1199 303
6 wong.pe Hisense Hisense Televisor LED 32'' HD H3218H4IP 499 1299 22
7 wong.pe LG "LG Smart TV 55\" 4K UHD 55UK6200 ThinQ AI" 1799 2199 31
8 wong.pe Panasonic Panasonic Smart TV Viera 32'' HD 32FS500 799 999 4
9 wong.pe AOC AOC Smart TV 55'' 4K UHD 55U7970 Linux 1299 2499 3
10 wong.pe AOC AOC Televisor LED 32'' HD 32M1370 499 699 4
# … with 44 more rows