iT邦幫忙

2021 iThome 鐵人賽

DAY 8
0
Mobile Development

使用 Swift 和公開資訊,打造投資理財的 Apps系列 第 8

D8 - 用 Swift 和公開資訊,打造投資理財的 Apps { 台股申購資訊實作.1 - 取得公開申購公告csv檔 }

承上一篇,公開申購公告的綱頁頁面如下

https://ithelp.ithome.com.tw/upload/images/20210916/20140622u3rX6SsvoV.png

依照我們會需要的欄位,我們的 model 如下

//
//  StockSubscriptionInfo.swift
//  ITIronMan
//
//  Created by Marvin on 2021/9/4.
//

import Foundation

/// 股票申購最小單位的 data model
struct StockSubscriptionInfo {
    
    let stockCode: String
    let stockName: String
    let subscriptionStartString: String
    let subscriptionEndString: String
    let subscriptionOccurString: String
    
    /// 承銷價
    let price: String
    
    /// 實際承銷價,不確定為什麼會有這個欄位,但看起來價格和承銷價一樣
    let actualPrice: String
    
    let stockDeliveringDateString: String
    
    let stockCountString: String
    
    /// 總合格件數,所有被扣款成功的數量
    let totalApplyCountString: String
    
    /// 中籤率
    let subscriptionRateString: String
}

如果你用的是 chrome,當滑鼠移到下載 csv 的位置的時候,你會看到下載的網址呈現出來,這個位置就是放 csv 檔案的地方。而後面的 yy=2021,就可以知道,他是依照年份為單位,來進行查詢的。

如果你換成 2020,那就會是 2020 年的所有資料。

csv 下載位置: https://www.twse.com.tw/announcement/publicForm?response=csv&yy=2021

依照前面的方式,再寫一個 StockSubscriptionManager 專門處理申購的資料。

//
//  StockSubscriptionManager.swift
//  ITIronMan
//
//  Created by Marvin on 2021/9/4.
//

import Foundation

/// 這個類別專門處理股票申購資訊
class StockSubscriptionManager {
    
    private lazy var alamofireAdapter: AlamofireAdapter = {
        return AlamofireAdapter()
    }()
    
    func requestStockSubscriptionInfo(year: Int, completion: @escaping (([StockSubscriptionInfo], Error?) -> Void)) {
        
        // https://www.twse.com.tw/announcement/publicForm?response=csv&yy=2021
        let urlString = "https://www.twse.com.tw/announcement/publicForm?response=csv&yy=\(year)"
        
        alamofireAdapter.requestForString(urlString, method: .get) { result in
            
            switch result {
            case .success(let string):
                print("you got string: \(string)")
            case .failure(let error):
                print("error: \(error.localizedDescription)")
            }
        }

    }
}

在測試的時候,我們先隨便找一個按鈕來發動 StockSubscriptionManager 的下載,看會不會有 header 或是資料跑出來

不過,照著這一份程式碼,這一個 func 發動的時候,console 上面會印出一堆,你好像看得懂,又好像看不懂的東西。

在印出來的結果上,你看得懂的是那些數字,所以先看這些可被辨識的文字代表什麼。110/09/14 應該是日期,3533 是股票代號,110/09/08 也是日期,後面有個 432。比對這些數字,他應該就是前述截圖中的 [嘉澤],只是編碼和預設的不同,所以無法被 String 識別。

https://ithelp.ithome.com.tw/upload/images/20210917/20140622lqCOCx9elZ.png

已經知道 requestForString 會出編碼的問題,至少確定 data 的 request 是有的,所以要改用 AlamofireAdapter 中的 request,並傳出 (Data?, URLResponse?, Error?) 讓這個 manager 進行 String parsing。

// https://www.twse.com.tw/announcement/publicForm?response=csv&yy=2021
        let urlString = "https://www.twse.com.tw/announcement/publicForm?response=csv&yy=\(year)"
        
        alamofireAdapter.request(urlString, method: .get) { data, response, error in
            
            if let error = error {
                completion([], error)
                return
            }
            
            var subscriptionList = [StockSubscriptionInfo]()
            
            if let data = data,
               let string = String(data: data, encoding: .utf8),
               let csv = try? CSVAdapter(rawString: string) {
                
                print(csv.header)
                print(csv.namedRows[10])
                
            }
            
            completion(subscriptionList, error)
        }

然後再試著找個測試按鈕,看一下 csv 能不能被 print 出來。

https://ithelp.ithome.com.tw/upload/images/20210918/20140622mwdJCjt62C.png

結果,是完全沒有反應,所以你遇到了開發者的日常。「有 bug!」

分析:

  • 是否為網址的問題? →貼到 chrome 上會跳出下載 csv 的視窗,所以網址正確

  • 是否 alamofire 呼叫有問題? → 在 error 那邊沒有跳出,所以沒發生 error

  • 第 31 行是否有 Data? → 使用 console print data,有 26651 bytes,而且和下載的 csv 檔比對 file size,不太可能是這邊有錯
    https://ithelp.ithome.com.tw/upload/images/20210918/20140622VjO8qoC3sg.png

  • 第 32 行後,就跳離 if let,沒有往 33 行走,可以確定的是 String(data: data, encoding: .utf8) 這邊, string 是 optional,所以程式跳出。

也就是…這個 String 不是 UTF-8 的編碼…

那他還可能是什麼編碼呢? 如果檔案是繁中的話,那應該就是 Big5

Big5 簡介如下

https://zh.wikipedia.org/wiki/大五碼

先找找看,有沒有其他 utf-8 編碼的來源?

在公開申購的右上方,有個 [English] 標籤,點下去後,頁面就變成全部英文了。然後滑鼠移到 csv 那一欄,連結變成下方這樣,可以看到,中間多了個 /en/,下載後的檔案,裡面的內容全部是英文。來試試看換成英文版的 csv 檔,能不能拿到我們要的資訊。

https://www.twse.com.tw/en/announcement/publicForm?response=csv&yy=2021

https://ithelp.ithome.com.tw/upload/images/20210918/20140622FWkV2ViPlp.png

成功了,如果把下載來源換成英文,就可以下載了。但和中文版資料相比,英文版資料只有 code,沒有名稱,所以還需要有一個 stock code vs. stock name 的表來查。如果是上市/上櫃增資,已經在市場上可以交易,所以在前面所提到的 上市/上櫃 公司基本資料表裡面有,如果真的想使用英文資料的話,可以使用 stock code 去前面的資料庫裡面反查 stock name。

https://ithelp.ithome.com.tw/upload/images/20210918/20140622lcOVpwMrMn.png

但是,Swift String 真的只能吃 utf8 嗎? iPhone 是被設計出來賣到全世界的產品,如果不能轉換成每個地區的語言/曆法/習慣,那是賣不出去的。

而 String 的 init 被設計為可以輸入 encoding,所以,一定是有方法可以將 Big5 的 Data 轉換成 String。

下一篇會說,怎樣實作操作 Big5 的 String


上一篇
D7- 用 Swift 和公開資訊,打造投資理財的 Apps { 台股申購分析資料來源 }
下一篇
D9-用 Swift 和公開資訊,打造投資理財的 Apps { 台股申購實作.2 -讀取Big5碼的csv}
系列文
使用 Swift 和公開資訊,打造投資理財的 Apps37

尚未有邦友留言

立即登入留言