2018-04-13

Get JSON open data from url with Javascript, PHP, and Python.

政府資料開放平臺 (DATA.GOV.TW) 公開了非常多的政府資料,我們可以很方便的取得這些資料來作分析、應用,甚至設計成網站或App讓其他人使用。那要如何取得這些資料呢?以下將介紹幾個很簡單取得開放資料的方法…

政府資料開放平臺 (DATA.GOV.TW) 上提供的資料有 xml, json, csv, 甚至是 pdf, zip 等格式,我們將針對 JSON 這個目前相當普遍使用的資料交換格式介紹從客戶端 (Client) 取得政府資料開放平臺上的 JSON 格式資料的方式。本篇僅介紹取得資料的技術,若想對政府資料開放平臺和 JSON 有更多的了解,可以到下列網站:
本篇介紹的方式包含由客戶端直接取得政府資料開放平臺上 JSON 資料的三個方式:
Javascript XMLHttpRequest, jQuery getJSON(), jQuery ajax()
如果客戶端無法直接取得資料,使用伺服器端 (server) PHP 或以 Python 取得 JSON 資料的方式。
我們的目標是開發 Web 或 Web App,將取得資料的工作交由客戶端可以減輕 server 的負擔,所以先來了解怎麼從客戶端直接取得 JSON 資料。

方法1 - Javascript XMLHttpRequest
XMLHttpRequest 物件會開啟 URL,並發起 HTTP 請求,XMLHttpRequest 可以很簡單的設定為同步 (synchronous) 或非同步 (asynchronous) 請求。以下就是 Javascript 以 XMLHttpRequest 物件取得 JSON 資料的方式,資料取得成功會呼叫 myFunction(xmlhttp.responseText),取得的 JSON 資料就在 xmlhttp.responseText 中。以下是 XMLHttpRequest 方法的程式碼和解說:
var xmlhttp = new XMLHttpRequest();   // 建立XMLHttpRequest物件
var url = "";   // 欲取得的JSON資料網址url
xmlhttp.onreadystatechange=function() {
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
        // 資料取得成功呼叫自訂函數 myFunction()
        myFunction(xmlhttp.responseText);   // xmlhttp.responseText中就是取得的資料
    }
}
xmlhttp.open("GET", url, true);   // 使用GET方法,true --> 非同步(asynchronous)
xmlhttp.send();   // 送出請求
您可以在自訂函數 myFunction(xmlhttp.responseText) 中對取得的 JSON 資料作進一步的處理。我們以政府資料開放平臺提供的文化部音樂表演資訊,試作一個簡單的完整範例,這個例子加上了Bootstrap美化表格,若不需要就將Bootstrap的引用刪除:
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- Bootstrap CSS & JS 若不使用Bootstrap可將以下4行引用刪除-->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>

    <script>
        var xmlhttp = new XMLHttpRequest();
        var url = "https://cloud.culture.tw/frontsite/trans/SearchShowAction.do?method=doFindTypeJ&category=1";
        xmlhttp.onreadystatechange=function() {
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                myFunction(xmlhttp.responseText);
            }
        }
        xmlhttp.open("GET", url, true);
        xmlhttp.send();
        
        function myFunction(response) {
            var arr = JSON.parse(response);
            var i;
            var out = '<table class="table table-striped table-hover">' +
                        '<thead><tr><th scope="col">#</th>' +
                        '<th scope="col">活動名稱</th>' +
                        '<th scope="col">主辦單位</th>' +
                        '<th scope="col">活動時間</th>' +
                        '<th scope="col">活動售票</th></tr></thead><tbody>';
        
            for(i = 0; i < arr.length; i++) {
                out += '<tr><th scope="row">' + i + '</th><td>' +
                arr[i].title + "</td><td>" +
                arr[i].masterUnit + "</td><td>" +
                arr[i].startDate + "</td><td>" +
                arr[i].sourceWebName + "</td></tr>";
            }
            out += "</tbody></table>";
            document.getElementById("showData").innerHTML = out;
        }
    </script>
</head>

<body>
    <h2>Get JSON Open Data Example</h2>
    <h4>文化部-音樂表演資訊</h4>
    <div id="showData"></div>
</body>
</html>

方法2 - jQuery getJSON()
getJSON() 是 jQuery 提供可向伺服器發出取回 JSON 資料的 AJAX HTTP GET 請求,它是一個簡單版的 ajax 方法。以下是 getJSON() 方法的程式碼和解說:
jQuery(document).ready(function(){   // 將$.getJSON()放在document.ready事件中
    var jqxhr = $.getJSON(url, function(arr) {   // url是JSON資料的網址,取得的資料存在arr變數中
        console.log("success");   // 請求成功會執行此區塊,可在此處理JSON資料
    }).done(function(arr) {
        console.log("second success");   // 另一個請求成功會執行的區塊,也可在此處理JSON資料
    }).fail(function() {
        console.log("error");   // 請求失敗會執行這個區塊
    }).always(function() {
        console.log("complete");   // 無論請求成功或失敗都會執行的區塊
    });
});
同樣以政府資料開放平臺提供的文化部音樂表演資訊,試作一個簡單的getJSON()完整範例,注意因為使用getJSON()需引用jQuery JS:
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- Bootstrap CSS & JS 若不使用Bootstrap可將以下4行引用刪除 -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
    <!-- 使用getJSON()需引用jQuery -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

    <script>
        jQuery(document).ready(function(){
            var url = "https://cloud.culture.tw/frontsite/trans/SearchShowAction.do?method=doFindTypeJ&category=1";
            var jqxhr = $.getJSON(url, function(arr) {
                console.log("success");
                var i;
                var out = '<table class="table table-striped table-hover">' +
                            '<thead><tr><th scope="col">#</th>' +
                            '<th scope="col">活動名稱</th>' +
                            '<th scope="col">主辦單位</th>' +
                            '<th scope="col">活動時間</th>' +
                            '<th scope="col">活動售票</th></tr></thead><tbody>';
            
                for(i = 0; i < arr.length; i++) {
                    out += '<tr><th scope="row">' + i + '</th><td>' +
                    arr[i].title + "</td><td>" +
                    arr[i].masterUnit + "</td><td>" +
                    arr[i].startDate + "</td><td>" +
                    arr[i].sourceWebName + "</td></tr>";
                }
                out += "</tbody></table>";
                document.getElementById("showData").innerHTML = out;
            }).done(function() {
                console.log("second success");
            }).fail(function() {
                console.log( "error" );
            }).always(function() {
                console.log( "complete" );
            });
        });
    </script>
</head>

<body>
    <h2>Get JSON Open Data Example</h2>
    <h4>文化部-音樂表演資訊</h4>
    <div id="showData"></div>
</body>
</html>

方法3 - jQuery ajax()
使用非同步 JavaScript 及 XML(Asynchronous JavaScript and XML,AJAX),以下是 ajax() 方法的程式碼和解說:
jQuery(document).ready(function(){   // 將$.ajax()放在document.ready事件中
    $.ajax({
        type: "GET",   // 使用GET方法
        url: "",   // 取得JSON資料的網址
        dataType: "json",   // 資料類型 json
        async: true,   // true(非同步請求 defaule), false(同步請求)
        success: function(arr) {   // 取得的資料存在變數arr中
            // 請求成功執行的區塊,可在此處理JSON資料
        }
    });
});
同樣以政府資料開放平臺提供的文化部音樂表演資訊,試作一個簡單的ajax()完整範例,注意因為使用ajax()需引用jQuery JS:
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- Bootstrap CSS & JS 若不使用Bootstrap可將以下4行引用刪除 -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
    <!-- 使用ajax()需引用jQuery -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

    <script>
        jQuery(document).ready(function(){
            $.ajax({
                type: "GET",
                url: "https://cloud.culture.tw/frontsite/trans/SearchShowAction.do?method=doFindTypeJ&category=1",
                dataType: "json",
                async: true,
                success: function(arr) {
                    console.log("success!");
                    var i;
                    var out = '<table class="table table-striped table-hover">' +
                            '<thead><tr><th scope="col">#</th>' +
                            '<th scope="col">活動名稱</th>' +
                            '<th scope="col">主辦單位</th>' +
                            '<th scope="col">活動時間</th>' +
                            '<th scope="col">活動售票</th></tr></thead><tbody>';
            
                    for(i = 0; i < arr.length; i++) {
                        out += '<tr><th scope="row">' + i + '</th><td>' +
                        arr[i].title + "</td><td>" +
                        arr[i].masterUnit + "</td><td>" +
                        arr[i].startDate + "</td><td>" +
                        arr[i].sourceWebName + "</td></tr>";
                    }
                    out += "</tbody></table>";
                    document.getElementById("showData").innerHTML = out;
                }
            });
        });
    </script>
</head>

<body>
    <h2>Get JSON Open Data Example</h2>
    <h4>文化部-音樂表演資訊</h4>
    <div id="showData"></div>
</body>
</html>

方法4 - 使用 PHP
如果無法從前端直接抓資料,因同源政策(Same-origin policy) 或 cross-domain error,則可由伺服器端以 PHP 抓取。PHP 提供了 file_get_contents 和 curl 方法來取得 JSON 資料。 PHP 應該就一定可以抓取了。以下是這兩個方法的參考資料及使用方式:
PHP - file_get_contents() 使用方式:
<?php
    $url = "";  // Your json data url
    $data = file_get_contents($url);  // PHP get data from url
    $json = json_decode($data, true);  // Decode json data
    // 處理取得的 json 資料
?>
PHP - curl 使用方式:
<?php
   $url = "";  // Your json data url
   $ch = curl_init();
   curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
   curl_setopt($ch, CURLOPT_URL, $url);
   $data = curl_exec($ch);
   curl_close($ch);
   $json = json_decode($data);   // Decode json data
   // 處理取得的 json 資料
?>

方法5 - 使用 Python
也可以從伺服器端以 Python 抓取,然後存成 .json 檔放在伺服器上, Python 抓取 JSON 資料的方式如下:
import requests
data = requests.get(url="")   // Your json data url
print(data.json())   // 檢視取回的json資料
可將抓取回來的 JSON Data 存成 .json 檔,程式碼如下:
import requests
import json
data = requests.get(url="http://cloud.culture.tw/frontsite/trans/SearchShowAction.do?method=doFindTypeJ&category=3")
with open("a.json","w",encoding="utf-8") as myFile:   // 開啟檔案以寫入JSON資料
    json.dump(data.json(), myFile,ensure_ascii=False)
myFile.close()
以上就是本篇介紹取得政府資料開放平臺 JSON 格式資料的方式。

參考資料 (References):
😺 jQuery 官方文件 - jQuery.getJSON()