2015年3月17日 星期二

IMPORTHTML提取中文網頁資料之亂碼解決方式(部分情形可解決)

近來都把試算表的使用重心放在Spredsheet上(暫時對EXCEL失去興趣了XD),為了解決提取網頁資料亂碼問題,爬了許多文才找到下列這個自定函數的運用,此方式並無法完全解決所有網頁的問題

以Spredsheet IMPORTHTML()函數提取中文網頁資料,常會看到一堆亂碼,經比對網頁編碼方式,幾乎確定Spredsheet是預設將資料以"西歐語系"來呈現(網頁設計觀念我不是很懂,似乎是網頁以JvaScript或Ajax獲取資料的編碼設定有關)。

解決方式:請開啟  工具/指令碼編輯器  ,自創新的函數(要記得先編譯過,開放授權後續才能使用自定函數),以下是我用的二個方式,針對不同情況測試
function encode_utf8( s ){
  return Utilities.newBlob("").setDataFromString(s, "ISO-8859-1").getDataAsString("UTF-8") ;
}

function encode_big5( s ){
  return Utilities.newBlob("").setDataFromString(s, "ISO-8859-1").getDataAsString("big5") ;
}

測試一、假如網站資料呈現是繁體中文(BIG5),此方式轉換100%成功,例如台工銀網站證券
(渣打銀行匯率資料也是以繁體中文編碼,但無須任何轉換及可正常顯示,所以問題與網頁編碼形式似乎無多大關聯)

將要轉換的儲存格套上公式即可  =encode_big5( 儲存格 )
底下是轉換的範例

測試二、假如網站資料呈現是UTF-8(轉換方式如上所述方法,改用encode_utf8( )函數),例如公開資訊觀測站資料,很不幸的,轉換後仍然還是有部分亂碼

將IMPORTHTML取得的資料與網頁資料核對(網頁以ISO-8859-1編碼),發現部分內容不一致,才導致轉換無法完全成功,殘念....。

也想過是否誤判提取的資料預設編碼為ISO-8859-1,但更換數種編碼結果仍是失敗,所幸轉換過的內容大致可辨讀。


2015年3月16日 星期一

Spreadsheet提取公開資訊觀測站現金流量表資料

公開資訊觀測站現金流量表並不是正規的TABLE表格,即使使用EXCEL WEB查詢,資料仍會無法正確顯示。
原先想利用IMPORTXML()去提取裡面有用的資訊,不知為何,嘗試多次均失敗,可是部分網站又可以(例如http://www.marketwatch.com/),有傳聞GOOGLE試算表改為新版後就發生這個問題了。不管如何,山不轉路轉,我使用另外一個方式來提取資料

首先,要善用瀏覽器的插件來分析網頁(小弟我是用 firefox 的 httpfox),找到所需文件正確位置,本例是提取股票代號6184大豐電100年第四季的現金流量表資料,正確位置是
http://mops.twse.com.tw/mops/web/ajax_t05st36?firstin=1&off=1&keyword4=&code1=&TYPEK2=&checkbtn=&queryName=co_id&TYPEK=all&isnew=false&co_id=6184&year=100&season=04

單純使用IMPORTXML()抓到的資料長相如下


(資料亂碼應是編碼問題,小弟仍無法解決)

看似很整齊的資料單純利用SPLIT卻被分割的七零八亂,原因是換行及空白代號的問題,這個資料如果貼到WORD裡頭去觀看(要到選項設定裡打開顯示字元符號及空白),會看到換行符號為向下的箭頭
這個換行符號的代碼是CHAR(10),裡頭看不見的空格代碼是CHAR(32)

完整語法請參考
=transpose(split(IMPORTHTML("http://mops.twse.com.tw/mops/web/ajax_t05st36?firstin=1&off=1&keyword4=&code1=&TYPEK2=&checkbtn=&queryName=co_id&TYPEK=all&isnew=false&co_id=6184&year=100&season=04","table",5),char(10)))



因為我只是要提取部分資訊,所以我使用QUERY()來查詢資料(中文字雖然是亂碼,但是有對應,所以可以當搜尋KEY。注意,這種亂碼使用Vlookup是無法正確搜尋的)

以本例來說,我要查詢的是"營業活動之淨現金流入(流出)"的數據,所以搜尋KEY對應的亂碼就是 營業活動之淨現金流入(流出)

=QUERY(B1:B300,"select * where B like '%營業活動之淨現金流入(流出)%'")
取出的資料仍然放在同一格,再利用SPLIT分離一次

如果只要100年度的數值,可配合使用 index()
=index(split(QUERY(B1:B300,"select * where B like '%營業活動之淨現金流入(流出)%'"),char(32)),1,2)
99年度數值==index(split(QUERY(B1:B300,"select * where B like '%營業活動之淨現金流入(流出)%'"),char(32)),1,3)