【问题标题】:rvest web content scraping issue / car trading websitervest 网页内容抓取问题 / 汽车交易网站
【发布时间】:2017-09-11 19:36:11
【问题描述】:

问题

我想投资网站的特定部分(汽车销售平台)。

坦率地说,CSS 太混乱了,我无法自己找出问题所在。

#### scraping the website www.otomoto.pl with used cars #####

baseURL_otomoto = "https://www.otomoto.pl/osobowe/?page="

i <- 1

for ( i in 1:7000 )
{
  link = paste0(baseURL_otomoto,i)
  out = read_html(link)
  print(i)
  print(link)

  ### building year 
  build_year  = html_nodes(out, xpath = '//*[@id="body-container"]/div[2]/div[1]/div/div[6]/div[2]/article[1]/div[2]/div[3]/ul/li[1]') %>%
    html_text() %>%
    str_replace_all("\n","") %>%
    str_replace_all("\r","") %>%
    str_trim()

  mileage  = html_nodes(out, xpath = '//*[@id="body-container"]/div[2]/div[1]/div/div[6]/div[2]/article[1]/div[2]/div[3]/ul/li[2]') %>%
    html_text() %>%
    str_replace_all("\n","") %>%
    str_replace_all("\r","") %>%
    str_trim()

  volume  = html_nodes(out, xpath = '//*[@id="body-container"]/div[2]/div[1]/div/div[6]/div[2]/article[1]/div[2]/div[3]/ul/li[3]') %>%
    html_text() %>%
    str_replace_all("\n","") %>%
    str_replace_all("\r","") %>%
    str_trim()

  fuel_type  = html_nodes(out, xpath = '//*[@id="body-container"]/div[2]/div[1]/div/div[6]/div[2]/article[1]/div[2]/div[3]/ul/li[4]') %>%
    html_text() %>%
    str_replace_all("\n","") %>%
    str_replace_all("\r","") %>%
    str_trim()


  price = html_nodes(out, xpath = '//div[@class="offer-item__price"]') %>%
    html_text() %>%
    str_replace_all("\n","") %>%
    str_replace_all("\r","") %>%
    str_trim()

  link = html_nodes(out, xpath = '//div[@class="offer-item__title"]') %>%
    html_text() %>%
    str_replace_all("\n","") %>%
    str_replace_all("\r","") %>%
    str_trim()

  offer_details = html_nodes(out, xpath = '//*[@id="body-container"]/div[2]/div[1]/div/div[6]/div[2]/article[1]/div[2]/div[3]/ul') %>%
    html_text() %>%
    str_replace_all("\n","") %>%
    str_replace_all("\r","") %>%
    str_trim()

您猜到这种行为的原因可能是什么?

PS#1。

如何将所分析网站上可用的报价中的所有 build_type、mileage 和fuel_type 数据作为data.frame 一次性获取?使用类 (xpath = '//div[@class=...) 在我的情况下不起作用

PS#2。

我想使用 f.i. 了解实际报价的详细信息

gear_type = html_nodes(out, xpath = '//*[@id="parameters"]/ul[1]/li[10]/div') %>%
    html_text() %>%
    str_replace_all("\n","") %>%
    str_replace_all("\r","") %>%
    str_trim()

论据

  • in ul[a] 用于 a in (1:2) &
  • in li[b] 用于 b in (1:12)

不幸的是,这个概念失败了,因为结果数据框是空的。猜猜为什么?

【问题讨论】:

    标签: r web web-scraping rvest web-scripting


    【解决方案1】:

    首先,了解 CSS 选择器和 XPath。你的选择器很长而且非常脆弱(其中一些对我根本不起作用,仅仅两周后)。例如,而不是:

    html_nodes(out, xpath = '//*[@id="body-container"]/div[2]/div[1]/div/div[6]/div[2]/article[1]/div[2]/div[3]/ul/li[1]') %>%
        html_text()
    

    你可以写:

    html_nodes(out, css="[data-code=year]") %>% html_text()
    

    其次,阅读您使用的库的文档。 str_replace_all 模式可能是正则表达式,这样可以节省一次调用(使用str_replace_all("[\n\r]", "") 而不是str_replace_all("\n","") %&gt;% str_replace_all("\r",""))。 html_text 可以为你做文字修剪,也就是说str_trim() 根本不需要。

    第三,如果你复制粘贴一些代码,退后一步想想函数是否不是更好的解决方案;通常它会。就您而言,就您个人而言,我可能会跳过 str_replace_all 调用直到数据清理步骤,那时我会在 data.frame 上调用它们来保存整个报废数据。


    要从您的数据创建 data.frame,请使用列名和内容调用 data.frame() 函数,如下所示:

    data.frame(build_year = build_year,
        mileage = mileage,
        volume = volume,
        fuel_type = fuel_type,
        price = price,
        link = link,
        offer_details = offer_details)
    

    或者您可以仅使用一列初始化 data.frame,然后添加更多向量作为列:

    output_df <- data.frame(build_year = html_nodes(out, css="[data-code=year]") %>% html_text(TRUE))
    output_df$volume <- html_nodes(out, css="[data-code=engine_capacity]") %>%
      html_text(TRUE)
    

    最后,您应该注意 data.frame 列的长度必须相同,而您废弃的一些数据是可选的。在写这个答案的那一刻,我几乎没有没有引擎容量和报价描述的报价。您必须连续使用两个 html_nodes 调用(因为单个 CSS 选择器不会匹配不存在的选择器)。但即便如此,html_nodes 也会默默地丢弃丢失的数据。这可以通过管道 html_nodes 输出到 html_node 调用来解决:

    current_df$volume  = out %>% html_nodes("ul.offer-item__params") %>% 
        html_node("[data-code=engine_capacity]") %>% 
        html_text(TRUE)
    

    我的循环内部方法的最终版本如下。只需确保在调用它之前初始化空 data.frame 并将当前迭代的输出与最终数据帧合并(例如使用rbind),否则每次迭代都会覆盖前一个迭代的结果。或者你可以使用do.call(rbind, lapply()),这是用于此类任务的惯用 R。

    附带说明,当抓取大量快速变化的数据时,请考虑将数据下载和数据处理步骤解耦。想象一下,有一些你没有考虑到的极端情况会导致 R 终止。如果这种情况出现在您的迭代中间,您将如何进行?您在一个页面上停留的时间越长,您介绍的重复项就越多(随着更多优惠出现并且现有的优惠被下推到更多页面上),并且您错过的优惠越多(随着销售结束并且优惠永远消失)。

    current_df <- data.frame(build_year = html_nodes(out, css="[data-code=year]") %>% html_text(TRUE))
    
    current_df$mileage  = html_nodes(out, css="[data-code=mileage]") %>%
      html_text(TRUE)
    
    current_df$volume  = out %>% html_nodes("ul.offer-item__params") %>% 
        html_node("[data-code=engine_capacity]") %>% 
        html_text(TRUE)
    
    current_df$fuel_type  = html_nodes(out, css="[data-code=fuel_type]") %>%
      html_text(TRUE)
    
    current_df$price = out %>% html_nodes(xpath="//div[@class='offer-price']//span[contains(@class, 'number')]") %>% 
      html_text(TRUE)
    
    current_df$link = out %>% html_nodes(css = "div.offer-item__title h2 > a") %>% 
      html_text(TRUE) %>% 
      str_replace_all("[\n\r]", "")
    
    current_df$offer_details = out %>% html_nodes("div.offer-item__title") %>% 
        html_node("h3") %>% 
        html_text(TRUE)
    

    【讨论】:

    • 谢谢米罗斯瓦夫。您的 cmets 和建议绝对具有巨大的附加值。将尽快返回最终结果(可行)。
    猜你喜欢
    • 1970-01-01
    • 2023-03-22
    • 2017-10-02
    • 2020-04-24
    • 1970-01-01
    • 1970-01-01
    • 2017-11-08
    • 2020-07-18
    • 2019-02-17
    相关资源
    最近更新 更多