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

Web Scraping với R và PhantomJS

Hướng dẫn ngắn về cách thu thập dữ liệu do Javascript tạo ra bằng R với PhantomJS.
· 5 phút đọc

Khám phá cùng AI

Khi cần thực hiện web scraping, thông thường bạn sẽ sử dụng gói rvest của Hadley Wickham. Gói này cung cấp một giải pháp sẵn dùng, dễ sử dụng để lấy mã html tạo nên một trang web. Tuy nhiên, khi trang web hoặc trang sử dụng JavaScript để hiển thị dữ liệu bạn quan tâm, gói rvest thiếu đi chức năng cần thiết. Một giải pháp là sử dụng PhantomJS.

(Muốn luyện tập nhập nhiều dữ liệu hơn vào R? Hãy thử hướng dẫn này.)

Tải các gói cần thiết

Bước đầu tiên, bạn sẽ phải tải tất cả các gói cần cho phân tích này vào không gian làm việc (nếu bạn chưa cài đặt các gói này trên hệ thống cục bộ, hãy dùng install.packages() để cài đặt):

library(rvest)
library(stringr)
library(plyr)
library(dplyr)
library(ggvis)
library(knitr)
options(digits = 4)

Thu thập dữ liệu do Javascript tạo ra với R

Bước tiếp theo là thu thập dữ liệu TechStars bằng PhantomJS. Hãy xem tệp .js cơ bản sau:

// scrape_techstars.js

var webPage = require('webpage');
var page = webPage.create();

var fs = require('fs');
var path = 'techstars.html'

page.open('http://www.techstars.com/companies/stats/', function (status) {
  var content = page.content;
  fs.write(path,content,'w')
  phantom.exit();
});

Script này về cơ bản sẽ render trang HTML sau khi mã javascript bên dưới đã chạy xong, cho phép bạn lấy trang HTML với tất cả các bảng bên trong. Để tiếp tục làm việc trong R cho phần còn lại của phân tích, chúng tôi đề xuất bạn dùng hàm system() để gọi PhantomJS (bạn sẽ phải tải và cài đặt PhantomJS và đặt nó trong thư mục làm việc của bạn):

# Để phantomJS thu thập dữ liệu techstars, kết quả được ghi vào techstars.html
system("./phantomjs scrape_techstars.js")

Sau vòng rẽ nhỏ này, cuối cùng bạn có một tệp HTML, techstars.html, trên hệ thống cục bộ, có thể được thu thập bằng rvest. Kiểm tra trang Techstars cho thấy các bảng mà chúng ta quan tâm nằm trong các div có class css batch:

batches <- html("techstars.html") %>%
  html_nodes(".batch")

class(batches)
[1] "XMLNodeSet"

Bây giờ bạn có một danh sách các đối tượng XMLNodeSet: mỗi đối tượng chứa dữ liệu cho một lứa TechStars. Trong đó, chúng ta có thể tìm thấy thông tin về địa điểm, năm, mùa, cũng như về các công ty, trụ sở hiện tại, trạng thái hiện tại và tổng số vốn họ đã huy động. Chúng tôi sẽ không đi sâu vào các bước thu thập và làm sạch dữ liệu bên dưới; bạn có thể tự chạy mã và xem chúng thực hiện được gì. Bạn sẽ thấy có một số bước làm sạch tùy chỉnh để đảm bảo từng mẩu thông tin được định dạng gọn gàng:

batch_titles <- batches %>%
  html_nodes(".batch_class") %>%
  html_text()

batch_season <- str_extract(batch_titles, "(Fall|Spring|Winter|Summer)")
batch_year <- str_extract(batch_titles, "([[:digit:]]{4})")
# thông tin địa điểm là mọi thứ trong tiêu đề batch không phải là năm hoặc mùa
batch_location <- sub("\\s+$", "",
                      sub("([[:digit:]]{4})", "",
                          sub("(Fall|Spring|Winter|Summer)","",batch_titles)))

# tạo data frame với thông tin batch.
batch_info <- data.frame(location = batch_location,
                         year = batch_year,
                         season = batch_season)

breakdown <- lapply(batches, function(x) {
  company_info <- x %>% html_nodes(".parent")
  companies_single_batch <- lapply(company_info, function(y){
    as.list(gsub("\\[\\+\\]\\[\\-\\]\\s", "", y %>%
       html_nodes("td") %>%
       html_text()))
  })
  df <- data.frame(matrix(unlist(companies_single_batch),
                   nrow=length(companies_single_batch),
                   byrow=T,
                   dimnames = list(NULL, c("company","funding","status","hq"))))
  return(df)
})

# Thêm thông tin batch vào breakdown
batch_info_extended <- batch_info[rep(seq_len(nrow(batch_info)),
                                  sapply(breakdown, nrow)),]
breakdown_merged <- rbind.fill(breakdown)

# Gộp tất cả thông tin
techstars <- tbl_df(cbind(breakdown_merged, batch_info_extended)) %>%
  mutate(funding = as.numeric(gsub(",","",gsub("\\$","",funding))))

Với sự kết hợp giữa R lõi, rvest, plyr và dplyr, giờ đây chúng ta có data frame techstars; một bộ dữ liệu về tất cả các công ty TechStars, với toàn bộ thông tin công khai đã được định dạng gọn gàng:

techstars
## Source: local data frame [535 x 7]
##
##          company funding   status                hq location year season
## 1    Accountable  110000   Active    Fort Worth, TX   Austin 2013   Fall
## 2          Atlas 1180000   Active        Austin, TX   Austin 2013   Fall
## 3        Embrace  110000   Failed        Austin, TX   Austin 2013   Fall
## 4  Filament Labs 1490000   Active        Austin, TX   Austin 2013   Fall
## 5        Fosbury  300000   Active        Austin, TX   Austin 2013   Fall
## 6          Gone!  840000   Active San Francisco, CA   Austin 2013   Fall
## 7     MarketVibe  110000 Acquired        Austin, TX   Austin 2013   Fall
## 8           Plum 1630000   Active        Austin, TX   Austin 2013   Fall
## 9  ProtoExchange  110000   Active        Austin, TX   Austin 2013   Fall
## 10       Testlio 1020000   Active        Austin, TX   Austin 2013   Fall
## ..           ...     ...      ...               ...      ...  ...    ...
names(techstars)
## [1] "company"  "funding"  "status"   "hq"       "location" "year"
## [7] "season"

Kết luận

Với sự kết hợp các công cụ và đoạn mã ở trên, chúng ta đã thu thập được dữ liệu từ một trang web sử dụng JavaScript để tạo dữ liệu. Như có thể thấy, đây là một quy trình rất có cấu trúc và có thể thực hiện dễ dàng khi đã có mã ban đầu. Muốn học R và đang tìm các hướng dẫn, khóa học về khoa học dữ liệu và R? Hãy xem DataCamp

Chủ đề

Liên quan