我无法使用 R 抓取 Glassdoor.com 的一个元素

I cannot scrape one element of Glassdoor.com using R

我正在尝试从 Glassdoor.com 中为一个项目抓取一些数据。这是我到目前为止的代码:

## Load libraries
library(httr)  
library(xml2)  
library(rvest) 
library(purrr) 
library(tidyverse)
library(lubridate)

  # URLS for scraping
  start_url <- "https://www.glassdoor.co.uk/Reviews/Company-Reviews-"
  settings_url <- ".htm?sort.sortType=RD&sort.ascending=false&filter.iso3Language=eng"
  
  
  ### Scrape Reviews
  map_df(1:1, function(i){
    Sys.sleep(3)
    tryCatch({
      pg_reviews <- read_html(GET(paste(start_url, "E8450", "_P", i, settings_url, sep = "")))
      table = pg_reviews %>% 
        html_elements(".mb-0")
      
      data.frame(date = pg_reviews %>% 
                   html_elements(".middle.common__EiReviewDetailsStyle__newGrey") %>% 
                   html_text2(),
                 
                 summary = pg_reviews %>% 
                   html_elements(".reviewLink") %>% 
                   html_text(),
                 
                 rating = pg_reviews %>%
                   html_elements("#ReviewsFeed .mr-xsm") %>%
                   html_text(),
                 
                 employee_type = pg_reviews %>%
                   html_elements(".eg4psks0") %>%
                   html_text(),
                 
                 pros = pg_reviews %>%
                   html_elements(".v2__EIReviewDetailsV2__fullWidth:nth-child(1) span") %>%
                   html_text(),
                 
                 cons = pg_reviews %>%
                   html_elements(".v2__EIReviewDetailsV2__fullWidth:nth-child(2) span") %>%
                   html_text()
                 
      )}, error = function(e){
        NULL
      })
    
  }) -> reviews_df

到这里一切正常。但是,我也想在某些评论中删除个人评分: picture

但我真的很难找到与这些评级相关的特定元素。我很乐意提出我的看法,但我完全迷失了这一点。我已尝试使用 SelectorGadget 并检查页面,但我似乎无法管理。

有什么建议吗?

定位数据

检查这些评级中的星星,显示它们具有以下 HTML 结构:

...
<div class="content">
  <ul class="pl-0">
    <li>
      <div>Work/Life Balance</div>
      <div font-size="sm" class="css-18v8tui e1hd5jg10">
        <span class="gd-ui-star  css-vk03c5 e7cj4650" color="#0caa41" font-size="sm" tabindex="0" role="presentation">★</span>
        <span class="gd-ui-star  css-vk03c5 e7cj4650" color="#0caa41" font-size="sm" tabindex="0" role="presentation">★</span>
        <span class="gd-ui-star  css-vk03c5 e7cj4650" color="#0caa41" font-size="sm" tabindex="0" role="presentation">★</span>
        <span class="gd-ui-star  css-vk03c5 e7cj4650" color="#0caa41" font-size="sm" tabindex="0" role="presentation">★</span>
        <span class="gd-ui-star  css-vk03c5 e7cj4650" color="#0caa41" font-size="sm" tabindex="0" role="presentation">★</span>
      </div>
    </li>
    <li>
      <div>Culture &amp; Values</div>
      <div font-size="sm" class="css-18v8tui e1hd5jg10">
        ...
        

CSS定义了其中有多少个是彩色的,通过'Work/Life Balance'下的div的class,例如:

<div font-size="sm" class="css-18v8tui e1hd5jg10">

我们在文档的其他地方找到对应的CSS:

<style data-emotion-css="18v8tui">
  .css-18v8tui {
    display: inline-block;
    line-height: 1;
    background: linear-gradient(90deg, #0caa41 40%, #dee0e3 40%);
    -webkit-letter-spacing: 3px;
    -moz-letter-spacing: 3px;
    -ms-letter-spacing: 3px;
    letter-spacing: 3px;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;                                                                                                                        
  }
</style>

background 值中的 40% 将 div 的 40% 设置为黄色,使本例中 40% 的星星点亮。

提取数据

首先我们加载页面

url = "https://www.glassdoor.co.uk/Reviews/PwC-Reviews-E8450.htm?sort.sortType=RD&sort.ascending=false&filter.iso3Language=eng"
pg_reviews = read_html(url)

然后我们提取所有 <style> 个元素,在本例中每个元素都包含一个 class。我们将 CSS class 中的任何 ...% 值和 divide 中的任何值乘以 20,以将百分比转换为星数。我们将这个数量的星星保存在一个命名向量中,其中每个字段的名称是对应的 CSS class 的名称。这将使我们能够将评级的 CSS class 与许多星相关联。

class.ratings = c()
styles = pg_reviews %>% html_elements('style')
for(s in styles) {
  class = s %>% html_attr('data-emotion-css')
  class = paste0('css-', class)
  rating = str_match(s %>% html_text2(), '(\d+)%')[2]
  class.ratings[class] = as.numeric(rating)/20
}

> class.ratings
css-animation-1fypb1g           css-197m635            css-67i7qe 
                   NA                   5.0                   5.0 
           css-3x0lbp            css-hdvrkk            css-8hewl0 
                   NA                   5.0                   5.0 
          css-1x8evti           css-1ohf0ui           css-1htgz7a 
                   NA                    NA                   5.0 
 ...

并非我们发现的每个百分比都与 star-rating 真正相关,但这没关系。

最后我们抓取所有评论,每个评论都在 class gdReview 的元素中。对于每条评论,我们都会获取所有 star-rating,每个都在 class content 的元素中,在 li 元素中。对于每个 star-rating 我们提取文本标签和 CSS class 作为星星的数量。我不做任何导出结果,只是将它们输出到控制台:

reviews = pg_reviews %>% html_elements('.gdReview')
for(re in reviews) {
  
  ratings = re %>% html_elements('.content') %>% html_elements('li')
  for(ra in ratings) {
    
    label = ra %>% html_element('div') %>% html_text()
    classes = ra %>% html_elements('div[font-size="sm"]') %>% html_attr('class')
    class = str_split(classes, ' ')[[1]][1] # take the first class attribute
    
    cat(label, class.ratings[class], '\n')
    
  }

  cat('\n')
  
}

输出:

Work/Life Balance 5 
Culture & Values 5 
Diversity & Inclusion 5 
Career Opportunities 5 
...

由于并非每个评论都包含这些 star-rating 每个子类别,因此会有一些空白字段。