首页 > 解决方案 > R:如何抓取 {{variable}} 容器

问题描述

webscraping时,我得到:{{price}}. 网络浏览器显示价格 S/1800.00(某个数字),查看源代码是您看到{{price}}.

发生这种情况precio.tarjeta,我正确地得到了所有其他变量。

在此处输入图像描述

代码:

library(rvest)
library(purrr)
library(tidyverse)

urls <- list("https://www.oechsle.pe/tecnologia/televisores/?&optionOrderBy=OrderByScoreDESC&optionOrderBy=OrderByScoreDESC&O=OrderByScoreDESC&optionOrderBy=OrderByScoreDESC&page=1",
             "https://www.oechsle.pe/tecnologia/televisores/?&optionOrderBy=OrderByScoreDESC&optionOrderBy=OrderByScoreDESC&O=OrderByScoreDESC&optionOrderBy=OrderByScoreDESC&page=2")

h <- urls %>% map(read_html) # scrape once, parse as necessary




df <- map_dfr(h %>%
                map(~ .x %>%
                      html_nodes("div.product")), ~
                data.frame(
                  periodo = lubridate::year(Sys.Date()),
                  fecha = Sys.Date(),
                  ecommerce = "oeschle",
                  marca = .x %>% html_node(".brand") %>% html_text(),
                  producto = .x %>% html_node(".prod-name") %>% html_text(),
                  precio.antes = .x %>% html_node('.ListPrice') %>% html_text(),
                  precio.actual = .x %>% html_node('.BestPrice') %>% html_text(),
                  precio.tarjeta = .x %>% html_node('.tOhPrice') %>% html_text()
                ))

更新 1:

我注意到产品会重复自己,即存在重复的产品,即使它们是第 1 页和第 2 页的浏览器中的不同产品。

为什么?

标签: htmlrweb-scrapingpurrr

解决方案


如何抓取 {{variable}} 容器

这里的答案是花一些时间通过研究页面源、调用的各种 JS 脚本和网络选项卡来了解页面如何动态更新自身。我想你可以跳过搜索网络标签并希望在那里找到你想要的东西。但是,在学习一些有关模板、内容提供者、动态页面如何更新等方面的知识时,您会输掉......

您看到的是 JavaScript 模板。内容提供者 VTEX 提供模板和各种脚本,这些脚本驱动这些“占位符”的实际值更新,例如 {{price}} 和 {{percent}}。

为了获得您想要的值,这里需要注意的是,有一个调用 API 端点,带有来自页面的产品 id,并且返回的 JSON 包含您所追求的内容。您可以通过动态提取 id 并将相同的 GET 请求发送到 API 来复制此请求。

借助辅助函数,您可以提取折扣,然后从互联网价格中减去。虽然从 API 调用返回了各种其他价格(以及更多信息),但我决定从初始 GET 请求中提取其他价格。


这是一个 url 的示例:

library(rvest)
library(tidyverse)
library(jsonlite)

get_oh_price <- function(item) {
  var <- item$items[[1]]$sellers[[1]]$commertialOffer$Teasers
  oh_discount <- 100 * ifelse(length(var) == 0, 0, var[[1]]$`<Effects>k__BackingField`$`<Parameters>k__BackingField`[[2]]$`<Value>k__BackingField`) |> as.numeric()
  return(tibble(id = item$productId, oh_discount))
}

api_prefix <- "https://www.oechsle.pe/api/catalog_system/pub/products/search?fq="
api_suffix <- "&_from=0&_to=49&sc=1"

url <- "https://www.oechsle.pe/tecnologia/televisores/?&optionOrderBy=OrderByScoreDESC&optionOrderBy=OrderByScoreDESC&O=OrderByScoreDESC&optionOrderBy=OrderByScoreDESC&page=1"

page <- read_html(url)

listings <- page |> html_elements("[id^=ResultItems_] li[layout]")

df <- map_dfr(listings, ~
data.frame(
  id = .x |> html_element(".product") |> html_attr("data-id"),
  name = .x |> html_element(".product") |> html_attr("data-name"),
  brand = .x |> html_element(".product") |> html_attr("data-brand"),
  category = .x |> html_element(".product") |> html_attr("data-cat"),
  link = .x |> html_element(".product") |> html_attr("data-link"),
  instock = .x |> html_element(".product") |> html_attr("data-stock"),
  antes = .x |> html_element(".ListPrice") |> html_text() |> str_replace_all("S/.\\s+|,|\\.", "") |> as.numeric(),
  internet = .x |> html_element(".BestPrice") |> html_text() |> str_replace_all("S/.\\s+|,|\\.", "") |> as.numeric(),
  currency = "S/"
))

api_request <- paste0(api_prefix, paste(sprintf("productId:%s,", df$id), sep = "", collapse = ""), api_suffix)

product_data <- jsonlite::read_json(api_request)

discount_df <- map_dfr(product_data, get_oh_price)

df <- df |> inner_join(discount_df, by = "id")

df$oh_price <- map2_dbl(df$internet, df$oh_discount, .f = ~ ifelse(.y == 0, NA_integer_, .x - .y))

推荐阅读