前言 在Project Amaterasu中,我們預計將使用台灣的高速公路車流資料。這些資料可以在台灣政府的開放資料網站查詢並下載。我們將在這篇文章中紀錄我們是如何下載,又是如何去整理這些資料的。
下載資料 前置準備 首先,我們要到交通部的交通資料庫網站 中找尋我們要用的資料。我們需要的是各類車種通行量統計各類車種 的資料,資料類別為M03A 。進入M03A 的資料頁面 後,我們可以觀察到可以下載的檔案有兩種類型:
資料夾形式:為近期的歷史資料(以及部分2016年的資料)。
Image by Author 壓縮檔案形式:為一個月以上的單日資料,以壓縮檔案形式提供下載。
Image by Author 在這網站中的資料實在太多,我們如果要一個一個手動下載會耗費非常多的時間與精力。更好的方式是使用程式來自動下載。為了撰寫程式,首先我們可以透過瞭解網頁的元素來解析目標檔案的存放方式,並設計下載的程式。
使用開發者模式後,我們可以發現檔案的存放方式很簡單,連下載方式都很簡單。只要以該網頁的連結加上檔案名稱就可以下載對應的壓縮檔案,實在非常容易。
這邊我們邊忽略還沒有變成壓縮檔案的日期,即時資料在這邊暗中並不是如此重要,等到這些資料變成壓縮檔案再下載也不遲。
撰寫程式 既然知道檔案的連結,那我們就可以使用Python來撰寫下載的程式了。我們將會需要使用以下幾個Python套件:
wget: 下載檔案使用 rich: 顯示進度使用 pandas: 處理日期以及結構化資料使用。 concurrent: 使程式碼可以平行或是同步運行。 下載程式的核心程式碼如下所示:
1
2
3
import wget
wget . download ( url , out = output_dir )
Copy 只要使用wget
搭配連結,並指定輸出的位置,就可以將網路上的檔案下載到電腦中的指定資料夾。
由於檔案數量龐大,我們會希望同時下載多個檔案,這時候就需要concurrent
套件的協助了。我們將使用concurrent
套件中的ThreadPoolExecutor
功能來建立線程池,用以執行我們所指定的任務。
以下是結合了wget
以及concurrent
所撰寫的下載程式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import os
import wget
import pandas as pd
from rich.progress import Progress
from concurrent.futures import ThreadPoolExecutor
def get_tar_file (
item_name ,
output_dir ,
base_url ,
):
url = f " { base_url }{ item_name } "
try :
wget . download ( url , out = output_dir , bar = None )
except urllib . error . HTTPError as e :
if e . code == 404 :
print ( f "Archive { item_name } does not exists!" )
else :
print ( f "An error occured! Exception: { e } " )
def main ():
base_url = "https://tisvcloud.freeway.gov.tw/history/TDCS/M03A/"
start_date = '2021-01-01'
end_date = '2021-02-01'
output_dir = "./data"
num_workers = 5
dateList = [
ts . strftime ( "%Y%m %d " )
for ts in pd . date_range ( start_date , end_date , freq = "1D" )
]
tarfileList = [ f "M03A_ { date } .tar.gz" for date in dateList ]
download_func = partial ( get_tar_file , output_dir = output_dir , base_url = base_url )
with ThreadPoolExecutor ( max_workers = num_workers ) as executor :
with Progress () as progress :
task1 = progress . add_task ( "[red]Downloading..." , total = len ( tarfileList ))
for _ in executor . map ( download_func , tarfileList ):
progress . update ( task1 , advance = 1 )
if __name__ == '__main__' :
main ()
Copy 在上方的程式碼中,我們下載了2021年一月一日到2021年二月一日之間的資料。我們將這些下載的資料存放到了./data
資料夾之中。我們使用了pandas
的date_range
函數來產生指定在一段時間之內,以指定頻率所間格的時間戳記,並根據下載的需求使用strftime
函數將時間戳記轉換為格式為%Y%m%d
的字串,並將字串前後加入對應的格式來構成檔案名稱。
我們使用了try...except
的語法來避免指定下載的檔案不存在。詳細可以參考這篇文章 。
在下載完成後,我們將會在指定的資料夾中看到已經下載好的壓縮檔案:
1
2
3
4
5
M03A_20210101.tar.gz M03A_20210106.tar.gz M03A_20210111.tar.gz M03A_20210116.tar.gz M03A_20210121.tar.gz M03A_20210126.tar.gz M03A_20210131.tar.gz
M03A_20210102.tar.gz M03A_20210107.tar.gz M03A_20210112.tar.gz M03A_20210117.tar.gz M03A_20210122.tar.gz M03A_20210127.tar.gz M03A_20210201.tar.gz
M03A_20210103.tar.gz M03A_20210108.tar.gz M03A_20210113.tar.gz M03A_20210118.tar.gz M03A_20210123.tar.gz M03A_20210128.tar.gz
M03A_20210104.tar.gz M03A_20210109.tar.gz M03A_20210114.tar.gz M03A_20210119.tar.gz M03A_20210124.tar.gz M03A_20210129.tar.gz
M03A_20210105.tar.gz M03A_20210110.tar.gz M03A_20210115.tar.gz M03A_20210120.tar.gz M03A_20210125.tar.gz M03A_20210130.tar.gz
Copy 處理壓縮檔案 如果你使用的是Linux系統,我們將可以使用for迴圈搭配tar
指令來解壓縮這些檔案。我們先示範一下如何解壓縮一個檔案:
1
tar zxvf M03A_20210101.tar.gz
Copy 執行完上方的指令後,將會出現一個M03A
的資料夾,其中有一個20210101
的子資料夾。
關於如何在Linux系統解壓縮各種檔案,可以參考這篇文章 。
接下來,我們可以先來熱身一下,使用for迴圈來輸出資料夾內所有檔案的名稱:
1
for file in $( ls) ; do echo $file ; done
Copy 上方的指令中,我們將ls
指令的結果作為對象,使用for迴圈來迭代每一個結果。執行後會看到以下的輸出。
1
2
3
4
5
6
7
M03A_20210101.tar.gz
M03A_20210102.tar.gz
M03A_20210103.tar.gz
M03A_20210104.tar.gz
M03A_20210105.tar.gz
M03A_20210106.tar.gz
... (省略)
Copy 我們只需要把echo $file
改為tar zxvf $file
就可以經鬆的使用for迴圈來將所有的資料解壓縮了。以下是完整的指令:
1
for file in $( ls) ; do tar zxvf $file ; done
Copy 解壓縮完成後,我們可以觀察一下資料集的儲存方式。以2021年一月一日為例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
M03A/20210101/
├── 00
│ ├── TDCS_M03A_20210101_000000.csv
│ ├── TDCS_M03A_20210101_000500.csv
│ ├── TDCS_M03A_20210101_001000.csv
│ ├── TDCS_M03A_20210101_001500.csv
│ ├── TDCS_M03A_20210101_002000.csv
....
├── 01
│ ├── TDCS_M03A_20210101_010000.csv
....
├── 02
│ ├── TDCS_M03A_20210101_020000.csv
│ ├── TDCS_M03A_20210101_020500.csv
....
Copy 為節省版面,我們省略了一部分的輸出。可以看到資料夾是以天 為單位建立主要資料夾,並以每小時 為單位建立子資料夾,並在每小時的資料夾中,每五分鐘 建立一筆csv
檔案。
小結 在這篇文章中,我們使用了wget
以及concurrent
來建立一個快速下載交通資料庫的程式。請注意,我們並未限制下載的頻率以及次數,有些網站可能會針對一些過於頻繁的下載請求進行阻擋,甚至是封鎖,請自行確定每個網站的規則後,加上必要的措施來避免在下載完資料之前就被網站給拒於門外。