Cách scrape một trang web bằng R. Scrape và so sánh dữ liệu lịch sử thị trường tiền điện tử từ CoinMarketCap

Web scraping là công việc trích xuất dữ liệu từ một trang web. Trong thực tế đôi khi bạn cần thu thập 1 số lượng lớn thông tin từ một số trang web như là giá cổ phiếu, chi tiết sản phẩm, số liệu thống kê thể thao, thông tin liên hệ của công ty,…để phục vụ cho nhiều mục đích khác nhau. Tuy nhiên, việc lấy các thông tin này một cách thủ công thì cần rất nhiều thời gian. Lúc này web scraping chính là cách giúp chúng ta trích xuất dữ liệu từ các trang web một cách tự động. Kỹ thuật này chủ yếu tập trung vào việc chuyển đổi dữ liệu phi cấu trúc (HTML) trên web thành dữ liệu có cấu trúc (cơ sở dữ liệu, bảng tính,…)

CoinMarketCap là một trang web chuyên cung cấp dữ liệu về các loại tiền điện tử đang được lưu hành trên thế giới. Nếu bạn là người đã hoặc đang tìm hiểu, đầu tư vào các đồng coins thì không thể nào bỏ qua trang web cung cấp thông tin về tiền điện tử lớn nhất thế giới này. Với CoinMarketCap bạn có thể xem rất nhiều lọai thông tin ví dụ như: biến động giá cả các đồng coin, trữ lượng, khối lượng giao dịch theo từng khoảng thời gian, tỷ giá, xem trang web chính thức hoặc các hoạt động trên mạng xã hội của các đồng coins.

Trong bài này tôi sẽ giới thiệu với các bạn cách sử dụng gói rvest trong R để scrape dữ liệu lịch sử thị trường các loại tiền điện tử từ CoinMarketCap. Sau đó dùng gói ggplot2 để trực quan hóa dữ liệu nhằm mục đích so sánh biến động giá cả của các đồng coins với nhau trong khoảng thời gian nhất định.

Gói rvest cũng giống như thư viện BeautifulSoup trên Python, là một thư viện R để trích xuất dữ liệu từ các tập tin HTML.

Lưu ý khi scape một trang web:

  • Không nên tạo quá nhiều request đến trang web trong 1 thời điểm, vì nó có thể gây ra sập trang web (có thể bị liệt vào tấn công từ chối dịch vụ DDoS)
  • Trang web có thể sẽ thường xuyên thay đổi giao diện, bố cục (HTML) nên bạn cần thường xuyên cập nhật code của mình

Nạp các thư viện cần dùng vào phiên làm việc của R để thực hành:

library(jsonlite) # Thư viện cho phép đọc json files
library(rvest) # thư viện để scape web
library(viridis) # Thay đổi bảng màu mặc định ggplot2
library(tidyverse) # Hệ sinh thái các gói hỗ trợ biến đổi (dplyr) và trực quan hóa dữ liệu (ggplot2)

Nếu chưa cài các thư viện trên thì các bạn dùng lệnh install.packages(.) để cài đặt với tham số đầu vào là tên các thư viện cần cài đặt. Ví dụ:

install.packages("rvest")

Đầu tiên chúng ta đọc json file từ trang CoinMarketCap để biết thông tin về các loại coins:

json <- "https://s2.coinmarketcap.com/generated/search/quick_search.json"
coins <- read_json(json, simplifyVector = TRUE)

Hiển thị bảng thông tin 10 đồng coins đầu tiên theo rank:

head(coins,10)
##               name symbol rank            slug
## 1          Bitcoin    BTC    1         bitcoin
## 2         Ethereum    ETH    2        ethereum
## 3              XRP    XRP    3             xrp
## 4           Tether   USDT    4          tether
## 5        Chainlink   LINK    5       chainlink
## 6     Bitcoin Cash    BCH    6    bitcoin-cash
## 7         Litecoin    LTC    7        litecoin
## 8       Bitcoin SV    BSV    8      bitcoin-sv
## 9  Crypto.com Coin    CRO    9 crypto-com-coin
## 10    Binance Coin    BNB   10    binance-coin
##                                   tokens   id
## 1                  Bitcoin, bitcoin, BTC    1
## 2                Ethereum, ethereum, ETH 1027
## 3                          XRP, xrp, XRP   52
## 4                   Tether, tether, USDT  825
## 5             Chainlink, chainlink, LINK 1975
## 6        Bitcoin Cash, bitcoin-cash, BCH 1831
## 7                Litecoin, litecoin, LTC    2
## 8            Bitcoin SV, bitcoin-sv, BSV 3602
## 9  Crypto.com Coin, crypto-com-coin, CRO 3635
## 10       Binance Coin, binance-coin, BNB 1839

Kiểm tra tổng số lượng đồng tiền kỹ thuật số đang lưu hành trên CoinMarketCap:

dim(coins)[1]
## [1] 4869

Để ví dụ, trong bài này tôi sẽ so sánh thông tin 10 đồng coins đầu tiên có rank từ 2 đến 11:

# Lấy thông tin về tên, symbol và slug của 10 đồng coins có rank = [2:11]
coinslug <- coins$slug[2:11]
coinname <- coins$name[2:11]
coinsymbol <- coins$symbol[2:11]

Tạo hàm để get dữ liệu coins. Khi ta vào mục historical data (như hình bên dưới) để xem thông tin của từng loại coin trên trang CoinMarketCap, ta thấy trong đường link3 thông tin quan trọng đó là:

  • slug: Slug của loại coin đó (như đường link trong hình dưới là bitcoin)
  • start: Ngày bắt đầu của khoảng thời gian ta muốn xem thông tin
  • end: ngày kết thúc của khoảng thời gian ta muốn xem thông tin
Screenshot từ trang CoinMarketCap

Screenshot từ trang CoinMarketCap

Vì vậy ta sẽ viết hàm để get dữ liệu dựa vào 3 thông tin trên như sau:

# Tạo hàm get dữ liệu coin
get_data_coin <- function(coin, start_date, end_date){
  # coin: slug của coin
  # start_date: Ngày bắt đầu lấy dữ liệu
  # end_date: Ngày kết thúc lấy dữ liệu
  # Tạo đường link từ 3 thông tin đầu vào
  historyurl <- paste0("https://coinmarketcap.com/currencies/",
                      coin,
                      "/historical-data/?start=",
                      start_date,
                      "&end=",
                      end_date)
  
  # Đọc dữ liệu từ web
  url <-read_html(historyurl)
  data <- data.frame(html_table(url)[[3]])
  data$Slug <- coin
  return(data)
}

Ví dụ sử dụng hàm get_data_coin() vừa tạo để lấy dữ liệu lịch sử của 10 loại coins trên từ ngày 21/08/2019 dến ngày 21/08/2020:

# Nhập ngày bắt đầu và và kết thúc trong khoảng thời gian muốn xem theo định đạng "Năm-Tháng-Ngày"
start_date = 20190821
end_date = 20200821
# Tạo list trống để lưu dữ liệu coins
results_data <- list()

# Lưu dữ liệu từng loại coin trong danh sách 10 coins ở trên vào list trống
for (i in (1:length(coinslug))){
  results_data[[i]] <- get_data_coin(coin = coinslug[i], start_date = start_date, end_date = end_date)
}

# Gộp data.frame của từng loại coin trong list vào thành 1 bảng
results_data <- do.call(rbind, results_data)

Để kiểm tra dữ liệu thu được, ta hiển thị 10 hàng dữ liệu đầu tiên trong bẳng bằng lệnh head():

head(results_data, 10)
##            Date  Open.   High    Low Close..         Volume     Market.Cap
## 1  Aug 22, 2020 389.03 396.47 382.81  395.84 10,131,847,985 44,448,918,222
## 2  Aug 21, 2020 416.15 418.64 387.44  389.13 11,781,796,374 43,690,315,907
## 3  Aug 20, 2020 406.76 418.73 404.03  416.44 10,043,032,427 46,751,356,941
## 4  Aug 19, 2020 423.74 427.02 396.68  406.46 13,137,391,167 45,625,864,918
## 5  Aug 18, 2020 429.67 432.58 419.67  423.67 11,978,984,079 47,551,407,033
## 6  Aug 17, 2020 433.97 442.73 422.65  429.53 13,227,089,410 48,203,426,751
## 7  Aug 16, 2020 433.35 436.27 415.09  433.79 12,168,816,874 48,675,162,267
## 8  Aug 15, 2020 437.56 441.75 429.87  433.35 12,416,067,894 48,620,820,125
## 9  Aug 14, 2020 428.68 444.58 423.35  437.40 15,064,589,987 49,068,474,083
## 10 Aug 13, 2020 390.84 432.90 379.71  428.74 18,480,303,526 48,091,569,052
##        Slug
## 1  ethereum
## 2  ethereum
## 3  ethereum
## 4  ethereum
## 5  ethereum
## 6  ethereum
## 7  ethereum
## 8  ethereum
## 9  ethereum
## 10 ethereum

Thêm thông tin gồm namesymbol của từng coin vào bảng dữ liệu:

coinnames <- data.frame(
        Name = as.character(coinname),
        Symbol = as.character(coinsymbol),
        Slug = as.character(coinslug))
df <- full_join(coinnames, results_data, by = "Slug")

Để kiểm tra bảng dữ liệu mới thu được, ta hiển thị 10 hàng dữ liệu đầu tiên trong bảng:

head(df, 10)
##        Name Symbol     Slug         Date  Open.   High    Low Close..
## 1  Ethereum    ETH ethereum Aug 22, 2020 389.03 396.47 382.81  395.84
## 2  Ethereum    ETH ethereum Aug 21, 2020 416.15 418.64 387.44  389.13
## 3  Ethereum    ETH ethereum Aug 20, 2020 406.76 418.73 404.03  416.44
## 4  Ethereum    ETH ethereum Aug 19, 2020 423.74 427.02 396.68  406.46
## 5  Ethereum    ETH ethereum Aug 18, 2020 429.67 432.58 419.67  423.67
## 6  Ethereum    ETH ethereum Aug 17, 2020 433.97 442.73 422.65  429.53
## 7  Ethereum    ETH ethereum Aug 16, 2020 433.35 436.27 415.09  433.79
## 8  Ethereum    ETH ethereum Aug 15, 2020 437.56 441.75 429.87  433.35
## 9  Ethereum    ETH ethereum Aug 14, 2020 428.68 444.58 423.35  437.40
## 10 Ethereum    ETH ethereum Aug 13, 2020 390.84 432.90 379.71  428.74
##            Volume     Market.Cap
## 1  10,131,847,985 44,448,918,222
## 2  11,781,796,374 43,690,315,907
## 3  10,043,032,427 46,751,356,941
## 4  13,137,391,167 45,625,864,918
## 5  11,978,984,079 47,551,407,033
## 6  13,227,089,410 48,203,426,751
## 7  12,168,816,874 48,675,162,267
## 8  12,416,067,894 48,620,820,125
## 9  15,064,589,987 49,068,474,083
## 10 18,480,303,526 48,091,569,052

Ta thấy cột Date ở dạng character nên cần chuyển về dạng date như sau:

df$Date <- lubridate::mdy(unlist(df$Date))
head(df, 10)
##        Name Symbol     Slug       Date  Open.   High    Low Close..
## 1  Ethereum    ETH ethereum 2020-08-22 389.03 396.47 382.81  395.84
## 2  Ethereum    ETH ethereum 2020-08-21 416.15 418.64 387.44  389.13
## 3  Ethereum    ETH ethereum 2020-08-20 406.76 418.73 404.03  416.44
## 4  Ethereum    ETH ethereum 2020-08-19 423.74 427.02 396.68  406.46
## 5  Ethereum    ETH ethereum 2020-08-18 429.67 432.58 419.67  423.67
## 6  Ethereum    ETH ethereum 2020-08-17 433.97 442.73 422.65  429.53
## 7  Ethereum    ETH ethereum 2020-08-16 433.35 436.27 415.09  433.79
## 8  Ethereum    ETH ethereum 2020-08-15 437.56 441.75 429.87  433.35
## 9  Ethereum    ETH ethereum 2020-08-14 428.68 444.58 423.35  437.40
## 10 Ethereum    ETH ethereum 2020-08-13 390.84 432.90 379.71  428.74
##            Volume     Market.Cap
## 1  10,131,847,985 44,448,918,222
## 2  11,781,796,374 43,690,315,907
## 3  10,043,032,427 46,751,356,941
## 4  13,137,391,167 45,625,864,918
## 5  11,978,984,079 47,551,407,033
## 6  13,227,089,410 48,203,426,751
## 7  12,168,816,874 48,675,162,267
## 8  12,416,067,894 48,620,820,125
## 9  15,064,589,987 49,068,474,083
## 10 18,480,303,526 48,091,569,052

Dùng thư viện ggplot2 để trực quan hóa và so sánh biến động giá cả của các loại coins trong khoảng thời gian từ ngày 21/08/2019 dến ngày 21/08/2020:

# Chỉ so sánh thông tìn các cột Open, High, Low, Close
df <- df[,1:8]

# Chuyển bẳng dữ liệu từ dạng bảng rộng về dài
library(tidyr)
df$Name<- factor(df$Name)
df_tall <- df%>% gather(key = s, value = value, -Name, -Symbol, -Slug, -Date)
df_tall$s <- factor(df_tall$s, levels=unique(as.character(df_tall$s)))

# Vẽ biểu đồ so sánh thông tin
ggplot(df_tall, aes(x = Date, y = value, color = Name)) +
geom_line(size = 0.75) +
xlab("Time")+
facet_wrap(~s, ncol = 2, scales = "free_y")+
theme_bw()

Khi đã có dữ liệu rồi tiếp theo chúng ta có thể xây dựng các mô hình dự báo để đự đoán giá các loại coins

Chú thích:

  • Open: Giá mở cửa
  • Close: Giá đóng cửa
  • High: Mức giá cao nhất
  • Low: Mức giá thấp nhất

4 bộ phận này cấu thành nên một nến giao dịch đại diện cho sự lên xuống của giá trị một loại tài sản trong một khoảng thời gian cố định. Điểm “open” của nến đại diện cho mức giá của loại tài sản khi bắt đầu khoảng thời gian giao dịch, trong khi “close” là mức giá khi kết thúc thời gian giao dịch. Còn “high”“low” lần lượt là các mức giá cao nhất và thấp nhất đạt được trong phiên giao dịch.

Các bộ phận của một nến giao dịch, với nến tăng (màu xanh) và nếu giảm (màu đỏ)

Các bộ phận của một nến giao dịch, với nến tăng (màu xanh) và nếu giảm (màu đỏ)

Cuong Sai
Cuong Sai
PhD student

My research interests include Industrial AI (Intelligent predictive maintenance), Machine and Deep learning, Time series forecasting, Intelligent machinery fault diagnosis, Prognostics and health management, Error metrics / forecast evaluation.

comments powered by Disqus

Related