【祿】邁向財務「自由」之路:建立專屬且免費的自動化軍隊1(上篇)

副題:Google Sheets自動六合彩彩池到價電郵提示 Step-by-Step 更可引發無限應用可能

多數企業家成功的一大基本條件,在於將較基本的工作交與別人而自己保持清晰的腦袋。這樣,企業家便能節省時間,集中精力發揮自己的所長。將基本的工作交與別人,更能發揮乘數效應,同一時間擁有多個自己同時工作,發揮最大的效能。

我們作為個體戶或是小投資者,未必能聘請員工作為「秘書」或是「軍隊」為自己效命。然而現今科技進步,我們何不跟大企業學習,借助互聯網和雲端運算,在網路世界將日常執行的繁瑣事情程序化,建立虛擬秘書軍隊?

筆者這次會從最簡單的例子開始,解構如何利用 Google Sheets 製作六合彩彩池到價電郵提示。

讀者應很容易就能舉一反三,製作股票到價提示、每日投資組合狀況匯報、每周賬單繳付提示等系統。從此不用再記得去 refresh 網站、生怕錯過了機會;而且有甚麼要知道、何時要知道,都由自己話事,活像是擁有專屬自己的秘書甚至是自動化軍隊,更甚者這是免費的


要建立六合彩彩池到價電郵提示,大致有三大步驟:
1. 建立一張能閱讀六合彩彩池及下期搞珠日期的 Google Sheet
2. 建立一段能將彩池及日期以電郵發出的程式碼
3. 建立指示讓程式碼在搞珠日後的午夜運行

上篇會先介紹第一步驟,下篇會介紹餘下兩個步驟。如果讀者希望直接取得原檔,可以在本頁留言處留下電郵地址;原檔會在下篇發表後不日發出。


1. 建立一張能閱讀六合彩彩池及下期搞珠日期的 Google Sheet

要建立 Google Sheet,首先要擁有 Google 帳戶。登入 drive.google.com 後選新增空白的 Sheet 文件。給他隨便起個名字,就叫 MarkSix 吧。

六合彩彩池及下期搞珠日期的資訊可在馬會網站http://bet.hkjc.com/marksix/index.aspx?lang=ch 找到:



要利用 Google Sheet 閱讀資訊,方法是利用 ImportXML 函數。函數有兩個參數:

=IMPORTXML(url, xpath_query)

url 顧名思義就是資料來源的網址,即是 "http://bet.hkjc.com/marksix/index.aspx?lang=ch"(緊記加上 quotation marks)。
xpath_query 是需要閱讀的資訊在頁面的位置,例如我們要閱讀六合彩彩池的資訊,就得告訴 Google Sheet 這個彩池到底放在網頁的哪裡。

找出這位置的編碼通常是整個Project 最具挑戰性的部分。一般第一個嘗試的方法是 Inspect Element。方法是在瀏覽器上 Highlight 彩池的金額,按滑鼠右鍵,選取「Inspect」或「Inspect Element」(筆者用的是 Google Chrome,其他瀏覽器的操作應是大同小異的):



瀏覽器會彈出網頁的原始碼,並 Highlight彩池金額的相關部分。此時在 Highlighted原始碼按滑鼠右鍵,選取「Copy XPath



此時如果我們貼上 Copy 了的東西的話,大概會得到以下的結果:

//*[@id="oddsTable"]/table/tbody/tr[2]/td/table/tbody/tr/td[1]/table/tbody/tr[6]/td[2]

這就是六合彩彩池的資訊在上述馬會網頁的位置。

現在讓我們測試一下能否使用這位置擱取彩池資訊。在 Google Sheet Cell A1 輸入:

=IMPORTXML("http://bet.hkjc.com/marksix/index.aspx?lang=ch", "//*[@id="oddsTable"]/table/tbody/tr[2]/td/table/tbody/tr/td[1]/table/tbody/tr[6]/td[2]")

很抱歉嘗試是失敗的。仔細看看 Formula Bar,會發現 xpath_query 參數中有一個部分顏色轉黑了。原來 Google Sheet 誤以為 XPath 裡的 " Google Sheet Function 定義字串結尾用的 "



解決方法是多打一個 " 以示脫逸:

=IMPORTXML("http://bet.hkjc.com/marksix/index.aspx?lang=ch", "//*[@id=""oddsTable""]/table/tbody/tr[2]/td/table/tbody/tr/td[1]/table/tbody/tr[6]/td[2]")

這次函數順利執行,但執行結果是 #N/A,即是函數未能取到任何資訊。通常的原因是 XPath Restrictive,這時候可以嘗試取走一些可有可無的項。例如在這個例子中,每一個 table 中只可能有一個 tbody,那就是說 tbody 這些項是可有可無的。擁有一些基本 HTML 的認識會對這除錯步驟很有幫助。

Xpath_query 中取走所有 tbody 的項:

=IMPORTXML("http://bet.hkjc.com/marksix/index.aspx?lang=ch", "//*[@id=""oddsTable""]/table/tr[2]/td/table/tr/td/table/tr[6]/td[2]")

這回我們終於成功取到彩池金額:



其實如果讀者對 HTML 有少許認識,不難在網頁原始碼發現彩池金額的 td cell 已經附送了 id

<td class="snowball1" style="line-height:15px;">$15,000,000</td>

利用這個資訊以及少許 XML 的知識,可以嘗試更乾淨俐落的取到彩池金額:

=IMPORTXML("http://bet.hkjc.com/marksix/index.aspx?lang=ch", "//td[@class=""snowball1""]")

Google Sheet 會回傳兩個金額,一個是多寶 / 金多寶,另一個是我們要的彩池。



仔細看一下網頁原始碼尋找原因,讀者會發現多寶 / 金多寶的金額也是用同一個格式裝住的,而 ImportXML 函數會回傳在網頁中所有符合條件的項目。這時候我們只要告訴函數我們想取的是第二個 Element 即可:

=IMPORTXML("http://bet.hkjc.com/marksix/index.aspx?lang=ch", "(//td[@class=""snowball1""])[2]")



同一方法,我們可以在 Cell A2 用以下任一方法取得下期的搞珠期數:

=IMPORTXML("http://bet.hkjc.com/marksix/index.aspx?lang=ch", "//*[@id=""oddsTable""]/table/tr[2]/td/table/tr/td[1]/table/tr[2]/td[2]")

=IMPORTXML("http://bet.hkjc.com/marksix/index.aspx?lang=ch", "(//td[@class=""content""])[5]")


資料擱取大致完成。然而為了方便下一個步驟的資料處理,讓我們先將彩池金額從文字(字串 string)換成數字。在 Cell B1 輸入:

=VALUE(A1)


以後每次打開這張 Google Sheet,試算表就會自動從馬會網頁取得下期六合彩的彩池金額以及下期搞珠日期的資訊。

至於如何指令 Google Sheet 將此資訊定期電郵至讀者的信箱,敬請期待下篇

14 則留言:

  1. 這是一個很有用的工具, 不知為何沒人留言....
    我剛試用這方法從morningstar.com拿不同data, 但結果總是#N/A

    =IMPORTXML("http://financials.morningstar.com/ratios/r.html?t=0P000000XL&culture=en-US&platform=sal", "//*[@id=""tab-financial""]/table[2]/tr[2]/td[11]")

    =IMPORTXML("http://financials.morningstar.com/ratios/r.html?t=0P000000XL&culture=en-US&platform=sal", "//td[@class=""row_lbl""]")


    不知你是否曾經成功從morningstar拿到data呢?

    回覆刪除
    回覆
    1. Sboy兄,在本篇的下篇有很多留言,你可以去參考一下 :)

      Morningstar 也是我未能成功的例子,而且死因未明。讓我有空再研究。如果成功了,用來做債券評分真能省下不少功夫 :)

      刪除
  2. 好鐘意睇樓主呢類型應用programming 喺生活上的文章,希望可以分享多啲
    我自己連拎股票data 落excel 都深感困難......

    回覆刪除
    回覆
    1. 多謝 Lite Ocean 兄支持!拆解原始檔以取股價,也是一種挑戰,成功破解時更會有莫大的興奮感!

      刪除
  3. 福兄,剛剛看完了你幾篇教學,覺得真的很實用,香港少有全面且有心機既教學
    我嘗試跟隨你教學去抓取aastock的數據,例如:每股手數,可是返回數據都是N/A,
    請問下面那句google的importxml錯在哪裡,麻煩指正,辛苦了福兄: )

    =IMPORTXML("http://www.aastocks.com/tc/ltp/RTQuote.aspx?S=Y&Symbol=00005","//*[@id=""form1""]/div[2]/div[1]/div[5]/div[1]/div/table[1]/tr[6]/td[1]/div/div[2]/strong")

    回覆刪除
    回覆
    1. 感謝支持和讚賞!寫 Step-by-step 其實也是一種樂趣,既能幫人又能將自己的理解梳理一下 ;)

      在 .aspx 動態頁面抓資訊不容易,所以我都不在 AAStock 抓股價。每股手數的話,可以嘗試改在這一頁扒「買賣單位」:
      http://www.aastocks.com/tc/stocks/analysis/company-fundamental/basic-information?symbol=00005

      刪除
  4. 很實用的教學, 值得一讚!
    早幾年前用YAHOO FINANCE API抓股價數據, 在YAHOO FINANCE封了那API後就沒有其他辦法..
    看來可以跟你的步驟一試了~ :)

    回覆刪除
  5. 早些年曾用YAHOO FINANCE API抓股票資料, 在那API被封後一直沒有好辦法
    謝謝樓主分享, 小弟又可以去一試了~ :)

    回覆刪除
  6. 福祿壽全兄
    拜讀左你既文章真係獲益不淺呀。

    我成功用左你教既方法去抽取損益表,但係現金流量表就失敗左,可否求你指點一下?


    =IMPORTXML("https://www.aastocks.com/tc/stocks/analysis/company-fundamental/profit-loss?symbol=0005&period=2","//tr[@ref=""PL_Field_NB_4_1""]")

    =IMPORTXML("https://www.aastocks.com/tc/stocks/analysis/company-fundamental/cash-flow?symbol=0005&period=2","//tr[@ref=""CF_Field_1_2""]")

    回覆刪除
    回覆
    1. 對不起阿新,現在才看到你的留言。我記得兩頁的方法是差不多的,有空再給你看看,謝謝支持!

      刪除
    2. 方法應該沒有問題?只是留意AAStock 有否改了 Ref ID:-

      =IMPORTXML("https://www.aastocks.com/tc/stocks/analysis/company-fundamental/profit-loss?symbol=0005&period=2","//tr[@ref=""PL_Field_B_4_1""]")

      =IMPORTXML("https://www.aastocks.com/tc/stocks/analysis/company-fundamental/cash-flow?symbol=0005&period=2","//tr[@ref=""CF_Field_2_1""]")

      刪除
  7. 福祿壽全兄, 謝謝你的文章, 可否請教如何從 Seekingalpha 抓取 ex dividend date? 我試了很多 不同方法也失敗.

    =ImportXML("https://seekingalpha.com/symbol/SSW.PH/dividends/scorecard", "//td[@id=""ex-dividend-date""]")

    感激不盡!

    回覆刪除
    回覆
    1. 在 SeekingAlpha 可以考慮將整個 JSON format 的原料拿下來慢慢玩:
      =ImportXML("https://seekingalpha.com/symbol/SSW.PH/dividends/scorecard", "(//script/text())[2]")

      Ex-dividend date 是 "dividend":[] list 內的第一個元素內的 ex_date。

      刪除

熱門文章