Зачистка страницы для цены товара возвращает одинаковую цену для всех товаров - PullRequest
1 голос
/ 27 июня 2019

Я очищаю веб-страницу для образовательных целей.

Я получаю следующие значения: producto (продукт), precio_antes (цена_перед), * ​​1005 * (цена_в настоящее время) и 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    |   |

Current Ouput

| 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 ]

1 голос
/ 30 июня 2019

Селен медленный и должен использоваться только в качестве крайней меры. В этом случае это не нужно, поскольку API каталога доступен. API также предлагает более богатые, хорошо структурированные данные. Можно запросить 50 элементов за раз, так что вы можете увеличивать до 0, 50 и т. Д., Пока общая длина возвращаемого содержимого не станет <50, а затем вы можете получить необходимую информацию по имени и / или целочисленной позиции. </p>

Числа 1000144 и 1000098 в URL относятся к отделу и категории и могут быть извлечены из узла script в HTML-коде https://www.wong.pe/tecnologia/televisores/tv. Я не делал этого здесь, чтобы упростить задачу, но это возможно, если вы хотите более адаптируемый скребок.

Вместо 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
1 голос
/ 29 июня 2019

Редактирование добавляет отличную спецификацию, спасибо!

Я предполагаю, что вы хотите снова отслеживать отсутствующие элементы с помощью 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
...