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ậtcode
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 link
có 3
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 tinend
: ngày kết thúc của khoảng thời gian ta muốn xem thông tin
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 name
và symbol
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ửaClose
: Giá đóng cửaHigh
: Mức giá cao nhấtLow
: 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”
và “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.