2016年12月31日 星期六

如何剖析不標準的網頁

最近在寫 PHP 爬蟲程式時遇到一個比較特殊的網頁, 需要費一點功夫來處理, 雖然也不算太麻煩, 但因為值得以後處理類似網頁時參考, 於是就抽出一點時間記錄一下. 這網頁就是鉅亨網的類股行情表 :

# 鉅亨網類股行情表

此網頁將集中市場每日盤後各產業分類的成交量, 比重, 以及指數漲跌幅等資料做成一個報表, 且可查詢近一周的資訊. 紀錄各分類所佔比重變化可以知道資金往哪個產業移動, 若比重逐漸增加, 表示該產業逐漸成長增溫, 資金流向此產業將推升股價, 特別是該產業的龍頭股; 反之則是該產業逐漸降溫, 有可能走入景氣循環的下坡, 市場籌碼漸漸抽出. 另外從台股產業龍頭的電子股與金融股也可以看出市場交易的冷熱情形, 電子類股占比若低於 50% 表示市場過冷; 而金融類股占比若超過 10% 表示市場過熱.

檢視此網頁的原始碼可知, 此網頁的類股資料放在 <!-- 資料區塊:start --> 與 <!-- 資料區塊:end --> 之間的 <div> 區塊裡, 裡面含有三個表格, 而我們需要的類股資料放在第三個表格中的 tbody 元素裡面, 因此我會以 thead 末尾的幾個欄位標題當作開頭標誌, 以 </tbody> 當作結束標誌, 這樣就能輕易抓出 tbody 內部的一堆 tr 與 td 所構成的儲存格內容. 擷取網頁的程式碼如下 :

//===擷取目標網頁 : 鉅亨網類股行情表===
$target="http://www.cnyes.com/twstock/a_price4.aspx";
echo "<br>擷取鉅亨網類股行情報表 : <a href='$target' target='_blank'>原始網頁</a><br>";
$ref=$target;
$web_page=http_get($target,$ref); //下載網頁檔
$file=$web_page['FILE'];
$file=preg_replace("/([\s]{2,})/","",$file); //先去除多餘空白以利尋標

這裡我們用 preg_replace() 函數將原始網頁中的多餘空白去除, 包含跳行字元, 因此取得的原始碼字元串會變得很緊緻, 有利於後續剖析. 接下來要抓出 tbody 內的儲存格資料, 程式碼如下 :

//擷取表格內容 : 最後一個 table
$start='市值(億)</th><th>增減</th></tr></thead><tbody>';
$end="</tbody>";
$data=return_between($file, $start, $end, EXCL);

這裡 $start 就是該表格的 thead 最後面的幾個欄位直到 <tbody>, 具有唯一性 (才不會找錯資料), 呼叫 return_between() 函數後會傳回開頭與結尾中間的儲存格內容, 包含 tr 與 td 元素. 不過這些元素含有樣式屬性與元素 (font), 必須去除才好處理, 程式碼如下 :

//純化表格:去除屬性與不需要的元素
$data=str_replace(' bgcolor="#FFFFFF"', "", $data);; //去除 <tr> 屬性
$data=str_replace(' nowrap align="center"', "", $data);; //去除 <td> 屬性
$data=str_replace(' nowrap align="right"', "", $data);; //去除 <td> 屬性
$data=remove($data, "<font", ">"); //去除 font
$data=str_replace('</font>', "", $data);; //去除 font

經過這樣處理後的 tr 與 td 序列就全部乾淨了, 只含有 tr, td 以及資料. 但是仔細看這些 tr 與 td 元素發現, 這些表格元素不是標準的 HTML 格式, 例如部分 tr 為 <tr >, 裡面含有一個空格; 其次它沒有 tr 與 td 的結束標籤, 格式如下 :

<tr >
  <td>電子
  <td>324.97
  <td>64.69
  ...
<tr>
  <td>金融
  <td>37.33
  <td>7.43
  ...

缺乏結束標籤會造成剖析上的困難, 因為 parse_array() 與 remove() 函數都需要開頭與結束標籤來尋標. 解決之道是對其進行矯正, 修正為標準 HTML 格式. 程式碼如下 :

//修正 HTML 格式
$data=str_replace('<tr >', "<tr>", $data);; //矯正 <tr >
$data=str_replace('<tr><td>', "</tr><tr><td>", $data); //補上 </tr>
$data=substr($data, 5); //刪除最前面多加的 </tr>
$data .= "</tr>";
echo "<br>類股比重漲跌<br><table border=1>".$data."</table><br>";

這裡首先用 str_replace() 將 <tr > 全部改成 <tr>, 去除 tr 中的空格, 其次用 str_replace() 將 <tr><td> 全部改成 </tr><tr><td>, 亦即補上缺漏的 </tr>, 但是這樣一來最前面就會多出一個 </tr> 了, 因此須用 substr() 把前面 5 個字元刪掉. 這樣就把 $data 變成標準的 HTML 格式了.

咦, td 不是還缺結束標籤嗎? 是的, 但這可以不需要處理, 因為拆分欄位不需要再次使用 parse_array(), 只要用 <td> 當拆分符去拆解每一列, 就可以取得所需要的比重與漲幅欄位了, 程式碼如下 :

$arr=parse_array($data, "<tr", "/tr>");  //拆分每一列 (共 30 列)
for ($i=0; $i<count($arr); $i++) { //拜訪每一列 (每一支股票)
  $brr=explode("<td>", $arr[$i]); //拆分每一欄
  $sector=$brr[1];  //類別
  $ratio=$brr[3];   //比重
  $delta=$brr[7];   //漲幅
  echo "$sector : 比重=$ratio% 漲跌=$delta%<br>";
  }

這裡先拆分 tr 列, 然後在迴圈中用 explode 拆分行, 類別欄位在第 1 欄 (索引 1), 比重在第 3 欄 (索引 3), 而指數漲幅在第 7 欄 (索引 7). 咦, 第一欄不是索引 0 嗎? 沒錯, 但因為用 <td> 當分界符, 所以索引 0 是一個空值. 舉個簡單的範例來說明會比較明白 :

$str="<td>1<td>2<td>3";  //沒有結尾 </td> 的儲存格
$arr=explode("<td>",$str);  //[0]為空白, [1]為 1,...
print_r($arr);

在這個範例中, 以  <td> 拆分字串時, 第一個  <td>  前面的空值 "" 是第一個被拆除來的子字串, 它會變成索引 0, 而第一欄的資料會在索引 1, 依此類推.

網頁格式不一定是標準的 HTML, 剖析處理時要視情況個別處理, 以上只是一種特例.

2016年12月30日 星期五

買養命酒與消費高手好關鍵

昨天去巷子口幫二哥買枇杷膏時看見貨架上有擺養命酒, 就問老闆一瓶多少, 答說那是 1000 毫升的, 要 1000 元. 本想買一瓶喝看看是否冬天手腳冰冷的情況會改善. 但轉頭一想, 還是回去比個價再說.

由於年底還有一天休假必休, 所以早上就在家上網查詢, 發現東森購物最便宜的是兩瓶 1599 元, 一瓶 800 元有找, 比巷子口藥局便宜兩百塊! 因此我就買了兩份共 3189 元.

# 【養命酒】藥用養命酒1000mlX2入組



另外, 爸的退化性 (髖) 關節炎四月份時小舅媽介紹去管醫師那裏, 吃坡尿酸剛開始效果非常顯著, 但之後似乎就疲乏了. 最近電視上廣告打得兇的消費高手好關鍵, 據說對退化性關節炎有改善效果, 所以我就進行了一番調查, 才曉得原來膠原蛋白有好幾種型, 第一型就是一般我們所認知的跟防止皮膚退化有關的, 而第二型才是跟關節有關的, 參考 :

關節不卡卡:非變性第二型膠原蛋白(UC-II)的實證
見証『 UC-II® - 非變性二型膠原蛋白(Undenatured Collagen Type II) 』
非變性二型膠原蛋白膠囊,保留膠原蛋白完整活性 讓你步伐好輕盈

消費高手好關鍵主要含非變性二型膠原蛋白, 由雞冠萃取的坡尿酸, 以及橄欖果萃取物. 除了消費高手外, 美商健而婷 NOW 也有類似商品 :

NOW健而婷-UCII 二型膠原蛋白 (60顆/瓶) $1350 (5 折)

不過它跟消費高手不同處在於它不含坡尿酸, 而是添加海藻鈣. 考慮了一早上, 最後還是買了消費高手好關鍵 3 入兩組共 6 瓶, 任買兩組折 1000 相當於 69 折共 9560 元.

【3.4倍升級】破億!愛用者好動見證★升級版★消費高手好關鍵(3盒組)


根據說明這要空腹吃, 搭配維他命 C 更好吸收. 等到貨後再帶回去鄉下給爸吃看看.

市立圖書館的管理問題

今天超不開心, 中午去河堤還書時, 志工阿姨說其中一本 C 語言的書應還光碟, 我說沒有借光碟啊! 因為我若有借光碟一定會用膠帶黏在書後以防遺失 (我是如此謹慎+龜毛的人), 但電腦註記我有借光碟, 只是光碟編號 2821 與館內實際那片 2812 不同, 這根本就是之前的志工記錯了, 第一, 我沒借記成有借, 第二, 光碟編號還記錯. 但是那個阿姨還是說這本書不能還, 要我回去找看看光碟, 這不就是要我跑兩趟嗎?

我對物品管理很有自信, 自知回去根本找不到那片光碟, 我就問那戴眼鏡的阿姨, 如果找不到光碟怎麼辦? 她說那就要買一本書來賠. 哇咧! 如果是志工打錯也要我賠? 我又不是沒經驗, 以前在左新就遇過明明剛拿去還的一本書, 三天後接到 EMAIL 通知說那本書逾期沒還. 我趕緊跑去澄清說已經還了, 但是館員與志工怎麼找也找不到, 電話查詢原藏書分館也說架上沒有, 逾期未還. 這下我真是跳到黃河也洗不清, 跟館長說你們要在櫃台架攝影機, 以免有爭議時吵不完. 如果再找不到我就要買書來賠了, 結果幾天後左新通知我, 書找到了, 因為志工把它放在櫃台底下忘記刷還了. 哇哩咧.

不只這樣, 幾年前還接過前鎮分館來電, 說我們在前鎮借了好多本書未還, 我連左新都嫌遠了, 還大老遠跑到前鎮去借? 電腦資料錯亂了張冠李戴亂栽贓, 我說這樣無憑無據對用書人非常不公平, 因為我們無法舉證, 請他們再查看看電腦哪裡出問題. 後來就沒再打來了, 我覺得至少也要打個電話道個歉吧.

為了避免這個困擾, 我決定以後非必要不借光碟, 跨館一定會有光碟就沒辦法, 只好用多重膠帶給它黏牢. 要不然圖書館志工來來去去對業務不熟悉以及少一根筋的大有人在, 隨便這樣亂一下就有我們受的了.

晚上我又再跑一趟河堤, 索性將一批最近不可能有時間看的 C 語言書全還了. 這回換一位歐吉桑, 他中午也知道這件事, 但在忙別櫃未介入, 他說光碟在館內 (也就是說我根本沒借光碟), 編號打錯, 就收書還了. 真是的, 可以一次搞定的事偏要我們跑兩趟. 要不是家裡沒地方擺書, 我寧可去書局買一本, 才不想這樣奔波去借書呢!

關於 cron jobs 執行頻率的調整問題

這兩周來已把 PHP 專案中的 cron jobs 程式大致寫完, 目前執行頻率大都是 5 分鐘, 但是手動執行時偶而會收到伺服器會回應 "Resource limit reached", 詢問線上客服, 他們回覆說是因為我的 Premium 方案可使用的 CPU 資源已超過之故, 這可能是我設定每五分鐘執行一次, 每一個 cron job 大約都在 0, 5, 10, ... 分同時執行的關係. 雖然等個幾秒鐘重試即恢復正常, 但顯然執行頻率似乎需要調整.

其實 Cron jobs 大致可分成兩類, 一種是所擷取的目標網頁是個別公司的資料, 因此需要靠指標來分批擷取, 也是這次要將擷取頻率從每 5 分鐘一次改成每 15 分鐘一次的對象; 第二種是擷取的網頁已包括全部訊息, 不必依賴指標移動來分批擷取者 (例如美元指數資料), 這種 cron job 只要半小時或一小時擷取一次即可, 我是將其分散在 0~59 分啟動執行, 例如下圖是指定在每小時的 5 分去執行一次 cron job :


而需分批執行的 cron jobs 則要依據資料多久必須全部更新一次來考量執行頻率. 若以目前擷取 976 個公司資料來計, 若要在一天內更新全部資料的話, 每小時要更新約 967/24=40 個, 每次抓 10 個的話, 每小時要抓 40/10=4 次, 亦即大概 60/4=15 分鐘抓一次即可. 在 Hostinger cPanel 的 advanced cron jobs 中有每 15 分鐘執行一次的選項 :


底下時, 日, 月, 周都用 Every ~ 即可, 如下所示 :


當然有些不需要每天更新一輪的 cron 可以設為每 30 分鐘執行一次 (通常一次 10 個), 這樣就是每兩天全部刷新一遍了, 同理可推, 每小時執行一次的話要 4 天才會抓齊全部資料; 每兩小時一次的話則要 8 天.

今天因為還剩休假一天必須休掉, 下午重新整理 cron jobs 設定, 大部分都改成 15 分鐘 run 一次, 少部分需要在 8 小時內分批抓齊資料者 (如 yahoo 的 credit, major, dealing) 仍維持每 5 分鐘跑一次. 在此將做法做個紀錄以便後續參考.

2016年12月27日 星期二

2016 年第 50 周記事

週六 12/24 參加了母校電機系 50 周年慶, 到場的同學還是我們這十個出頭的老面孔, 許多同學還是失聯中. 不過還是非常開心, 見到了三十年未謀面的老師, 大家能聚在一起吃個飯真不容易.

本周閒暇時間還是在忙 PHP 專案, 進度還算不錯, 爬蟲程式越寫越順手, 但是要在元旦前完成恐怕非常拚. 總之, 計畫只是理想, 人生中大部分的場景都是且戰且走.

週日因菁菁要求出去走走 (都是我大嘴巴沒做好計畫就隨口說說), 原本想去茂林, 後來覺得很久沒去三地門, 就臨時改去三地門, 順便測試一下剛買的 Garmin 4592R Plus 導航機. 實測結果非常滿意, 反應速度很快, 圖資也很精確.


茄萣濕地自行車之旅

昨天 12/26 補行憲紀念日放假, 是一例一休前最後一個勞工小確幸, 上回合歡山的老班底再次出擊, 這次是騎自行車到茄萣濕地, 中午到附近興達港吃海產再折回, 下面是老張寄給我的行程計劃 :

路程大約: 08:30文藻->蓮池潭->世運主場->援中港->台17->茄萣濕地(中午在興達港附近用餐再騎回高雄 ), 沿途會在7-11休息補充,原則每10km或50-60分鐘休息一次.

要準備的物品 :
  1. 腳踏車安全帽
  2. 頭巾
  3. 運動褲褲尾要束緊免得絞入鍊條
  4. 太陽眼鏡
  5. 飲用水 / 可攜帶香蕉等含鉀水果補充能量
  6. 可帶小背包(勿帶大背包)
  7. 手套
  8. 只攜帶健保卡及悠遊卡, 減少攜帶零錢
我這次不騎二哥的小黑 (登山越野車), 改騎小白 (小折), 因為小白從沒出過遠門, 我想操它一下, 未料此乃錯誤決策, 我反而被它操得吱吱叫. 因為小折輪子小, 變速器又少人家一檔, 人家踩一圈我要踩兩圈, 真是累死我了. 我一路都落後車隊起碼一百公尺, 都靠紅綠燈才跟上隊伍.

此行除了同學四人外, 還有老張的同事冠志兄, 他是自行車好手, 挑戰過武嶺, 老張請他幫我們領隊. 去程由於逆東北季風, 騎起來非常吃力, 冠志兄說由他在前面破風, 我們緊跟在後就會比較省力, 但這招對我沒用, 因為我 ... 全程落隊. 

早上約 9 點從文守路文壬家出發, 經蓮池潭轉台 17 線, 約 11:50 到達目的地茄萣濕地, 全程約 36 公里 :



這個濕地非常遼闊, 吸引許多水鳥聚集 : 




濕地周圍有賞鳥屋與賞鳥樓, 在賞鳥樓上吃過點心, 稍作休息後就前往興達港附近的大茄萣海產吃午餐, 這裡好吃的魚丸叫姑嫂丸, 據說是一對姑嫂合力經營的, 我看到招牌原先以為是在賣中藥哩. (這幾張都是老張拍的,  他們的相機比較好).

回程是順風較好騎, 但因為一吃完飯就啟程, 所以出發不久膝蓋內側肌肉就抽筋, 還好冠志兄教我以腳尖踩踏板, 兩腳稍內縮才不致一路抽筋. 回到高雄剛好下午四點半, 不僅屁股痛, 連腿都軟了. 

此行教訓 :
  1. 遠程不要騎小折.
  2. 一些裝備還是要買 : 束褲, 頭巾. 
至於車子, 的確, 好車當然有其價值, 但現階段還不用花大錢另買新車, 二哥那台越野車堪用即可. 

2016年12月24日 星期六

母校電機系 50 周年慶

今天回我的第一母校高應大參加電機系 50 周年慶, 見到了畢業 30 年來第一次相見的師長, 實在非常高興, 在中正堂遇見以前教我們電子學的洪麟老師 (也是三年級時的導師), 以及超級優秀當過母校校長的方俊雄學長, 跟阿超一起趨前報上級數向他們握手寒暄, 他們或許不記得我是誰了, 但這不重要, 我記得就好.

# 高應大電機工程系50周年慶 千餘系友回娘家

本來大家約好不用太早去, 因為典禮可能漫長而無聊. 但我覺得, 以前到中正堂參加集會確實無聊, 但現在還怕無聊嗎? 如果可能, 還真想回到過去全班被叫到中正堂集合的日子哩! 所以我還沒九點就到現場了, 但是舉目所見都是不認識的學長, 過了一會兒才看到阿超, 我們兩人聊了一會兒看見一位老先生走過來, 問說 : 我應該有教過你們吧? 我們馬上站起來說 : 老師好! 但是, 突然忘記老師名字了, 怎麼想就是想不起來, 只記得以前在自動控制與電磁學課堂上常聽他提到道家的龜息大法.

後來遇到我的同事蔡學長, 趕緊問他, 這才想起來是蔡繁仁老師. 中午在操場午宴時他來到我們這一桌, 我趕緊湊過去問他 : 老師, 您的龜息大法練到第幾層了? 他笑著說 , 哈哈哈, 說到這個就對你們不好意思了, 他大概是覺得以前在課堂上愛閒扯淡吧! 但我想說的是 : 老師, 您教的馬克士威爾方程式我們早已經忘記了, 但提到龜息大法, 沒有一個同學會忘記您啦! 人生中, 記得的才是無價.

Source : 中國時報

蔡老師來到我們這桌時, 剛好被中時記者拍下這張照片, 然而, 我卻被建興與明璜的兩個大頭擋住了! 殘念! (BTW : 以奴, 你的頭頂也太亮了吧!)

午宴席開 150 餘桌, 近尾聲時主持人請老師們到前台接受我們的致敬, 然後要求學生們別只是握手, 擁抱一下老師吧! 剛開始有些靦腆, 但我還是走向前擁抱了黃國恩老師, 黃文良老師, 以及洪麟老師, 但卻漏掉了李慶祥老師, 真可惜, 因為五十年慶就只有一次, 而我是離校三十年後才再次見到老師哩! 這種機會不會很多, 超珍貴.

以前保守的我不習慣擁抱, 但有了小孩後, 從小我就會跟小狐狸們 kiss good night, 但姐姐與二哥中年級後就不跟我抱抱了, 只有菁菁到現在還保持這個習慣. 阿超聽我說之後超羨慕, 我說就是一個習慣啦! 就跟寫日記一樣, 如果堅持每天都要寫, 那麼就不會間斷.

2016年12月20日 星期二

2016 年第 49 周記事 : 家裡來了一隻小貓

週五晚上菁菁去上英文課的時候, 學校的理化項老師送來一隻黑色小貓, 放在一個粉紅塑膠籠子裡, 我提上來的時候只有稍微打開瞧瞧, 只見她怯生生地待在角落裡, 咕嚕嚕的一雙大眼盯著陌生的我看. 菁菁本來說就放在警衛室, 她回來時再提上來, 因為她想要成為第一個看到她的人, 但是我說這樣管理員不就是第一個看到她的人嗎?

我提上來之後就放在客廳茶几上, 我看她到處張望後就躺在籠子裡睡覺了, 我也沒逗她, 就寫程式去了. 過一會兒就聽到她在喵而喵的, 兩爪不斷地在抓籠子, 我就放她出來, 她這裡看看那裏聞聞, 竟然鑽到客廳木椅底下躲起來了, 喵也喵不出來. 我想她可能還在觀察環境就不理她, 繼續寫我的程式. 接著我就例行去圖書館還書, 順道去畫室載姐姐, 回來時她還是躲在椅子底下, 不過菁菁說餵過後已經不會那麼怕生了. 晚上睡覺前還是把她關回項老師的籠子裡, 免得到處亂跑.

經過幾天適應後, 這隻小貓已經熟門熟路, 每天聽到早上我起來就從木椅下鑽出來喵啊喵的, 我就先把她抱進貓砂盆尿尿, 其實項老師自小貓出生後就有在訓練, 所以她現在已經會自己跑去盆裡解決衛生問題. 早上我在看新聞做甩手功時, 她還會蹲在電視前面盯著螢幕看, 真是可愛 :


菁菁說要叫她汪汪, 因為她本來想養狗不可得只好求其次養貓, 但是名字還是要叫原本要給狗狗的名字. 我則叫她 Monkey, 因為怎麼看, 我都覺得她那張貓臉長得真像猴子. 家裡從來沒養過貓犬類的寵物, 突然間客廳有一隻毛茸茸的東西在穿來穿去還真不習慣哩!

本周過完離新年剩下兩週了, 2016 就要莎喲娜拉囉. 這周我還是把全部閒暇時間拿來寫 PHP 專案, 所以沒有多少時間寫網誌, 我希望專案進度能在年底前結束, 我想盡速回到 Arduino 與 Raspberry Pi 的學習上.

兩周前種的玉米已長高不少, 故本周又買了 20 株來種, 但這次的苗較小, 所以先放個一周再種. 另外也買了十株茄子苗先行種下去, 這回要立柱牽繩好好照顧, 希望能採收兩年. 菁菁特愛吃絲瓜, 我應該多種些絲瓜才對, 所以預計下周再買三株來種.

2016年12月15日 星期四

EasyUI Datagrid 表格內容為超連結時的編輯問題

之前在測試 EasyUI 的 Datagrid 時發現, 若表格內容含有超連結, 這時使用 EasyUI Dialog 對話框編輯表格內容時會有一個問題, 就是呼叫 load 方法將所點選的列 (row) 內容載入表單中時, 含有超連結的欄位會載入超連結內容, 但實際上我們要編輯的只是超連結的 innerText 而已. 當時認為這很難處理, 所以就得到一個印象 : 表格內容盡量不要含有超連結, 除非它不需要編輯.

昨晚在替 PHP 專案新增一個 cron_list 資料表來管理 cron jobs 時, 又遇到這個問題. 因為我想在 cron_list 表格中可以直接按程式名稱的超連結就開啟新視窗去執行該 cron job, 但在編輯 cron 程式的說明欄位時, 由於程式名稱是超連結, 結果載入編輯欄位的就是那個超連結內容, 感覺很奇怪, 我要的是純粹的程式名稱而已.



經過來回測試各種方法後, 終於搞定這個長久以來未解決的麻煩. 其實方法很簡單, 就只是 Javascript 的字串處理而已. 處理方式如下 :

    $("#edit_cron").bind("click",function(){
      var row=$("#cron_list").datagrid("getSelected");
      if (row) {
        var str=row.program_name; //去除超連結用, 只取出程式名稱
        if (str.indexOf("<") != -1) { //避免第二次編輯時變空白, 只有第一次時才須擷取
          row.program_name=str.substring(str.indexOf(">")+1,str.lastIndexOf("<"));
          }
        $("#cron_list_dialog").dialog("open").dialog("setTitle","編輯 Cron 說明");
        $("#cron_list_form").form("load",row);
        $("#op").val("update_cron");
        $("#id").val(row.id); //edit 需要傳送 id
        }
      else {$.messager.alert("訊息","請選擇要編輯的 Cron 項目!","info");}
      });

與一般無超連結表格編輯方式不同之處就是加入了上面藍色部分的程式碼, 當第一次選取列進行編輯時, 所取得的 row.progrma_name 屬性值是超連結內容, 例如 :

<a href='http://www.myweb.com/cron/test.php' target='_blank'>test.php</a>

我要的只是其中 innerText 的 test.php 而已, 使用 Javascript 的 substring() 即可輕易取出超連結內的程式名稱, 先用 indexOf() 找出第一個大於符號索引, 加 1 就是 php 程式名稱的開始位置; 然後用 lastIndexOf() 從後面尋找第一個小於符號索引, substring() 會擷取此索引之前的字元. 哈哈哈, 總算搞定了, 這樣以後要處理含有超連結的表格就不會綁手綁腳了.

之前一直不願面對處理的難題竟然只要三行程式碼就解決了, 因為這次我既要在表格中使用超連結, 也要能編輯表格內容, 之前遇到阻礙就不想花時間去試, 這回被逼到了不得不面對. 可見, 障礙的高度通常不在問題的本身,  而是在我們心裡自己築起來的那道高牆.

參考 :

# Get selected row from DataGrid


2016年12月13日 星期二

2016 年第 48 周記事

之前菁菁一直想要養寵物, 從領養狗狗, 貓咪, 到市場的黃色小雞, 她都想要養, 當然都被我一一否決. 只要出去時看到有人遛狗, 她就會發狗瘋, 不斷地盧, 就是要養一隻狗. 我當然要技巧性地把話題扯開, 不然她的盧功真是讓人受不了.

前陣子學校的理化老師的母貓生了幾隻小貓, 問同學有沒有人要養, 她回來又再三央求要養貓, 水某鬆動了, 說給她養看看好了, 免得以後說我們都不讓她養. 我雖然覺得養寵物麻煩, 但也勉為其難答應了. 本來週六下午要送來, 但左等右等都沒來, 我看她捉摸不定, 一下子說這禮拜想在高雄, 一下子又說還是跟我回鄉下好了, 我說如果妳擔心周日老師送貓來, 那就留在高雄好了. 於是乎本周就我一個人回鄉下.

周六接到李麥克老師電話, 說二哥上課時在看數學, 被老師抓到唸了一頓, 跟家長通報一下. 我一直很煩惱二哥在英文上無法提起興趣, 上高中後雖然回李麥克上英文, 但是很少看到他拿英文小說來看. 回來後我也沒問他, 周一放學去載他, 他主動說想停掉李麥克的課, 因為實在無法應付. 我也覺得他說得對, 不能因為姊姊在那裏學得好, 就每一個人都得去那裏, 他覺得那種教學方式他不適合, 他適合傳統文法教學. 我看只好自己來教他了.

本周日傍晚程式告一段落, 想要活動一下筋骨, 又在菜園鋤了兩畦菜圃, 預定下周再種 20~40 株玉米. 其實把整理菜園當作一種運動也很不錯, 光一小塊地就讓我汗水淋漓 :


兩周前種下去的 22 株玉米只乾掉一株, 雖然幼苗有被壓折到, 但顯然生命力強大, 都活過來了. 但是離過年不到 50 天, 這次似乎太晚種了. 以後進十月就要開始種植. 另外兩周前種的地瓜葉也欣欣向榮, 再過兩周應可採摘矣 :


這一周來專心寫 PHP 爬蟲程式, 總算完成了預定進度的九成, 在闊別近一年後重回 PHP 專案雖然有點生疏, 但在之前認真寫下的筆記與備註輔助下, 短時間就可以迅速恢復戰力, 足見花點心力做備註跟寫筆記是有回報的. 不要太相信自己的記憶力, 也不要認為自己現在有多熟, 一段時間不摸保證忘光光, 之前多熟都沒有用.

鄉下頂樓的太陽能熱水器附裝的電熱控制器日前失靈了, 似乎是右側這顆電磁開關 (magnetic connector, 又稱電磁接觸器) 壞掉了, 因為按中間的手動按鈕也不會動作 :



爸說看能不能買到一樣的回來自己換, 回來高雄一查, 根本沒有這 Mitsuki FH-16H 型號! 畢竟是 25 年前的產品了! 我去小漢找, 發現電磁開關都非常貴, 至少要 500 元以上! 我看要先研究一下線路圖, 了解此電磁開關個接點作用後, 再去找個類似的來取代. 參考 :

# 電磁接觸器與按鈕開關該如何接線?
電磁接觸器(Magnetic Contactor)
動力群科電子報(教材教法) 交流電磁開關及其控制電路製作

2016年12月11日 星期日

PHP 日期字串格式轉換方式整理

這一周來演練 PHP 爬蟲程式, 發現不同的財經網站呈現日期的方式各不相同, 有民國紀元的, 例如 "105年12月9日"; 有西元紀元的, 例如 "2016/12/9", 而且個位數的月日有的有補 0, 有些沒有, 真是傷腦筋. 我寫程式喜歡格式統一, 這樣才能前後一致, 程式碼可以一刀未剪一再重複使用. 在日期方面採用 "2016-12-09" 十個字元格式; 日期時間則採 "2016-12-09 12:08:07" 格式, 其中日期與時間以空格隔開, 這樣要拆分處理時也方便.

我將這陣子在各財經網站看到的種種日期格式轉成 "YYYY-MM-DD" 格式的處理方法整理如後備查, 這樣以後要用到時就不用到每一個專案目錄下, 一個個檔案逐一開啟來尋找, 我最討厭那種 : "咦? 我記得在這個程式中有寫過這樣的功能啊? 怎麼找不到?", 這樣漫無目標地找, 還不如重新寫較快. 但再怎麼快, 都不會比用谷歌大神搜尋自己的筆記快.

1. 證交所三大法人買賣金額統計表 : 格式 "105年12月09日"

此網頁之日期含中文且使用民國紀元, 處理起來較費事, 不過個位數的月日都已補 0, 不算是最糟的, 處理方式如下 :

//擷取交易日期:格式 "105年12月09日"
$start="<span style='float:left;margin-left:171px;'>"; //頭標
$end="三大法人買賣金額統計表"; //尾標
$trade_date=return_between($file, $start, $end, EXCL);
echo $trade_date."<br>"; //"105年12月09日"
//改為 YYY-MM-DD 格式
$trade_date=str_replace("年","-",$trade_date); //年改為 "-"
$trade_date=str_replace("月","-",$trade_date); //月改為 "-"
$trade_date=preg_replace("/[^0-9-]/","",$trade_date); //除去其餘中文部分(日)
//改為西元年 YYYY-MM-DD 格式
$arr=explode("-",$trade_date);
$arr[0] += 1911; //民國年加 1911 為西元年
$trade_date=implode("-",$arr); //組合回去
echo $trade_date."<br>";

2. 鉅亨網新台幣兌美元匯率 : 格式 "20161209"

此網頁之日期為純數字, 年月日一氣呵成絕不含糊, 而且個位數的日月都已補 0, 所以處理方式就是抓出年月日後中間插 dash 即可 :

//擷取交易日期:格式 "20161209"
$start="昨收</th></tr><tr><td>"; //頭標
$end="</td>"; //尾標
$trade_date=return_between($file, $start, $end, EXCL);
echo $trade_date."<br>";
$Y=substr($trade_date,0,4);  //取出年
$M=substr($trade_date,4,2); //取出月
$D=substr($trade_date,6,2);  //取出日
$trade_date=$Y."-".$M."-".$D;  //組合成 YYYY-MM-DD 格式
echo $trade_date."<br>";

3. 期交所三大法人區分各期期貨契約 : 格式 "2016/12/9"

此網頁預設 GET 存取的話顯示最近一次交易日全部資料, 其日期標在表格右上角. 此頁日期格式月日個位數須補 0, 處理方式如下 :

//擷取交易日期:格式 "2016/12/9"
$start='<span class="right">日期'; //頭標
$end="</span>"; //尾標
$trade_date=return_between($file, $start, $end, EXCL);
echo "交易日期=".$trade_date."<br>"; //"2016/12/9"
//改為 YYYY-MM-DD
$arr=explode("/",$trade_date); //拆出年月日以調整月日格式
if ($arr[1] < 10) {$arr[1]="0".$arr[1];} //個位數前面補 0
if ($arr[2] < 10) {$arr[2]="0".$arr[2];} //個位數前面補 0
$trade_date=implode("-",$arr); //組成 YYYY-MM-DD
echo "交易日期=".$trade_date."<br>";

4. 期交所臺股期貨 (TX) 行情表 : 格式 "2016/12/09"

此網頁是期交所期貨每日交易行情查詢頁面, 預設顯示大臺行情. 其日期位置在表格左上方, 同樣是期交所網頁, 此頁日期格式硬是跟上面期交所三大法人持倉網頁的不一樣. 不過這個好處理, 因為個位數的日月都已經補 0, 只要將斜線改成 dash 即可 :

//擷取交易日期 : 格式 "2016/12/09"
$start="<h3 align='left'>日期:"; //頭標
$end="</h3>"; //尾標
$trade_date=return_between($file, $start, $end, EXCL);
echo "交易日期=".$trade_date."<br>"; //"2016/12/09"
//改為西元年 YYYY-MM-DD
$arr=explode("/",$trade_date);
$trade_date=implode("-",$arr); //組合回去
echo "交易日期=".$trade_date."<br>";

5. Yahoo 世界股市行情表 : 格式 "12/09/2016"

Yahoo 世界股市的日期格式是月/日/年, 要轉成 YYYY-MM-DD 有點麻煩, 不僅尋標要費點手腳, 日期還要拆開重組, 所幸個位數的月日已經補 0, 省了一道手續, 處理方式如下 :

//擷取交易日期:格式 "12/09/2016"
$file=preg_replace("/[\s]{2,}/", "", $file); //去除 2 個以上空格
$start="美加</font></td>"; //頭標
$end="&nbsp;"; //尾標
$trade_date=return_between($file, $start, $end, EXCL);
//去除前面不需要的元素
$trade_date=str_replace('<td height=20 align=right>', "", $trade_date);
$trade_date=str_replace('<font color="#330066">資料日期:', "", $trade_date);
$trade_date=trim($trade_date); //刪除左右可能之空格
echo "交易日期=".$trade_date."<br>"; //"12/09/2016"
//改為西元年 YYYY-MM-DD
$arr=explode("/",$trade_date); //[0]=月,[1]=日,[2]=年
$trade_date=$arr[2]."-".$arr[0]."-".$arr[1]; //組合成 YYYY-MM-DD
echo "交易日期=".$trade_date."<br>";

2016-12-12 補充 :

奇怪, 證交所三大法人買賣金額表明明昨天還是 BIG5 編碼的網頁, 今天就改版變成 UTF-8 編碼, 導致昨天改好的程式執行失敗. 即使改為 UTF-8, 還是無法擷取成功, 仔細看網頁原始碼, 原來網頁內容也有改變, 新版網頁處理方式要改成如下 :

//擷取交易日期:格式 "105年12月09日"
$start="<span style='float:left;margin-left:223px;'>";
$end="三大法人買賣金額統計表</span>";
$trade_date=return_between($file, $start, $end, EXCL);
echo $trade_date."<br>"; //"105年12月09日"
//改為 YYY-MM-DD
$trade_date=str_replace("年","-",$trade_date); //年改為 "-"
$trade_date=str_replace("月","-",$trade_date); //月改為 "-"
$trade_date=preg_replace("/[^0-9-]/","",$trade_date); //除去其餘中文部分(日)
//改為西元年 YYYY-MM-DD
$arr=explode("-",$trade_date);
$arr[0] += 1911; //民國年加 1911 為西元年
$trade_date=implode("-",$arr); //組合回去
echo $trade_date."<br>";


2016年12月7日 星期三

買 Garmin 4592R Plus 導航機

十月的時候花了很多時間在評估導航機, 當時結論是買 Garmin 4592R 這款, 但是後來一忙又不了了之. 上個月跟老張, 峰仔, 與文壬去攀登合歡山, 老張車上裝的就是 Garmin 導航機 (很舊了但還是照樣可下載圖資), 老同學們的意見也是買 Garmin, 但回來還是沒動作. 今天同事提醒我 10000 原的福利金 12/20 就要到期了, 所以就趕緊上網訂購了 :

訂單編號 :
219229
訂單狀態 :
新訂單
訂購時間 :
2016/12/07
訂單名稱 :
【GARMINnuvi 4592R Plus】GARMIN nuvi 4592R Plus Wi-Fi多媒體衛星導航(贈4好禮)
訂購商品明細 :


商品名稱項目單價數量
【GARMINnuvi 4592R Plus】GARMIN nuvi 4592R Plus Wi-Fi多媒體衛星導航(贈4好禮)10,990 1
商品金額 :
10,990
運費 :
0
訂單金額 :
10990
使用點數 :
10000
訂單應付金額: 
990

這比當初開始評估時的價格 11900 便宜了近 1000 元, 另外要將我原本的倒車攝影鏡頭連進來的話, 需要購買 Garmin 原廠的轉接線, 廠商原本說一條 420 元, 下午我打電話給客服問說要如何加購, 廠商回覆因之前客戶訂的貨有多出來, 所以免費送給我隨或寄送, 這樣又省了 420 元, 因此我這回只要花 990 + 800 (安裝費) 約 1800 元即可.

參考 :

# 汽車衛星導航評估

2016-12-10 補充 :

我 7 號訂, 8 號就通知要送貨, 比網頁上預訂的 9 號提早了一天. 由於在忙程式, 所以到貨後我只拆外箱, 確認贈品都在就擱在一邊. 昨天問鳳山阿勇的店, 說如果電源線與倒車攝影要走線必須確認線夠長, 隨即問供貨商, 說一條原廠電源延長線要 960, 好貴! 今早拆箱後比對發現原廠附的線確實只夠到點菸器而已. 不然先開去建億問看看, 結果有兩台車在裝, 只好預約下周二. 

2016-12-13 補充 :

今天請兩小時補休將車子開去民族路的建億, 將倒車顯影接到導航機上, 可惜電源線不夠長, 沒辦法將電源隱藏起來, 只好暫時垂一條線下來. 花了 300 元. 有找到一條 3.5 米的電源線, 如果可用的話再開去埋線. 這就是沒先問好得跑兩次, 花兩次錢 :

# 破盤王/台南 GARMIN 導航 行車記錄器 2A 車充線 電源線【3.5米】NUVI 4659R 4592R 57 $350

關於吸盤固定問題, 有人使用螢幕保護貼加 3M VHB 雙面膠, 參考 :

http://www.mobile01.com/topicdetail.php?f=621&t=3246461&p=2
# 3M VHB雙面膠帶-片狀(車外用) $139
# 壁掛式行車記錄器透明膠受不住高熱?
# 破盤王/台南 3M 助黏劑↘79元【透明10ml裝】超強助黏效果~晴雨窗/測速器/鯊魚天線/行車記錄器/後視鏡/氣氛燈 $79
# 行車記錄器後視鏡支架 $150
# 行車紀錄器支架 $120 
# 破盤王/台南 GARMIN 導航+行車記錄器 2合1【後視鏡支架】nuvi 3595 2585【錄得清】AA01 $399
# 3M 黏、吸盤吸的、後視境扣環,哪種行車記錄器安裝方法比較好呢?

"把黏貼式支架上的舊膠給撕下→塗上助黏劑後等個1分鐘→重新貼上3M專用超強雙面膠帶(灰色那種,厚度1.2mm)→前擋欲黏貼處用衛生紙擦一擦,塗上助黏劑後等個1分鐘→黏貼式支架與前擋結合→6個小時內不要扣上主機.有了助黏劑的加持就算要刻意把它拔下來也相當吃力"

薪資所得每月扣繳與定期定額投資 0056 比較

這幾天收到公司會計部門 Email, 要求就明年度所得稅額扣繳方式進行變更, 如果照舊由公司自每月薪資中預扣所得稅額, 那就不用採取任何動作. 我看了一下薪資單, 每個月都被預扣了 4200 元左右的稅額, 一年下來大概被預扣了超過 5 萬塊的稅, 也就是說我們每個月都已經在繳稅, 每年五月報稅只是做個總清理, 看是要補稅還是退稅.

這些錢如果自己存起來的話, 可以孳生額外的利息, 何必無息存在國稅局呢? 各銀行都有定期儲蓄存款, 可以臨櫃辦理一個在每年五月到期的一年定儲帳戶 (零存整付), 授權銀行每月自薪資帳戶中扣固定金額存在此帳戶, 次年五月要繳稅時剛好到期領出繳稅. 以台銀定儲一年利率 1.09 為例, 利用華南銀行網站提供的零存整付利息試算功能計算, 若每月扣 5000 元, 則到期本利和為 60355 元, 亦即可獲得 355 元利息 :

# 華南銀行零存整付儲蓄存款利息試算



雖然 355 元利息少得可憐, 但至少還可以吃個刷刷鍋吧! 對於欠缺理財技能的人小資族來說, 這是只要做個小改變就能擁有的小確幸. 當然, 對於理財高手來說, 每個月 5000 元若妥善投資, 應該可以帶來數倍於 355 元的利潤.

以投資台灣高股息 (0056) 為例, 它是 ETF (一籃子的高股息股票), 不必擔心踩到地雷股, 其股價通常在 20~25 元間變動, 股息殖利率平均來說大約 5%, 若這 5000 元每月購買 0056 零股, 一年投入 60000 元約可以買到 2400~3000 股, 以今年每股配 1 元來算, 應可獲利 2400 元左右, 這可是定儲利息 355 元近 7 倍的獲利啊!

由於是定期定額扣 5000 元買 0056, 當股價跌時買進股數會比較多, 漲時則買進股數較少, 因此實際持有成本大約是一年的平均值. 這樣投資到每年五月時就賣掉 0056 來繳稅, 如果股價高於平均持有成本還會有額外資本利得, 賣出後每個月 5000 塊還是繼續扣錢買進 0056. 定期定額投資零股可參考元富證券零股理財專區 :

http://www.masterlink.com.tw/money/DreamPlan

現在促銷方案零股定期定額每筆手續費 1 元!


參考 :

定存和定儲的存款利率如何計算?


2016年12月5日 星期一

埋貓記

今天下班騎機車前往悟饕買便當途中, 在河南路差點輾過一隻躺在路上的動物, 閃開後才弄清楚是一隻白色墨綠色花紋的大貓, 馬上掉轉回去查看, 發現這貓咪已經不幸身亡了. 念在牠屍身躺在路上可能會被車子輾爛, 我從機車置物箱找出一個塑膠袋, 抓住牠四肢將其移到路旁公園, 想說挖個洞埋起來, 但是沒有工具也沒辦法.

我抓住牠腳的時候, 發現仍有餘溫, 想必是在我到達之前剛被車子撞死的, 真是可憐. 剛好附近有垃圾車, 一位出來倒垃圾的老伯說那就丟垃圾車吧! 我說我趕時間, 我只能將牠放在公園草地上避免被車子輾爛而已, 不知道那位阿伯是否有將其丟到垃圾車. 在鄉下的話我就會在路旁農地挖個洞埋掉, 但在都市就不容易了, 只是沒有埋成那隻貓讓我感到有點為德不卒.

擷取期交所小型台指期 (MTX) 每日行情的方法

這幾天演練 PHP 爬蟲程式的寫法, 對象是期交所小型台指期 (MTX) 的每日行情表, 其網址為 :

http://www.taifex.com.tw/chinese/3/3_1_1.asp

不過連線這個網址預設是查詢大台 (MX) 的行情表, 小型台指期 (MTX) 必須在契約欄位選擇 "小型台指 (MTX)" 後, 按 "送出查詢" 後才會顯示小台資料 :



顯然這是透過表單以 POST 方法查詢, 其參數可在 Firefox 或 Chrome 按 F12 查得 :


雖然一共傳出 15 個參數, 但實際上只用到框起來的五個參數而已. 所以如果要抓今天的行情表資料, 可以利用 cURL 函式庫來擷取, 程式如下 :

/* 載入函式庫 */
include_once("../lib/http.php");    //匯入http模組     (必須)
/* 擷取目標網頁 */
$target="http://www.taifex.com.tw/chinese/3/3_1_1.asp";
echo "<a href='$target' target='_blank'>原始網頁</a><br>";
$ref=$target;
//取得交易日期 (今日)
$today=date("Y-m-d"); //2015-12-05
list($Y,$M,$D)=explode("-", $today); //分出年月日
echo "交易日期=".$today."(".$Y.$M.$D.")<br>";
//設定查詢表單 POST 方法參數
$para["qtype"]="2";
$para["commodity_id"]="MTX"; //小型台指
$para["syear"]=$Y;  //查詢年
$para["smonth"]=$M; //查詢月
$para["sday"]=$D;   //查詢日
$web_page=http_post_form($target,$ref,$para); //下載網頁檔
$file=$web_page['FILE'];  //取得網頁檔案內容
echo $file."<br>";

這是第一次嘗試用 POST 傳遞參數來擷取網頁, 以前我都一直使用 GET 方法, 沒想到 POST 其實也很容易, 只是要先查出必須傳遞那些必要參數而已.


2016年12月4日 星期日

2016 年第 47 周記事

本周非常忙碌, 公司一套舊系統要汰換, 相關配套措施有一些沒考慮清楚, 結果手忙腳亂. 從這次得到教訓, 撰寫 SOP 的工作必須抽空加速進行, 現在腦力不比從前, 過一個月就會忘得差不多了, 沒有 SOP 助憶是不行的.

二哥第二次段考往前推進到第七名, 僅英文 59 分不及格. 他對英文沒熱情, 文法根基不佳, 我看要寫個文法句型練習單來補強. 菁菁理化終於及格了, 但數學卻奇慘, 竟然考個 17 分, 她實在不是讀書的料, 還是儘早學一技之長為妙.

本周菁菁終於有空跟我回鄉下了, 而且還說要跟我去買菜. 她問說會不會去全聯? 會的話順便去隔壁的全家福看鞋子. 哇咧, 這才是她要跟我去買菜的目的吧! 以前是去市場旁邊那家米琪看衣服, 現在米琪遷走了, 換成看鞋子. 不過我自己也買了一個 Puma 的小背包, 原價 680, 特價 298, 我是想放在公司, 有時中午外出洽私用來背 iPad 或一些文件用.

早上去市場順路經過種子行, 買了 20 株玉米苗與一株絲瓜苗, 但到市場買了豆腐後, 粗心的菁菁把豆腐壓在上面, 導致絲瓜苗與約三, 四株玉米苗被折到. 傍晚還是將它們全數種在菜園, 能不能翻生就看造化了.

下午沒睡午覺, 一邊看守煮湯與燜蘿蔔的爐子, 一邊改 PHP 程式. 兩個小時無人打擾情況下專心地改好 fetch_taifex_options_pcr.php 與 fetch_taifex_futures_top10.php, 測試 OK.


2016年12月2日 星期五

還書一批

因為最近在忙 PHP 網路爬蟲程式, 手邊跟市圖借的幾本書都沒時間看, 乾脆一古腦兒全都還了, 以免分散了我的注意力, 在此做個紀錄, 爾後有空再借回來看 :
  1. jQuery Mobile 智慧型手機程式開發 (草衙)
  2. 超詳細! 基礎木工圖解書 (河堤)
  3. 自己動手打造超人氣木作 (河堤)
  4. 木工迷超手感入門木作 (河堤)
  5. 精確預測 :如何從巨量雜訊中,看出重要的信號? (美濃)
  6. 10 天做好 App-Corona SDK 超直覺遊戲開發攻略 (總館)
  7. 遊戲自己做-Corona SDK 跨平台 App 開發設計實戰 (河堤)
  8. 神奇洋蔥冰塊の自癒料理奇蹟
另外, 跟母校高師大借的 "人工智慧的未來:揭露人類思維的奧祕", 因為有人急用, 託圖書館寄了封 Email 來問我是否可先讓他看, 我想可能是有學弟妹寫論文要參考, 反正我也是沒時間, 只能斷斷續續看, 乾脆提前還書好了.

自從上週租了 Hostinger 虛擬主機後, 我的焦點又移回 PHP 專案了, 估計短時間內沒辦法繼續學習物聯網, 所以 Arduino 的實驗暫時要 Hold 一下, 時間所限, 網誌也會寫得少. 我現在的優先順序是 :
  1. PHP 專案 (新版工作日誌, 網路爬蟲)
  2. Python 學習 (GAE, 網路爬蟲, 機器學習)
  3. 樹莓派 (機器人, 智慧家庭)
  4. Arduino + ESP8266  (機器人, 智慧家庭)
  5. R 語言 (機器學習)
  6. 綠能
興趣廣泛實在不是件好事, 因為不容易聚焦.

2016年11月28日 星期一

2016 年第 46 周記事

時序已過了 46 周了, 再過五周這一年就要過去, 如果不是有認真在寫周記還真的搞不清楚日子是怎樣過去的. 本周比較重要的是周二去上了兩天 Python 進階的課程, 把我的注意力從 Arduino 導回 Python 以及 GAE, 主要是從課堂上得知兩本 Python 在資料擷取方面的好書, 我就想說應該可以用樹莓派 Linux 裡的 cron table 來抓資料經過分析後存在 MySQL 資料庫裡, 然後將分析結果以 Email 傳給手機. 等有空再次玩樹莓派時再來試試看.

這次去上課巧遇了兩個人, 一個是同棟不同單位但已調職他處多年的美智, 我們彼此都忘了對方名字了; 另外一位是以前跟我一起奉派去美國舊金山研習的三元兄, 算算這竟然已經是 11 年前的事了, 日子怎麼過得這麼快呀! 可不是嗎? 當時二哥才上中班呢! 轉眼已經上了高中. 我覺得五十歲之後, 對時光越來越來越敏感, 恨不得時間的巨輪能轉慢一些, 對於人生的得失也較了然, 比較不想去計較了.

很久沒在管菜園, 上週日鋤了一小塊地來種玉米, 玉米用的是年初小舅給我的一支玉米棒, 但是沒把握會順利發芽, 所以旁邊與重新栽植了地瓜葉. 一周過去了, 似乎沒看到發芽跡象, 周日一整天都在下雨, 我看再不發芽可能都要爛掉了, 下周乾脆去買玉米苗來種算了.

另外就是 11/23 向英國 Hostinger 以美金 27 元租用其 Premium 虛擬主機三年 (到 2019/11/23), 這幾天陸續將專案上傳部署後, 設定 Advanced Cron Jobs 功能去觸發指定之 PHP 網路爬蟲程式擷取資訊後進行分析, 平均執行時間約在 30~40 秒完成, 我對此 Advanced Cron Jobs 功能相當滿意, 因為它最快可以設定每分鐘觸發一次.


本周菁菁與二哥本來要跟我一起回鄉下, 但理化家教黃老師周六下午有事, 問說可否改為周日下午; 而二哥則補習班臨時要補課, 所以仍是我一人回鄉下. 以後上大學或就業, 全家一起回鄉下的機會想必是越來越少了. 從二哥國二去全晟補習理化開始, 大家坐 QRV 回鄉下的情景就變成我跟姊姊與菁菁三人而已. 然後今年七月姐姐也為了準備明年的學測開始週日要去補習班, 就變成我跟菁菁兩人了. 接下來呢, 菁菁也要面臨會考了, 小舅媽說得沒錯, 以後會變成只有我一個人回去了. 雖然明白這是離巢期將近的訊息, 但 ... 孤寂總是需要些時間來調適 ... Good old days.


2016年11月26日 星期六

Hostinger 的 Advanced Cron Jobs 設定

昨天終於有空將我的 PHP 專案上傳到 Hostinger 虛擬主機, 安裝好應用程式後馬上就來測試它的 "Advanced Cron Jobs" 功能, 如果好用的話就可以自行觸發 PHP 程式的執行, 不用再依靠 GAE 的 Cron  Jobs 從外部查詢觸發了.

首先登入後台管理頁面, 往下移到 "Advance" 區塊按 "Advanced Cron Jobs" 鈕 :



最上面 "Command to run" 框是填入要執行的 PHP 程式, 裡面有提示預設格式如下 :

/usr/bin/php /home/u123456789/public_html/cron.php

注意喔, php 與後面的 / 之間必須空一格, 我第一次輸入就忽略這個, 雖然可以順利建立一個 cron, 但是在 View Output 時就會看到下列 "Not a directory" 的錯誤訊息 :

/bin/sh: /usr/bin/php/home/u123456789/public_html/cron/fetch_twse_daily_close.php: Not a directory

我猜這是 Hostinger 當初在 /user/bin 下建立 php 目錄時多敲了一個空格所致, 可能用戶多了之後才發現, 只好將錯就錯了. 我的 cron jobs 檔都放在根目錄的 cron 資料夾下面, 所以正確的路徑應該是 :

/usr/bin/php /home/u123456789/public_html/cron/fetch_twse_daily_close.php



這樣 cron tables 便設定完成, 按 "View Output" 可看到最近一次執行結果 (如果沒有的話, 可能是被瀏覽器擋掉了, 檢查網址列是否有顯示自動阻擋彈出式選單的統計, 將其取消阻擋即可). 與 "Cron Jobs" (Simple) 比較, "Advanced Cron Jobs" 最快執行頻率可設到每分鐘跑一次, 設定選項比較細比較多; 而 "Cron Jobs" 則最快是一小時跑一次, 而且只能在整點時跑 (即 0 分時), 選項也比較少.


"Cron Jobs" (Simple) 的 command to run 欄位已經預先固定路徑到我的帳號底下, 因此不會碰到 "Advanced Cron Jobs" 中 php 後面須有一空格問題.

不過, 不論是 "Advanced Cron Jobs" 或 "Cron Jobs", 同一個程式只能設一次, 但如果分別在兩邊各設一次則可以, 亦即兩者是各自獨立的. 要解決此問題也很簡單, 就是把要在不同時間執行的程式複製為另一個檔案, 例如 fetch_twse_daily_1.php 與 fetch_twse_daily_2.php 即可, 或者乾脆就每個小時執行一次也不為過, 有些意天只能產生一筆的資料就在程式中用日期欄位來判斷即可.

當然我還是可以從外部用 GAE 來觸發執行, 但先看看內部觸發跑的情況如何, 優的話就不必用到 GAE 了.

2016-11-29 補充 :

觀察 Cron jobs 運轉兩天的報告, 我發現指定時間執行的程式都比預期時間晚 8 個小時執行, 例如指定 16:00:00 執行, 實際上卻是到 00:00:00 才真的跑. 我猜這是因為台灣與英國有 8 小時時差的關係, 我們是 GMT+8, 所以若指定下午四點執行, 我們下午四點時英國才當日早上 8 點, 而英國下午 4 點時我們已是晚上 12 點. 我已寫信詢問 Hostinger 是否有地方可以設定 Cron Jobs 時區的? 不過我相信是沒有, 這部分可能得自己換算, 反正就是將我們預定要執行的時間減 8 即可, 要不然就改為每小時或每兩小時執行一次, 然後在程式中依據日期欄位判斷是否已經執行過了, 是的話跳過即可.


河堤公園單車行

早上載菁菁去圖書館回來後, 看到我的小白已經兩個禮拜沒騎了 (太忙了), 還好手機有帶, 就直接換小白騎出去, 今天主要是想測量沿河堤公園騎到博愛二路與三路兩端來回路程與時間. 路線圖如下 :


我從明誠路出發經大順路到博愛二路的愛河之心折返, 再騎回明誠路往前過新莊仔路, 自由路, 再到博愛三路折返明誠路, 這樣總計是 7.38 公里, 耗時約 40 分鐘 :


這樣單程應該是 3.6 公里. 每周都要這樣鍛鍊 1~2 次, 加上慢跑與游泳, 希望在冬季結束前完成南迴段, 可能的話也把 20 多年前停下來的彰化~嘉義段, 嘉義~高雄段補齊, 這樣就只剩下花東段了.

2016年11月25日 星期五

下載備份 Google App Engine 應用程式檔案的新方式

之前我在 Hostinger 上申請的免費網站由於進行了大量運算被認為濫用免費資源而遭到停權 (我哪知道免費用戶的 CPU 使用量是多少啊), 結果促使我在前天向 Hostinger 購買了 Premium 虛擬主機服務. 但是我發現原先的免費帳號還是不斷地被之前設定的 GAE cron jobs 進行 query, 因此在寫信向 Hostinger 解釋之前必須先停止 GAE 上的 cron jobs 才行.

我參考了之前的文章去下載 GAE 應用程式以便檢查看看到底是哪一個應用程式在 trigger 我的 Hostinger 免費主機, 因為太久忘記了, 所以就從最接近的 appfog-twstockbot 開始查起 :

# 下載備份 Google App Engine 應用程式檔案的方法

但是照原先的方法下載卻發現不像以前那樣會在 DOS 命令列中直接詢問 Google 帳號密碼, 而是顯示如下訊息 :

Microsoft Windows [版本 10.0.14393]
(c) 2016 Microsoft Corporation. 著作權所有,並保留一切權利。

E:\>appcfg.py download_app -A appfog-twstockbot -V 1 E:\gae\appfog-twstockbot
09:35 PM Host: appengine.google.com
09:35 PM Fetching file list...
Your browser has been opened to visit:

    https://accounts.google.com/o/oauth2/auth?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fappengine.admin+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2F&response_type=code&client_id=550516889913.apps.googleusercontent.com&access_type=offline

If your browser is on a different machine then exit and re-run this
application with the command-line parameter

  --noauth_local_webserver

這時 DOS 就僵在那邊無法動彈 (其實就是在等待我們使用瀏覽器進行 Google 帳號認證), 同時冒出一個視窗詢問要用哪一個瀏覽器認證, 選好後就會開啟瀏覽器連線到 Google 進行認證, 我的 Google 帳號採用兩階段認證, 因此必須用登記的手機接收認證碼, 驗證成功後會顯示要求授權存取 GAE 與 Google Cloud 頁面 :


按允許後結束認證, DOS 畫面即回應開始下載 :

Authentication successful. (認證通過)
09:36 PM Fetching files...
09:36 PM [1/10] main.py (這個檔案就是我要檢查的 cron table 觸發對象)
09:36 PM [2/10] extjs.htm
09:36 PM [3/10] jquery.htm
09:36 PM [4/10] index.yaml
09:36 PM [5/10] static/dataTables.zh-tw.txt
09:36 PM [6/10] html5.htm
09:36 PM [7/10] app.yaml
09:36 PM [8/10] cron.yaml (這是 cron table)
09:36 PM [9/10] default.htm
09:36 PM [10/10] favicon.ico

打開 main.py (此為 MTV 架構中的 View, 或 MCV 架構中的 Controller, 負責 routing) 檢查, 果然就是去觸發我在 Hostinger 申請的免費的 16mb.com 網址, 抓到了. 以前如果佈署完應用程式就馬上做紀錄的話, 現在也不會這麼費事去調查.

接著檢查其中的 cron.yaml, 其內容就是 cron table :

cron:
- description: fetch_twse_daily_close
  url: /fetch_twse_daily_close
  schedule: every day 16:00
  timezone: Asia/Taipei
- description: fetch_twse_daily_institutes
  url: /fetch_twse_daily_institutes
  schedule: every day 16:02
  timezone: Asia/Taipei
- description: technical_analysis
  url: /technical_analysis
  schedule: every day 16:04
  timezone: Asia/Taipei
- description: create_daily_report
  url: /create_daily_report
  schedule: every day 16:08
  timezone: Asia/Taipei
- description: fetch_daily_report
  url: /fetch_daily_report
  schedule: every day 16:10
  timezone: Asia/Taipei
- description: fetch_twse_daily_debit
  url: /fetch_twse_daily_debit
  schedule: every day 21:00
  timezone: Asia/Taipei
- description: fetch_2330_tw_basic
  url: /fetch_2330_tw_basic
  schedule: every 11 minutes
  timezone: Asia/Taipei
- description: fetch_2330_tw_dividend
  url: /fetch_2330_tw_dividend
  schedule: every 22 minutes
  timezone: Asia/Taipei
- description: fetch_2330_tw_analysis
  url: /fetch_2330_tw_analysis
  schedule: every 12 minutes
  timezone: Asia/Taipei
- description: fetch_2330_tw_balance
  url: /fetch_2330_tw_balance
  schedule: every 13 minutes
  timezone: Asia/Taipei
- description: fetch_2330_tw_cash
  url: /fetch_2330_tw_cash
  schedule: every 14 minutes
  timezone: Asia/Taipei
- description: fetch_2330_tw_income
  url: /fetch_2330_tw_income
  schedule: every 15 minutes
  timezone: Asia/Taipei
- description: fetch_2330_tw_profit
  url: /fetch_2330_tw_profit
  schedule: every 16 minutes
  timezone: Asia/Taipei
- description: fetch_2330_tw_owner
  url: /fetch_2330_tw_owner
  schedule: every 21 minutes
  timezone: Asia/Taipei
- description: fetch_yahoo_company
  url: /fetch_yahoo_company
  schedule: every 60 minutes
  timezone: Asia/Taipei
- description: fetch_yahoo_dealing
  url: /fetch_yahoo_dealing
  schedule: every 9 minutes
  timezone: Asia/Taipei
- description: fetch_yahoo_credit
  url: /fetch_yahoo_credit
  schedule: every 10 minutes
  timezone: Asia/Taipei
- description: fetch_yahoo_major
  url: /fetch_yahoo_major
  schedule: every 10 minutes
  timezone: Asia/Taipei
- description: fetch_yahoo_earning
  url: /fetch_yahoo_earning
  schedule: every 20 minutes
  timezone: Asia/Taipei

把第二行以下全部刪除, 只留第一行的 cron: 然後更新 cron table 即可終止 cron jobs 了. 參考 :

停止 GAE 的 cron jobs 的方法

接下來下達更新 cron 的指令 :

E:\>cd gae

E:\GAE>appcfg.py update_cron appfog-twstockbot
11:14 PM Host: appengine.google.com
11:14 PM Uploading cron entries.

E:\GAE>

註 : 加上 --oauth2 透過瀏覽器認證 (新版的 GAE SDK 已預設不須加, 較舊的則需要)

E:\GAE>appcfg.py --oauth2 update_cron appfog-twstockbot


注意, 不論是下載/上傳應用程式, 或者更新 cron 必須在應用程式 (此處為 appfog-twstockbot) 的上一層目錄 (此處為 GAE) 下執行, 參考 :

# GAE 的 Cron Job

所以上面下載應用程式應該在 E:\GAE 下比較一致 :

E:\cd GAE
E:\GAE>appcfg.py download_app -A appfog-twstockbot -V 1 appfog-twstockbot

最後補充一點, 如果不要用瀏覽器認證, 要像以前那樣直接在 DOS 輸入帳號密碼, 只要加上一些參數即可 :

appcfg.py download_app -A appfog-twstockbot -V 1 E:\gae\appfog-twstockbot --noauth_local_webserver

不過因為我的 Google 已經採用兩階段認證, 因此不能輸入 Google 密碼, 而是要輸入機器認證專用密碼, 我覺得還是用目前以瀏覽器進行認證較方便.

2016-12-26 補充 :

昨晚停掉 GAE 上的 appfog-twstockbot 應用的 cron 後, 果然就靜下來了 :


這樣就可以寫信給 Hostinger 說我的 16mb.com 免費主機只是做實驗用途, 不會再進行大量運算了, 希望他們可以恢復運作. 其實既然已經購買了 Premium 服務, 我是不需要這個免費主機, 但看到帳號底下有個 abuse 字樣總是不舒服, 而且無效的 cron 不斷運作也是耗損能源, 一切無效的動作都必須停止.

# https://cloud.google.com/appengine/docs/python/download

2016-11-27 補充 :

今天在鄉下老家電腦上用較舊版的 GAE SDK 照上面程序下載, 發現它還是跟以前一樣在 DOS 中詢問 Email 與密碼, 因為我的 Google 帳號已申請兩階段認證, 所以這密碼可不是 Google 帳號的密碼, 而是在 Google 帳號設定中授權 GAE 存取的另一組密碼, 我之前有特別記下來, 但是輸入後卻無法通過認證, 真是傷腦筋, 還要回去找之前所寫的紀錄, 很浪費時間. 我直接在 Google 搜尋, 馬上就找到結果了, 參考這篇 :

# 使用Google App Engine上傳程式, 一直要求輸入帳號密碼, 如何解決?

原來只要加上 --oauth2 就會透過瀏覽器進行 Google 帳號認證了, 例如 :

appcfg.py --oauth2 download_app -A appfog-twstockbot -V 1 E:\GAE\appfog-twstockbot



辦公室的新電腦

周一來了一批新電腦, 我辦公室的那台也在汰換之列. Something new is always good, but~~ 一堆資安要求與軟體重安裝很麻煩. 由於我 D 碟累積了一大堆工作資料, 周一下班前負責幫我調校系統的年輕人說資料搬移至少需要兩小時, 只好丟在那邊讓它跑. 受訓兩天回來才著手安裝軟體, 昨天花了半天才能開始用.

今天開始安裝軟體, Java 還是用 JDK7, 因為之前寫的程式都在此環境跑, 而且我不認為我會用到 Java 8 的那些奇怪的新功能, 也不打算在 Java 上花額外的心力, 我大概只要用 Java 來擷取與分析營運資料即可. 去上兩天 Pyhton 進階班課成後, 我決定專注在 Python 的學習.

安裝完 JDK 7 後要到 "控制台/系統" 下設定環境變數 :

JAVA_HOME=C:\Program Files (x86)\Java\jdk1.7.0_79
PATH= ~ ;%JAVA_HOME%\bin;

這樣在任何目錄下便能順利執行 Java 程式了.


好書 : 系統程式

這本書是從鄉下的市圖分館借來的, 此書寫得極好, 以作者設計的一個簡易 32 位元處理器 CPU0 為對象來說明如何實作其組譯器, 編譯器, 作業系統等系統程式. 看了前面一點便沒有時間看, 還是先歸還, 等以後有空再借, 這裡做個紀錄以便後續追蹤.

# 系統程式 System Software (旗標, 陳鍾誠)


作者陳鍾誠係金門大學教授, 涉獵廣泛著作頗豐, 參考 :

http://ccckmit.wikidot.com


2016年11月24日 星期四

如何取消手機未應答轉接

二哥前陣子問我說他的手機會接到打給我的電話, 我以為是之前在 3G 時代申請的雙號同振沒取消掉, 今天打電話問中華行動客服是否可取消, 結果竟然我沒有申請同振, 客服認為可能是我手機有設定未應答轉接之故, 可以在撥號盤輸入下列號碼後按撥號 :

##002#

按完後再試真的就不會有這現象了, 證實是未應答轉接. 如果要設定未應答轉接到某個號碼例如 0933000000 (假設號碼), 則要輸入如下號碼 :

**61*0933000000#

注意, 藍色部分要換成你要轉去的號碼.


購買 Hostinger Premium 虛擬主機服務

昨晚寫完 Python 學習筆記正想關機睡覺, 突然想到上周評估虛擬主機時有打算以每月 1.99 歐元租用英國 Hostinger 的 Premium 主機, 現在是否還有這個價格? 結果連線過去發現竟然有更好的折扣優惠, 租三年只要 27 歐元, 並贈送 .xyz 域名一年 !



點進去看發現只有租三年才有最高 15 折, 每月 0.75 歐元優惠, 租四年可沒這麼好哩 !


於是我當機立斷, 擇期不如撞期, 就給他下單了 :


可知 Hostinger 雖是 UK 公司, 但卻在塞普路斯註冊. 右上角還註明必須 11/23 日結束前付款, 我下單時雖已過 12 點為 11 月 24 日, 但在塞普路斯還是 11/23. 我使用信用卡付款後馬上收到銀行簡訊通知信用卡消費約 1027 元, 推算匯率是 1027/27=38 元, 哇咧, 比今天台銀收盤價 34 元高出 4 元, 這是手續費嗎? 這個價格以我上周我評估時四年 3333 元來算, 換成三年是 3333*3/4=2500, 則1027 相當於是上周的 41 折 : 1027/2500=0.41.

付款後網頁出現兩項訂單需要設定, 一是虛擬主機, 一是免費一年的域名 :


主機設定主要是輸入域名, 密碼, 以及選擇主機位置, 我選北美 :


而域名設定部分則是輸入姓名住址與電話而已 :


以現有 Hostinger 帳號登入系統後果然出現了這個新的主機, 租期三年到 2019-11-23 :


如果不是這麼湊巧, 我還不知道要猶豫多久才會下決定哩! 

2016-11-24 補充 :

早上登入 Hostinger 時出現下列告示 :

"Your domain is not pointing to our nameservers at the moment, so services such as FTP, File Manager, E-mail (and others) will not work correctly. You can find our nameservers at the "Accounts -> Details" section. Please mind that DNS might take up to 24 hours to propagate when the change is submitted."

好像是說我申請的一年免費 .xyz 域名尚未指到 Hostinger 的域名伺服器, 這要在哪裡指定呢? 還是說因為要 24 小時才會綁定, 所以這只是通知而已? 我已寫信詢問客服了解 (線上客服時間是英國當地 03:00~22:00, 相當於台灣時間 11:00~24:00). Hostinger 的域名伺服器如下 :


Business 主機也有打折優惠 (同樣租三年 15 折), 但我比較了 Premium 與 Business 的差別, 發現兩者只有資料庫備份週期與是否提供 SSL 這兩項不同而已 :


這兩項對我而言並非很重要, 而兩者價格卻差兩倍, 所以我覺得還是 Premium 價划算.

2016-11-24 晚上補充 :

晚上吃過飯後收信發現 Hostinger 通知我的一年免費域名已經開通, 實際連線果然顯示預設內容了, 可見域名啟用大約要花將近一天. 另外登入系統後在管理網頁右下角會顯示線上諮詢按鈕 :


按此按鈕會出現線上對談框, 可以向客服人員提出疑問. 我今天主要是問, 我的免費 .xyz 域名明年到期後若不續用, 可否切換為 Hostinger 提供的免費域名 (例如 16mb.com 的) ?


答案是可以的, 但不是在哪裡設定切換, 而是要按 Home/Hosting 底下的 New Hosting Account 鈕新增一個帳戶, 然後建立一個免費域名來連結虛擬主機即可.

2016-11-25 補充 :

我第一次申請 Hostinger 帳號是在 2016-2-16 日, 所寄 Email 資訊如下 :

Nameserver 1: ns1.hostinger.co.uk 31.170.163.241
Nameserver 2: ns2.hostinger.co.uk 31.220.23.1
Nameserver 3: ns3.hostinger.co.uk 173.192.183.247
Nameserver 4: ns4.hostinger.co.uk 31.170.164.249

Uploading Your Website

You may use one of the addresses given below manage your web site:

Temporary FTP Hostname: 31.220.16.247
Full FTP Hostname: ftp.yourAccount
FTP Username: uxxxxxxxxx
FTP Password: yyyyyyy

You must upload files to the public_html folder!

Email Settings

For email accounts that you setup, you should use the following connection details in your email program:

POP3 Host Address: mx1.hostinger.co.uk
Username: The email address you are checking email for
Password: As specified when setting up the email account

Thank you for choosing us.

Hostinger United Kingdom
http://www.hostinger.co.uk

那時為了 Hostinger 不再支援 mysql 函式庫, 我還特別為此將 mysql.php 改為 mysqli.php, 參考 :

EasyuiCMS 改版為 v2 (mysqli)


2016-12-05 補充 :

這幾天測試 PHP 專案, 發現有時候會出現如下結果 :

Resource Limit Exceeded

The website is temporarily unable to service your request as it exceeded resource limit. Please try again later.

我想這可能是 Premium 只保證 99.9% 穩定度的關係吧.

2016年11月23日 星期三

Python 學習筆記 : 安裝執行環境與 IDLE 基本操作

這兩天被派去受 "Python 進階班" 的訓, 有一段時間沒接觸 Python 了, 趁這個機會溫習一下也好. 老師使用的是 Python 3, 而我以前在 GAE 用的是 Pyhton 2, 但其實差異沒有很多啦. 以下就這兩天的 Python 3 學習做個摘要整理.

Python 是一種跨平台的指令碼語言 (Scripting language), 乃 Python 之父 Guido van Rossum 為了發展 Amoeba 分散式處理作業系統, 於 1989 年以其先前發展之 ABC 教學語言為基礎, 揉合了 modula-3, UNIX shell, Icon, SmallTalk 與 C 語言的風格於荷蘭阿姆斯特丹大學發展而成. Python 語言的基本哲學是 : 做事時應該只有一種明確的方式, 這使得 Python 程式較簡潔易學.

Python 虛擬機器可在多種 OS 上運作, 但最先是在 Mac 機器上實作的. Python 的圖騰是一隻蟒蛇, 但其名稱的由來卻與蟒蛇一點關係也沒有, 而是源自英國 BBC 著名的喜劇影集 "Monty Python’s Flying Circus" 來的. 而其整合開發環境叫做 IDLE 而非 IDE 的原因是 Monty Python 開發小組的一個成員名為 Eric Idle 的緣故.

Python 在 2000-10-16 發布了 Python 2.0, 支援垃圾回收與 Unicode, 此版本是 Python 大受歡迎的開始. 2008-12-03 又發布了 Python 3.0, 但與舊版本不完全相容 (not backward-compatible), 這在程式語言演進上較為罕見. 關於 Python 2 與 Python 3 的差異可參考這篇 :

# Python 2.x 或 3.x?

Python 語言的特色整理如下 :
  1. Python 是物件導向的直譯式語言 (Interpreter language), 與 Java/C++ 等編譯語言比起來, 省掉了編譯與連結步驟, 簡化了開發流程, 但事實上是把中介碼 byte code 的編譯動作隱藏起來了.
  2. Python 與 Javascript, PHP 等語言一樣均屬於腳本語言 (Scripting language), 其與系統語言 (C/C++) 之差異是 : 系統語言目標是節省系統資源, 提高執行效能 (資訊家電需求), 而腳本語言之目標是節省程式員時間, 提高開發速度 (應用程式需求).
  3. Python 是動態語言 (Dynamic language), 在執行時期才確定資料型別, 這與 Javascript, VBscript, Ruby 等語言是相同的.
  4. Python 是強型別語言 (Strong-typed language), 資料型別須透過顯式型別轉換才能混合運算, 如同 Java.
  5. Python 不是格式自由語言, 採用強制縮排定義程式區塊, 以換行表示敘述結束. 縮排是語法的一部分, 違反縮排規則將無法執行.
  6. Python 是跨平台語言, 早期本身是用 ANSI C 語言撰寫的, 可以在 Unix/Linux/DOS/Windows/Macintosh 等作業系統上執行. Python 程式執行時會編譯成 pycode 中介碼, 與 Java 的 bytecode 類似.
  7. Python 是開放源碼 (Open source) 的.
  8. Python 內建比 Java/C/C++ 還豐富的資料型別, 從而有效地減少程式碼長度.
  9. Python 內建複數型別, 支援複數運算.
  10. Python 是完全物件導向的語言, 不論資料, 字串, 函式, 模組全部都是物件. 完全支援多重繼承, 多型, 過載, 衍生, 與泛型, 使程式碼可重複使用. 同時也有例外處理機制, 具備垃圾回收功能, 自動管理記憶體之使用. 
  11. 利用 py2exe, pypy, pyinstaller 可將 Python 原始碼轉成脫離編譯器執行環境的獨立執行程式.
  12. Pyhton 的設計哲學 : 優雅, 明確, 簡單. 希望 "用一種方法, 最好是只有一種方法來做一件事", 而非像 Perl 那樣 "有多種方法來做同一件事", 盡量避免歧義, 因此 Python 原始碼具有高度的可讀性.
  13. Python 雖然被歸類為 "指令碼/描述語言 (Scripting language)", 但其功能遠比 Shell script, Javascript, VBscript 等僅能處理簡單工作之指令碼語言強大, Python 開發者稱其為一種 "高階動態語言".
  14. Python 也被稱為 Glue language (膠合語言), 能夠將其他語言編寫的程式進行整合與封裝.
  15. 大多數 Linux 發行版本都已整合了 Python, 可以在終端機下直接執行 Python.
  16. Python 語言的架構是可延伸的, 並非所有的功能與特性都整合到核心, 而是歸類於其強大的標準函式庫中, 從而避免像 VBscript 那樣臃腫. Python 輕巧的語言核心只包括數字, 字串, 串列, 字典, 檔案等資料型別與函式, 其他額外功能如系統管理, 網路通訊, 文字處理, 資料庫, 圖形介面, XML 等全部由標準函式庫提供. 另外社群還提供豐富的套件, 如 Web 開發, 科學計算等等.
  17. Python 標準函式庫包含多個作業系統功能呼叫函式庫, 透過 pywin32 套件可以存取 Windows API 與 COM 服務; 而透過 IronPython 則可直接呼叫 .Net Framework.
  18. 以 Python 編寫系統管理指令在可讀性, 效能, 重覆使用, 擴充性方面都優於 shell 指令.
  19. Python 已有的實作 : CPython (C), JPython (Java), PyPy (Python), IronPyhon (.Net).
以上都是關於 Python 的背景知識, 現在 Python 越來越受歡迎, 不僅在科學計算領域被廣泛使用, 許多大學如 MIT 與柏克萊等校之資訊科學系也改用 Python 作為學生必修語言, 目前 Python 在 TIOBE 排行已經穩定在前五名 :


自 Python 1.0 於 1994 年問世以來, 過去 22 年來 Pyhton 的排名從 26 名穩定上升到目前的第五名, 其受歡迎的程度可見一斑 :


此外在嵌入式系統應用中, Python 也是樹莓派 Raspberry Pi 的預設作業系統 Raspbian 的內建程式語言, 樹莓派也因為 Python 龐大的第三方套件而展現驚人的功能, 廣泛應用在無人機, 機器人, 影像辨識, 自然語言處理等領域. Python 的厲害在於其豐富的第三方套件, 在 PyPi 網站上已登錄超過 9 萬個套件, 各種應用應有盡有, 參考 :

https://pypi.python.org/pypi

學習 Python 要先安裝其執行環境, 首先到官網下載 Python :

https://www.python.org/downloads/

目前最新版是 3.5.2, 如果是用在 GAE 的話要下載 2.7 版, 因為 GAE 尚未支援 Python 3.  Python 2.7 版也是 Python 2 的最後版本.

安裝 Python 時要注意更改安裝路徑以及勾選 "Add Python 3.5 to PATH" :


注意, 這裡要選 "Customerized installation", 這樣才能更改安裝路徑 :


這個只要按 Next 即可 :


這裡就是修改安裝路徑的地方, 將原先又臭又長的路徑改為 C:\Python35 即可. 這樣安裝完後在 DOS 視窗的任何目錄下打 Python 都能執行 Python 程式.



直接輸入 Python 指令馬上即輸出結果. 例如 :

>>> 2+3
5
>>> print(2+3)
5

如果要跳出 Python 直譯器, 可輸入 exit() 或 quit() 或按 Ctrl+C 即回到 DOS 命令列.

此外也可以使用 Python 內建的 IDLE 交談式介面來執行 Python 程式, 其功能比由 DOS 進入 Python 執意環境要多, 例如可以編輯 Python 程式後點選 Run Module 來執行檔案.

當下了一些指令後, IDLE 視窗就會塞滿指令與回應, 能不能像在 DOS 一樣下個 CLS 指令就清除畫面呢? 很遺憾的是 IDLE 並沒有這樣的單一指令. 不過可以照下列文章介紹的方法為 IDLE 添加清除畫面快捷鍵 :

IDLE如何清屏?

先下載 ClearWindow.py 程式, 將其放在 Python 3 安裝目錄的 C:\Python35\Lib\idlelib 下, 然後用記事本編輯此目錄下的 config-extensions.def 檔, 將下列指令複製到檔尾後存檔, 將 IDLE 重開即可在 Option 下看到新增的 "Clear Shell Window" 功能選項了, 按此可清除畫面 :



這次受訓從老師那邊發現一本 Python 好書 :

Python 程式設計 : 從初學到活用 Python 開發技巧的 16 堂課 (何敏煌, 博碩)

Source : 天瓏

今天晚上就跑去明儀買回來, 打算好好研讀一番.

參考 :

Python 2.x或3.x?
Python Tutorial 第二堂(1)數值與字串型態

Python 3 與 Python 2 主要的差異如下 :

1. Input 輸入 :

在 Python 2 時可以使用 raw_input() 函數與 input() 函數讀取標準輸入, input() 事實上是透過 raw_input() 實作的, 兩者的傳回值型態不同, raw_input() 傳回值一律是字串, 且字串輸入時不用加引號, 例如 :

>>> raw_input("Name:")
Name:tony     (字串不須加引號)
'tony'
>>> raw_input("Age:")
Age:50
'50'                 (傳回字串)

可見 raw_input() 輸入時都不用加引號. 而 input() 則字串須加引號 :

>>> input("Name:")
Name:tony    (字串須加引號)

Traceback (most recent call last):
  File "    input("Name:")
  File "NameError: name 'tony' is not defined
>>> input("Name:")
Name:"tony"   (字串須加引號)
'tony'
>>> input("Name:")
Name:"tony"
'tony'
>>> input("Age:")
Age:50   (數字不須加引號)
50

可見 input() 只有數字不須加引號.

不過在 Python 3.2.3 版後已經不能用 raw_input() 了, 只能使用 input().

參考 :

# python 研究-raw_input 和 input 差異比較

2. Print 輸出 :

在 Python 2 時 print 是一個敘述 (指令), 列入關鍵字裡面, 使用方式如下 :

print "Hello World"

但是到了 Python 3 時 print 變成函數, 輸出資訊必須放在小括號內 :

print ("Hello World")

3. 中文支援 :

Python 2 雖然也支援中文, 但必須在第一行指定 UTF-8 字元編碼 :

# -*- coding:UTF-8 -*-

同時 .py 檔存檔時必須另存為 UTF-8 編碼格式.

但是在 Python 3 已經全面支援中文了 (預設使用 UTF-8 編碼), 連變數名稱也可以使用中文, 例如 :

>>> 哈囉世界="Hello World"
>>> 哈囉世界
'Hello World'

第一行不用再加 encoding 註記, 但仍要存成 UTF-8 格式.


另外, Python 支援大整數也是一個亮點, 在 C/Java 等語言裡, 整數 int 使用 4 個 bytes 儲存, 資料範圍 -2147483648~2147483647, 超出此範圍即發生溢位錯誤而無法儲存. 在 Python 無此問題, 再大的整數都可以處理. 在 Python 2 版還有分整數 int 與長整數 long, 大整數可以在後面加個 L 標示為長整數. 而且 2.2 版後若發生溢位會自動轉換成長整數, 不會出現執行錯誤. 到 Python 3 之後已經沒有 long 這種資料類型, 整數就只有 int 這個類型, 這個 int 其實就是 2 版的 long, 亦即在 Python 3 裡全部都是長整數.

不過, Python 對大整數的支援無上限指的是直到機器的極限, 看 CPU 是 32/64 位元而定. 而浮點數也是有機器限制的, 32 位元電腦只能表示到小數點後 12 位; 64 位元則至 16 位,  例如 :

>>> 1.0/3.0     (64 位元機器)
0.3333333333333333

而科學表示法可以處理到 1.7e308, 到 1.8e308 就變成 inf (無限大) 了 :

>>> 1.8e308
inf
>>> 1.7e308
1.7e+308
>>>

2017-04-11 補充 :

Python 3 與 Python 2 到底有哪些不同? 參見 :

# https://docs.python.org/3/whatsnew/3.0.html