用Python秒速製作上市公司業績表

剛過去的周三,股王騰訊(0700)公布中期業績,由於市場關注其業績會否走樣,因此大量投資者不斷F5港交所網站的披露易,令網站出現搶購演唱會門券般的網絡大塞車,結果業績開估真係乏善足陳。今期便以騰訊的業績通告為例,用Python寫一個小程式,以最快速度取得其業績內所有列表數據作分析。

港交所的上市公司通告,大多使用pdf的格式,要取用當中資料尤其是數字相當困難,因為用copy and paste其格式均會走位,不能直接放到google sheets或excel處理。因此筆者找了一會,找到由一名日本數據科學家所貢獻的程式庫tabula-py,可以把pdf上的列表「靚仔還原」,並可以即時進行處理。

首先是要安裝該程式庫tabula-py,詳細的方法及程式功能可以瀏覽這裡,由於這程式庫是要用Java的,故此請確定已預先安裝好Java。

在程式的開始,先載入相關的程式庫:

import tabula
import pandas as pd
import requests
import distro

之後,將騰訊的業績通告下載,或直接把鏈結存入filename亦可。將要讀取表格的頁數存入pageno,然後要求程式讀取,並清除NaN等無資料的空格。

filename="LTN20180815893_C.PDF"
pageno=1
df=read_pdf(filename, pages=pageno, pandas_options={'header':None} )
df.fillna("")

結果已相當靚仔:

把這個表直接copy and paste到google sheet或excel,已可直接使用。程式亦提供功能讓你把結果以csv或json等格式儲存。

當然,世事並非這樣完美,譬如想取得業績報告第13頁較詳盡的損益表時,程式卻只取得如下的列表,由收入以下的五項數據都被忽略了。怎麼辦?

tabula-py提供的一個功能,是可以把需要的列表框起來,增加準繩度,方法是把pdf打開,並使用選擇工具,把表框起來,然後檢查座標,並輸入到程式中,如圖:

相關的程式碼為:

left=63.46
width=478.56
top=239.2
height=494.8
right=left+width
bottom=top+height
tablearea=[top,left,bottom,right]
df3=read_pdf(filename, pages=pageno, guess=False, area=tablearea, pandas_options={'header':None})

問題得以解決:

不過,通告中這頁並無提供增長數字,只是把首兩季數字並立,要做到即時比較,可以撰寫一個子程序。其中numtreatment是把數字中的逗點清除,並把括號中的數字變為負數,方便計算。

同時,因為不少業績表會在第二列作為註解,用家要告訴程式第二列(got_remark是True或False)是否註解,然後程式便會自動計算每個細項的增長或倒退。

def numtreatment(numstring):
 if numstring[0]=="(":
 numstring="-"+numstring[1:-1]
 numstring=numstring.replace(',','')
 return float(numstring)
#業績處理
got_remark = False
df4=df3.copy()
if got_remark:
 df4=df4.dropna(how='all',subset=[2,3])
 df4=df4.drop(1, axis=1)
else:
 df4=df4.dropna(how='all',subset=[1,2])
df4.loc[:, 'growth'] = 0
for i in range(len(df4)):
 try:
 new=numtreatment(df4.iloc[i,1])
 old=numtreatment(df4.iloc[i,2])
 if new*old>0:
 df4.iloc[i,3]=str(round((new-old)/old*100,2))+"%"
 else:
 df4.iloc[i,3]="-"
 except:
 df4.iloc[i,3]="-"
 
df4.fillna("")

結果如下:

再進一步的處理,便是把一些升幅大或跌幅特別大的項目,以不同顏色highlight,讓投資者更快看到影響業績的主要因素。不過,即使憑上表,讀者也很容易看到騰訊按季缺乏增長點。

其實不單單用於業績,統計處每月均會公布月刊,當中亦包含不少列表,雖然統計處或會提供源數據的檔案,但月刊中的經整理後資料卻未必容易找到,這時亦可以用tabula-py來處理。依筆者的經驗,若果對較複雜的列表,如column相當多的,有時框起area亦未必可以解決,這時便要使用columns參數,把數據columns的一系列橫向坐標告訴程序,這樣通常都可以完美處理,相關程式如下:

tablecolumn=[200,280,374,457]
df=read_pdf(filename, pages=pageno, columns=tablecolumn)

tabula-py的功能已很強大,很多表格都可以順手拈來,但始終不能做到完美移植,筆者亦發現通告不斷有例外情況,很難寫一個包羅所有情況的程式,這或許要靠人工智能來突破。

另外,筆者近日多用nteract來寫Python程式,取其與jupyter notebook類似,但更易起動,而且測試方便,在此推介一下。