這個問題很容易答,只要到政府「資料一線通」網站下載 csv 檔,在 Excel 篩選機場出入境人流數字就行。
只是這個方法有點懶惰,有些數據沒有數據庫的,我還是是知道如何爬蟲索取資料。再者,入境處網頁刊載的表格, header 部分是巢狀的,需要特別處理。那麼學曉爬這個表格,有助處理其他稍為複雜的類型。最近坊間熱議通關,而機場出入境數字就是焦點,所以我決定這自學材料。再三強調,爬蟲為自學,不會牟利,內容也不涉及私隱和財產,索取數據數量和時間適可而止。
我是用 R 爬蟲,先寫程式取一天的資料,後再收集短時間的資料,期間在 stackoverflow 和 facebook 求教指正。
要爬資料的 HTML 表格內容沒甚麼問題,重點在於幾個 columns 的 header 拼在一起,故要區隔起來。

就此,我在 stackoverflow 發問如何處理 headers,答案是不用爬 headers,只爬 table rows,然後為每個 column 重新命名,以 9 月 21 日為例:
library(rvest)
library(dplyr)
library(tidyverse)
library(purrr)
rows <- read_html("https://www.immd.gov.hk/eng/stat_20220921.html") %>% html_elements(".table-passengerTrafficStat tbody tr")
prefixes <- c("arr", "dep")
cols <- c("Hong Kong Residents", "Mainland Visitors", "Other Visitors", "Total")
headers <- c("Control_Point", crossing(prefixes, cols) %>% unite("headers", 1:2, remove = T) %>% unlist() %>% unname())
crossing 和 unite 一起執行,把代表入境的 arr 和離境的 dep 分別分配到 4 個 columns,然後移除舊有的 columns,再把 headers 內容還原為普通 character。
然後正式爬數字。這裡我新認識 map_dfr( ),那是具有配對 table cell 而且 row bind 的功能。然後我只挑選所有出入境口岸之中的機場數據,移除人數上的逗號,加上當天日期 column,最後寫進檔案:
df <- map_dfr(rows,
function(x) {
x %>%
html_elements("td[headers]") %>%
set_names(headers) %>%
html_text()
}) %>%
filter(Control_Point %in% c("Airport")) %>%
mutate(across(c(-1), ~ str_replace(.x, ",", "") %>% as.integer())) %>%
mutate(date = "2022-09-21") %>%
write.csv(df, "immigrationStatistics.csv")

那麼,如果要爬連續數天的資料,又如何呢?我的進路是,先要把 URL 內的日期數字變成可以改動的,然後每 loop 一次 URL(那是用 while loop)就爬一次蟲,把 row data 儲存在檔案。但我試了很多遍也不行,所以再去求教 stackoverflow。原來我錯在太早把資料寫進檔案,而且每次也 overwrite 上一次的記錄。正確的編碼是這樣的:
library(rvest)
library(dplyr)
library(purrr)
library(stringr)
start <- as.Date("21-09-22", format = "%d-%m-%y")
end <- as.Date("01-10-22", format = "%d-%m-%y") #date range
prefixes <- c("arr", "dep")
cols <-
c("Hong Kong Residents",
"Mainland Visitors",
"Other Visitors",
"Total")
headers <-
c("Control_Point", crossing(prefixes, cols) %>% unite("headers", 1:2, remove = T) %>% unlist() %>% unname())
answer <- list() #empty list
theDate <- start
while (theDate <= end) {
url_data <-
print(paste0("https://www.immd.gov.hk/eng/stat_", format(theDate, "%Y%m%d"), ".html"
)) #while loop
rows <-
read_html(url_data) %>% html_elements(".table-passengerTrafficStat tbody tr")
df <- map_dfr(rows,
function(x) {
x %>%
html_elements("td[headers]") %>%
set_names(headers) %>%
html_text()
}) %>%
filter(Control_Point %in% c("Airport")) %>% #select only airport data
mutate(across(c(-1), ~ str_replace(.x, ",", "") %>% as.integer())) %>%
mutate(date = theDate)
answer[[theDate]] <-df #data collected in df
theDate <- theDate + 1
Sys.sleep(5) #set interval for data request
}
write.csv(bind_rows(answer), "immigrationStatistics.csv") #bind rows into file once and for all
要存取連續日子數據的話,主要改動包括:
- 先要設立空的 list;
- 把每一天的數據拼入 df;
- 拼完才開始新一天的爬蟲;
- 定下每次存取間距;
- 最後一次過寫進檔案。
檔案就存下了 11 天的數據,本地居民離境人數隨「0 + 3」措施實施而上升。

主題圖片來源:Sugarman Joe on Unsplash