产品价格的搜寻页针对所有商品返回相同的价格

时间:2019-06-27 15:46:31

标签: r rselenium

我正在为教育目标抓取一个网页。

我得到以下值: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")

为什么?

2 个答案:

答案 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.callrbind绑定行。可以将bind_colscbind一起使用,而不是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