Chuyển đến nội dung chính

Web Scraping trong R: Hướng dẫn rvest

Khám phá web scraping trong R với rvest qua một dự án thực tế: trích xuất, tiền xử lý và phân tích đánh giá Trustpilot với tidyverse và tidyquant, và còn nhiều hơn nữa!
· 11 phút đọc

Khám phá cùng AI

Xây dựng kỹ năng R cho sự nghiệp với DataCamp

Giới thiệu

Trustpilot đã trở thành một trang web phổ biến để khách hàng đánh giá doanh nghiệp và dịch vụ. Trong hướng dẫn ngắn này, bạn sẽ học cách thu thập (scrape) thông tin hữu ích từ trang web này và tạo một số insight cơ bản từ đó với sự trợ giúp của R. Bạn sẽ thấy rằng TrustPilot có thể không đáng tin như những gì được quảng cáo.

Cổng thông tin của Trustpilot

Cụ thể hơn, hướng dẫn này sẽ bao gồm những nội dung sau:

  • Đầu tiên, bạn sẽ học cách thu thập dữ liệu từ Trustpilot để tổng hợp các đánh giá;
  • Sau đó, bạn sẽ xem một số kỹ thuật cơ bản để trích xuất thông tin từ một trang: bạn sẽ trích xuất nội dung đánh giá, xếp hạng, tên tác giả và thời điểm gửi của tất cả các đánh giá trên một trang con.
  • Với các công cụ này, bạn đã sẵn sàng nâng cấp và so sánh các đánh giá của hai công ty (do bạn chọn): bạn sẽ thấy cách tận dụng các gói tidyverse như ggplot2 và dplyr, kết hợp với xts, để khảo sát dữ liệu sâu hơn và xây dựng giả thuyết, từ đó tiếp tục kiểm định với gói infer, một gói suy luận thống kê theo triết lý tidyverse.

Trên Trustpilot, một đánh giá bao gồm mô tả ngắn về dịch vụ, xếp hạng 5 sao, tên người dùng và thời điểm đăng bài.

Ví dụ đánh giá trên Trustpilot

Mục tiêu của bạn là viết một hàm trong R để trích xuất những thông tin này cho bất kỳ công ty nào bạn chọn.

Tạo một hàm Scraping

Trước tiên, bạn cần tải tất cả các thư viện cho tác vụ này.

    # General-purpose data wrangling
    library(tidyverse)  

    # Parsing of HTML/XML files  
    library(rvest)    

    # String manipulation
    library(stringr)   

    # Verbose regular expressions
    library(rebus)     

    # Eases DateTime manipulation
    library(lubridate) 

Tìm tất cả các Trang

Ví dụ, bạn có thể chọn công ty thương mại điện tử Amazon. Đây chỉ là minh họa và hoàn toàn không liên quan đến nghiên cứu tình huống bạn sẽ xem ở nửa sau của hướng dẫn.

URL trang đích sẽ là định danh cho một công ty, vì vậy bạn sẽ lưu nó dưới dạng biến.

    url <-'http://www.trustpilot.com/review/www.amazon.com'

Hầu hết các công ty lớn đều có nhiều trang đánh giá. Trên trang đích của Amazon bạn có thể đọc được số lượng trang, ở đây là 155.

Phần cuối trang đích của Amazon

Nhấp vào bất kỳ trang con nào sẽ cho thấy một mẫu về cách định địa chỉ URL của từng trang của một công ty. Mỗi URL là URL chính kèm ?page=n, trong đó n là số trang đánh giá, ở đây là từ 1 đến 155.

Chương trình của bạn nên hoạt động như sau:

  1. Tìm số trang tối đa cần truy vấn
  2. Tạo tất cả các trang con cấu thành danh sách đánh giá
  3. Thu thập thông tin từ từng trang
  4. Kết hợp thông tin vào một data frame tổng hợp

Hãy bắt đầu bằng cách tìm số trang tối đa. Nói chung, bạn có thể kiểm tra các thành phần hiển thị của một trang web bằng công cụ phát triển web tích hợp trong trình duyệt. Ý tưởng đằng sau là mọi nội dung của trang web, dù được tạo động, đều được gắn thẻ nào đó trong mã nguồn. Các thẻ này thường đủ để xác định chính xác dữ liệu bạn muốn trích xuất.

Vì đây chỉ là phần nhập môn, bạn có thể chọn cách đi đường vòng và tự mình xem mã nguồn.

Dữ liệu HTML có cấu trúc như sau:

    < Tag  Attribute_1 = Value_1 Attribute_2 = Value_2 ...>
        The tagged data
        <\Tag>

Để lấy dữ liệu, bạn sẽ cần một số hàm của gói rvest. Để chuyển một trang web thành đối tượng XML, bạn dùng hàm read_html(). Bạn cần cung cấp URL đích và hàm sẽ gọi webserver, thu thập dữ liệu và phân tích cú pháp. Để trích xuất các node liên quan từ đối tượng XML bạn dùng html_nodes(), với đối số là mô tả lớp (class descriptor), có tiền tố . để chỉ ra đó là một lớp. Kết quả trả về là danh sách tất cả các node tìm được theo cách đó. Để trích xuất dữ liệu được gắn thẻ, bạn áp dụng html_text() lên các node mong muốn. Trong trường hợp cần trích xuất thuộc tính thay vì nội dung, bạn dùng html_attrs(). Hàm này sẽ trả về danh sách thuộc tính, bạn có thể lấy phần con để có được thuộc tính muốn trích xuất.

Hãy áp dụng vào thực tế. Sau khi nhấp chuột phải trên trang đích của Amazon, bạn chọn xem mã nguồn. Bạn có thể tìm nhanh phần liên quan bằng cách tìm số '155'.

Trích đoạn mã nguồn của trang đích

Bạn có thể thấy toàn bộ thông tin nút phân trang được gắn thẻ lớp 'pagination-page'. Một hàm nhận HTML thô của trang đích và trích xuất phần tử áp chót của lớp pagination-page trông như sau:

    get_last_page <- function(html){

      pages_data <- html %>% 
                      # The '.' indicates the class
                      html_nodes('.pagination-page') %>% 
                      # Extract the raw text as a list
                      html_text()                   

      # The second to last of the buttons is the one
      pages_data[(length(pages_data)-1)] %>%            
        # Take the raw string
        unname() %>%                                     
        # Convert to number
        as.numeric()                                     
    }

Bước đặc thù của hàm này là áp dụng html_nodes() để trích xuất tất cả node thuộc lớp pagination. Phần cuối của hàm chỉ đơn giản là lấy phần tử đúng trong danh sách, tức phần tử áp chót, và chuyển nó sang giá trị số.

Để kiểm tra hàm, bạn có thể tải trang đầu bằng hàm read_html() và áp dụng hàm vừa viết:

    first_page <- read_html(url)
    (latest_page_number <- get_last_page(first_page))
    [1] 155

Bây giờ bạn đã có con số này, bạn có thể tạo danh sách tất cả URL liên quan

    list_of_pages <- str_c(url, '?page=', 1:latest_page_number)

Bạn có thể kiểm tra thủ công rằng các mục trong list_of_pages thực sự hợp lệ và có thể mở được qua trình duyệt.

Trích xuất Thông tin của Một Trang

Bạn muốn trích xuất nội dung đánh giá, xếp hạng, tên tác giả và thời điểm gửi của tất cả đánh giá trên một trang con. Bạn có thể lặp lại các bước trước đó cho từng trường bạn cần.

Một đánh giá với thông tin liên quan được tô sáng (trừ id của tác giả)

Với mỗi trường dữ liệu bạn viết một hàm trích xuất dựa trên các thẻ đã quan sát. Ở bước này cần một chút thử–sai để lấy đúng dữ liệu mong muốn. Đôi khi bạn sẽ thấy các mục bổ sung cũng được gắn thẻ, vì vậy bạn phải thu gọn đầu ra theo cách thủ công.

    get_reviews <- function(html){
      html %>% 
        # The relevant tag
        html_nodes('.review-body') %>%      
        html_text() %>% 
        # Trim additional white space
        str_trim() %>%                       
        # Convert the list into a vector
        unlist()                             
    }

    get_reviewer_names <- function(html){
      html %>% 
        html_nodes('.user-review-name-link') %>% 
        html_text() %>% 
        str_trim() %>% 
        unlist()
    }

Thông tin ngày giờ hơi phức tạp hơn, vì nó được lưu dưới dạng thuộc tính.

Nhìn chung, bạn tìm mô tả rộng nhất rồi cố gắng cắt bỏ thông tin dư thừa. Bởi vì thông tin thời gian không chỉ xuất hiện trong các đánh giá, bạn cũng phải trích xuất thông tin status liên quan và lọc theo mục đúng.

    get_review_dates <- function(html){

      status <- html %>% 
                  html_nodes('time') %>% 
                  # The status information is this time a tag attribute
                  html_attrs() %>%             
                  # Extract the second element
                  map(2) %>%                    
                  unlist() 

      dates <- html %>% 
                  html_nodes('time') %>% 
                  html_attrs() %>% 
                  map(1) %>% 
                  # Parse the string into a datetime object with lubridate
                  ymd_hms() %>%                 
                  unlist()

      # Combine the status and the date information to filter one via the other
      return_dates <- tibble(status = status, dates = dates) %>%   
                        # Only these are actual reviews
                        filter(status == 'ndate') %>%              
                        # Select and convert to vector
                        pull(dates) %>%                            
                        # Convert DateTimes to POSIX objects
                        as.POSIXct(origin = '1970-01-01 00:00:00') 

      # The lengths still occasionally do not lign up. You then arbitrarily crop the dates to fit
      # This can cause data imperfections, however reviews on one page are generally close in time)

      length_reviews <- length(get_reviews(html))

      return_reviews <- if (length(return_dates)> length_reviews){
          return_dates[1:length_reviews]
        } else{
          return_dates
        }
      return_reviews
    }

Hàm cuối cùng bạn cần là bộ trích xuất xếp hạng. Bạn sẽ dùng biểu thức chính quy để khớp mẫu. Xếp hạng được đặt như một thuộc tính của thẻ. Thay vì chỉ là một con số, nó là một phần của chuỗi count-X, trong đó X là con số bạn muốn. Biểu thức chính quy có thể hơi khó dùng, nhưng gói rebus cho phép viết chúng theo cách dễ đọc. Ngoài ra, khả năng piping của rebus qua toán tử %R% cho phép phân rã mẫu phức tạp thành các mẫu con đơn giản hơn để cấu trúc các biểu thức chính quy phức tạp.

    get_star_rating <- function(html){

      # The pattern you look for: the first digit after `count-`
      pattern = 'count-'%R% capture(DIGIT)    

      ratings <-  html %>% 
        html_nodes('.star-rating') %>% 
        html_attrs() %>% 
        # Apply the pattern match to all attributes
        map(str_match, pattern = pattern) %>%
        # str_match[1] is the fully matched string, the second entry
        # is the part you extract with the capture in your pattern  
        map(2) %>%                             

        unlist()

      # Leave out the first instance, as it is not part of a review
      ratings[2:length(ratings)]               
    }

Sau khi bạn kiểm tra rằng các hàm trích xuất riêng lẻ hoạt động trên một URL, hãy kết hợp chúng để tạo một tibble, về cơ bản là một data frame, cho toàn bộ trang. Vì bạn có thể áp dụng hàm này cho nhiều công ty, bạn sẽ thêm một trường tên công ty. Điều này hữu ích cho phân tích sau này khi muốn so sánh các công ty khác nhau.

    get_data_table <- function(html, company_name){

      # Extract the Basic information from the HTML
      reviews <- get_reviews(html)
      reviewer_names <- get_reviewer_names(html)
      dates <- get_review_dates(html)
      ratings <- get_star_rating(html)

      # Combine into a tibble
      combined_data <- tibble(reviewer = reviewer_names,
                              date = dates,
                              rating = ratings,
                              review = reviews) 

      # Tag the individual data with the company name
      combined_data %>% 
        mutate(company = company_name) %>% 
        select(company, reviewer, date, rating, review)
    }

Bạn bao hàm chức năng này trong một lệnh trích xuất HTML từ URL để việc xử lý thuận tiện hơn.

    get_data_from_url <- function(url, company_name){
      html <- read_html(url)
      get_data_table(html, company_name)
    }

Ở bước cuối, bạn áp dụng hàm này cho danh sách URL đã tạo trước đó. Để làm điều này, bạn dùng hàm map() từ gói purrr thuộc tidyverse. Nó áp dụng cùng một hàm cho từng phần tử của một danh sách. Bạn đã dùng hàm này trước đó, tuy nhiên khi đó bạn truyền vào một số n, đây là cách viết tắt để trích xuất phần tử con thứ n của danh sách.

Cuối cùng, bạn viết một hàm tiện lợi nhận vào URL trang đích của một công ty và nhãn bạn muốn gán cho công ty đó. Hàm sẽ trích xuất tất cả đánh giá, ghép lại thành một tibble. Đây cũng là điểm khởi đầu tốt để tối ưu mã. Hàm map áp dụng get_data_from_url() tuần tự, nhưng không nhất thiết phải vậy. Có thể áp dụng song song hóa để nhiều CPU mỗi cái sẽ lấy đánh giá cho một tập con các trang và chỉ ghép lại ở cuối.

    scrape_write_table <- function(url, company_name){

      # Read first page
      first_page <- read_html(url)

      # Extract the number of pages that have to be queried
      latest_page_number <- get_last_page(first_page)

      # Generate the target URLs
      list_of_pages <- str_c(url, '?page=', 1:latest_page_number)

      # Apply the extraction and bind the individual results back into one table, 
      # which is then written as a tsv file into the working directory
      list_of_pages %>% 
        # Apply to all URLs
        map(get_data_from_url, company_name) %>%  
        # Combine the tibbles into one tibble
        bind_rows() %>%                           
        # Write a tab-separated file
        write_tsv(str_c(company_name,'.tsv'))     
    }

Bạn lưu kết quả xuống đĩa bằng tệp phân tách bằng tab, thay vì tệp phân tách bằng dấu phẩy (CSV) phổ biến, vì các đánh giá thường chứa dấu phẩy, có thể gây nhầm lẫn cho bộ phân tích.

Ví dụ, bạn có thể áp dụng hàm cho Amazon:

    scrape_write_table(url, 'amazon')

    amz_tbl <- read_tsv('amazon.tsv')
    tail(amz_tbl, 5)
    # A tibble: 5 x 5
      company            reviewer                date rating
        <chr>               <chr>              <dttm>  <int>
    1  amazon            Anders T 2009-03-22 13:14:12      5
    2  amazon             David E 2008-12-31 18:57:31      5
    3  amazon      Joseph Harding 2008-09-16 13:05:05      3
    4  amazon   "Mads D\u00f8rup" 2008-04-28 11:09:05      5
    5  amazon Kim Fuglsang Kramer 2007-08-27 17:25:01      4
    # ... with 1 more variables: review <chr>

Nghiên cứu tình huống: Câu chuyện về hai công ty

Với hàm webscraping từ phần trước, bạn có thể nhanh chóng thu thập rất nhiều dữ liệu. Với dữ liệu này, có thể thực hiện nhiều phân tích khác nhau.

Trong nghiên cứu tình huống này, bạn chỉ sử dụng siêu dữ liệu của các đánh giá, cụ thể là xếp hạng và thời điểm đánh giá.

Đầu tiên, bạn tải thêm các thư viện.

    # For working with time series
    library(xts)      

    # For hypothesis testing
    library(infer)

Các công ty bạn quan tâm đều là những cái tên nổi bật trong cùng ngành. Cả hai cũng dùng điểm TrustPilot làm điểm nhấn bán hàng trên trang web của họ.

Bạn đã thu thập dữ liệu của họ và chỉ cần tải lên:

    data_company_a <- read_tsv('company_A.tsv')
    data_company_b <- read_tsv('company_B.tsv')

Bạn có thể tóm tắt các con số tổng quan với sự trợ giúp của các hàm group_by() và summarise() từ gói dplyr:

    full_data <- rbind(data_company_a, data_company_b)

    full_data%>%
      group_by(company) %>% 
      summarise(count = n(), mean_rating = mean(rating))
companycountmean_rating
company_A36284.908214
company_B26154.852773

Điểm trung bình của hai công ty trông có vẻ tương đương. Công ty B, hoạt động lâu hơn một chút, cũng có vẻ có xếp hạng thấp hơn đôi chút.

So sánh chuỗi thời gian

Một điểm khởi đầu tốt cho phân tích sâu hơn là xem hiệu suất theo tháng theo xếp hạng của mỗi công ty. Trước tiên, bạn trích xuất chuỗi thời gian từ dữ liệu rồi lấy một khoảng mà cả hai công ty đều đang hoạt động và có đủ hoạt động đánh giá. Điều này có thể tìm được bằng cách trực quan hóa chuỗi thời gian. Nếu có những khoảng trống lớn trong dữ liệu kéo dài nhiều tháng, thì các kết luận rút ra sẽ kém đáng tin cậy.

    company_a_ts <- xts(data_company_a$rating, data_company_a$date)
    colnames(company_a_ts) <- 'rating'
    company_b_ts <- xts(data_company_b$rating, data_company_b$date)
    colnames(company_b_ts) <- 'rating'

    open_ended_interval <- '2016-01-01/'

    # Subsetting the time series
    company_a_sts <- company_a_ts[open_ended_interval] 
    company_b_sts <- company_b_ts[open_ended_interval]

Bây giờ bạn có thể áp dụng phép lấy trung bình theo tháng với hàm apply.monthly() từ gói xts. Để bắt đầu, thu thập xếp hạng trung bình theo tháng cho từng công ty. Chuỗi thời gian có thể có nhiều quan sát cho cùng một chỉ số. Để chỉ định rằng trung bình được lấy theo một trường, ở đây là rating, chúng ta cần truyền colMeans.

Tiếp theo, đừng quên truyền length vào đối số FUN để lấy số lượng theo tháng. Điều này là vì chuỗi thời gian có thể được xem như một vector. Mỗi đánh giá làm tăng độ dài vector đó lên một và hàm length về bản chất là đếm số đánh giá.

    company_a_month_avg <-  apply.monthly(company_a_sts, colMeans, na.rm = T)
    company_a_month_count  <-  apply.monthly(company_a_sts, FUN = length)

    company_b_month_avg <-  apply.monthly(company_b_sts, colMeans, na.rm = T)
    company_b_month_count  <-  apply.monthly(company_b_sts, FUN = length)

Tiếp đó, bạn có thể so sánh xếp hạng và số lượng theo tháng. Cách làm rất đơn giản: vẽ biểu đồ xếp hạng trung bình theo tháng cho mỗi công ty và số lượng các đánh giá trong tháng đó cho mỗi công ty ở các biểu đồ riêng, sau đó sắp xếp chúng trên một lưới:

Biểu đồ xếp hạng theo tháng

Có vẻ công ty A có xếp hạng cao ổn định hơn nhiều. Không chỉ vậy, đối với công ty B, số lượng đánh giá theo tháng cho thấy các đỉnh rất rõ rệt, đặc biệt sau một giai đoạn đánh giá ở mức trung bình.

Liệu có khả năng gian lận?

Tổng hợp dữ liệu sâu hơn

Bây giờ bạn đã thấy dữ liệu, đặc biệt của công ty B, thay đổi khá mạnh theo thời gian, một câu hỏi tự nhiên là hoạt động đánh giá được phân bổ trong tuần hoặc trong ngày như thế nào.

    full_data <- full_data %>%  
      filter(date >= start_date) %>% 
      mutate(weekday = weekdays(date, abbreviate = T),
             hour = hour(date))

    # Treat the weekdays as factor. 
    # The order is for the plotting only
    full_data$weekday <-  factor(full_data$weekday, 
                                 levels = c('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))

Nếu bạn vẽ biểu đồ các đánh giá theo ngày trong tuần và theo giờ, bạn cũng sẽ thấy khác biệt đáng chú ý:

Biểu đồ cột số đánh giá theo ngày trong tuần

Phân tách theo thời điểm trong ngày của các đánh giá cũng cho thấy khác biệt rõ rệt giữa hai đối thủ:

Biểu đồ cột số đánh giá theo giờ trong ngày

Có vẻ như nhiều đánh giá được viết vào ban ngày hơn ban đêm. Tuy nhiên, công ty B lại có một đỉnh rõ rệt ở các đánh giá viết vào buổi chiều.

Giả thuyết không

Những mẫu hình này dường như cho thấy có điều gì đó bất thường tại công ty B. Có thể một số đánh giá không do người dùng viết mà do các chuyên viên. Bạn có thể kỳ vọng các đánh giá này, trung bình, sẽ tốt hơn những đánh giá do người dùng thông thường viết. Vì hoạt động đánh giá của công ty B cao hơn nhiều vào các ngày trong tuần, có khả năng các chuyên viên sẽ viết đánh giá vào một trong những ngày đó. Giờ bạn có thể xây dựng giả thuyết không và cố gắng bác bỏ nó bằng bằng chứng từ dữ liệu.

Không có khác biệt có hệ thống giữa các đánh giá viết vào ngày làm việc so với cuối tuần.

Để kiểm định, bạn chia các đánh giá của công ty B thành hai nhóm: viết vào ngày trong tuần và viết vào cuối tuần, rồi kiểm tra xếp hạng trung bình của chúng

    hypothesis_data <- full_data %>% 
      mutate(is_weekend = ifelse(weekday %in% c('Sat', 'Sun'), 1, 0)) %>% 
      select(company, is_weekend, rating)

    hypothesis_data %>% 
      group_by(company, is_weekend) %>% 
      summarise(avg_rating = mean(rating)) %>% 
      spread(key = is_weekend, value = avg_rating) %>% 
      rename(weekday = '0', weekend = '1)
companyweekdayweekend
company_A4.8981034.912176
company_B4.8645454.666667

Có vẻ đây là một khác biệt đủ nhỏ, nhưng liệu chỉ là ngẫu nhiên?

Bạn có thể trích xuất chênh lệch giữa các trung bình:

    weekend_rating <- hypothesis_data %>% 
      filter(company == 'company_B') %>% 
      filter(is_weekend == 1) %>% 
      summarise(mean(rating)) %>% 
      pull()

    workday_rating <- hypothesis_data %>% 
      filter(company == 'company_B') %>% 
      filter(is_weekend == 0) %>% 
      summarise(mean(rating)) %>% 
      pull()

    (diff_work_we <- workday_rating - weekend_rating)
    [1] 0.1978784

Nếu thật sự không có khác biệt giữa ngày làm việc và cuối tuần, bạn có thể đơn giản tráo nhãn is_weekend và chênh lệch giữa các trung bình sẽ cùng bậc độ lớn. Một cách thuận tiện để làm các bài toán 'Hacker Statistics' như vậy là dùng gói infer:

    permutation_tests <- hypothesis_data %>% 
      filter(company == 'company_B') %>% 
      specify(rating ~ is_weekend ) %>% 
      hypothesize(null = 'independence') %>% 
      generate(reps = 10000, type = 'permute') %>% 
      calculate(stat = 'diff in means', order = c(0,1))

Ở đây bạn đã chỉ định quan hệ muốn kiểm định, giả thuyết độc lập và yêu cầu hàm tạo 10000 hoán vị, tính chênh lệch trung bình xếp hạng cho mỗi lần. Giờ bạn có thể tính tần suất một hoán vị tình cờ tạo ra chênh lệch trung bình lớn như vậy:

    permutation_tests %>% 
      summarise(p = mean(abs(stat)>= diff_work_we))
    # A tibble: 1 x 1
          p
      <dbl>
    1 7e-04

Thật vậy, khả năng hiệu ứng quan sát được chỉ là ngẫu nhiên là rất nhỏ. Điều này không chứng minh có hành vi sai trái, nhưng rất đáng ngờ. Ví dụ, làm cùng thí nghiệm cho công ty A cho p-value bằng 0.561, nghĩa là rất có khả năng nhận được giá trị cực trị như quan sát, điều này chắc chắn không bác bỏ giả thuyết không của bạn.

Kết luận: Đừng mù quáng tin vào các đánh giá

Trong hướng dẫn này, bạn đã viết một chương trình đơn giản cho phép thu thập dữ liệu từ trang TrustPilot. Dữ liệu được cấu trúc trong một bảng tidy và mở ra cơ hội cho rất nhiều phân tích tiếp theo.

Ví dụ, bạn đã thu thập thông tin cho hai công ty hoạt động trong cùng ngành. Bạn phân tích siêu dữ liệu của họ và tìm thấy các mẫu đáng ngờ ở một công ty. Bạn dùng kiểm định giả thuyết để cho thấy có hiệu ứng có hệ thống của ngày trong tuần lên xếp hạng của một công ty. Đây là một chỉ báo rằng các đánh giá đã bị thao túng, vì không có lời giải thích hợp lý nào khác cho một khác biệt như vậy. Bạn không xác minh được hiệu ứng này cho công ty còn lại, tuy nhiên điều đó không có nghĩa là các đánh giá của họ nhất thiết là chân thực.

Có thể tìm thêm thông tin về việc các trang đánh giá bị nhấn chìm bởi đánh giá giả, ví dụ trên Guardian.

Muốn học thêm về Web scraping trong R? Hãy xem hướng dẫn Web Scraping và Phân tích cú pháp dữ liệu trong R của chúng tôi.

Chủ đề

Liên quan