最新消息

[公告2014/05/30] 如有需要將部落格中,任何一篇文章的程式碼使用在商業用途,請與我聯繫。

[公告2015/04/26] Line版的 iInfo程式與投資應用 群組已上線想加入的朋友們,請先查看 "入群須知" 再與我聯繫 Line : aminwhite5168,加入請告知身分與回答 "入群須知" 的問題。

[公告2018/04/22] 台北 Python + Excel VBA 金融資訊爬蟲課程,課程如網頁內容 金融資訊爬蟲班:台北班 Python 金融資訊爬蟲、EXCEL VBA 金融資訊爬蟲

[公告2019/01/08] 請注意:我再次重申,部落格文章的程式碼,是要提供各位參考與學習,一旦網頁改版請自行修改,別要求東要求西要我主動修改,你們用我寫東西賺錢了、交差了,請問有分我一杯羹嗎?既然賺錢沒分我,請問有什麼理由要求我修改,如果沒能力改,就花錢來找我上課。

[公告2019/12/01] 若各位有 Excel VBA 案子開發需求,歡迎與我聯繫,可接案處理。

[公告2020/05/22] 頁面載入速度慢,起因為部分JS來源(alexgorbatchev.com)失效導致頁面載入變慢,目前已做調整,請多見諒。

2012年8月31日 星期五

資訊站台

國外網站
財經網
財經論壇
綜合型(技術面+基本面)---部落格
技術面---部落格
基本面---部落格
綜合型工具(基本面、技術面、籌碼面)
技術面工具
基本面工具
期貨選擇權
籌碼面工具
籌碼明細查詢
權證工具
其他資訊
財經單位

學習推薦

有投資課程
基本面書籍
  • 操盤人教你看財務報表     ISBN:9789867283245
  • 一次就懂:怪老子帶你看懂財報選好股     ISBN:9789867283412
  • 賺錢的邏輯你懂了!用大白話說的財務報表速讀術   ISBN:9789866316128
  • 財報的秘密—探索財報數字內涵,掌握公司價值變化   ISBN:9789866511158
  • 打敗外資賺大錢   ISBN:9789867615053(絕版書)
  • 聰明買台股   ISBN:9789868346529(絕版書)
技術面書籍
  • 技術分析不設防:化繁為簡   ISBN:9789866366017
Multicharts書籍
  • PowerLanguage程式交易語法大全   ISBN:9789866320156
  • multicharts快譯通   ISBN : 9789866320309
  • 分析師關鍵報告:期貨交易篇   , ISBN:9789866320408
  • 分析師關鍵報告2:張林忠教你程式交易   ISBN:9789866320743
  • 股市的科學煉金術:程式交易全圖解   ISBN:9789867283528
Python教學
Python參考書籍
  • Python 入門   ISBN:9578247354 (絕版書)
  • Python Web開發學習實錄   ISBN:9787302266334 (簡體書)
  • Python 程式設計入門 (適用於 2.x 與 3.x 版)    ISBN:9789864340057 (適合入門)
  • 金融科技實戰:Python與量化投資    ISBN:9864342703 (適合入門)
  • Python 入門邁向高手之路王者歸來    ISBN:9865000598 (適合入門)
Excel VBA線上教學
Excel VBA參考書籍
  • 超圖解Excel VBA 基礎講座   ISBN:9789574423439 (適合入門)
  • 超圖解Excel VBA 應用講座   ISBN:9789574423996 (適合入門)
  • 跟我學Excel VBA   ISBN:9789862760352(適合入門)
  • 跟我學Excel VBA:將複雜的操作用一個按鍵就搞定!(適用2016/2013/2010/2007)   ISBN:9789862769843 (適合入門)
  • Excel VBA 巨集的職場效率術:無痛學習 VBA程式×步驟式教學錄製巨集×200個範例立即套用  ISBN:9789864342839(適合入門)
  • Excel VBA基礎必修課-增量版(適用Excel 2016/2013/2010)   ISBN:9789864763948(適合入門) 
  • Excel VBA與巨集程式設計:新手入門就靠這一本   ISBN:9789862016909 (適合進階)
  • Excel VBA一點都不難:一鍵搞定所有報表   ISBN:9789862017562  (適合進階)
  • Excel VBA徹底研究   ISBN:9789575277239 (絕版書、適合進階)
  • Excel與外部資料無縫整合:使用Excel VBA與SQL建置小型系統與資料分析,快速提昇辦公效率200問   ISBN:9789862015889
  • 詳解Excel+Access的資料庫整合應用實務   ISBN:9789862012376
  • Excel 2003 Power Programming with VBA
Excel VBA討論區
JavaScript
其他
線上虛擬交易

關於 Amin 作者與網站

Resume

個人背景

大學念電機系以C語言寫程式,碩士論文題目與生物資訊相關「DNA蛋白質摺疊結構預測」,以C++、Perl、Shell作為研究的使用語言,畢業後在工作上則以C/C++為主要語言,開發MFC Windows視窗,平時自己喜歡使用程式輔助在數據方面的分析與應用,主要語言以Python與Excel VBA為主。
在2012年建立個人網站《iInfo資訊交流》,主要分享網路爬蟲、C/C++、C#、Excel VBA、Python、Google Apps Script、Batch軟體整合應用等相關技術內容為主,歡迎各領域朋友相互交流。

個人網站與粉絲專頁
學歷
  • 台大生物產業機電工程所碩士 (2006~2008),網頁連結
  • 龍華電機工程學系 (1999~2005),網頁連結
  • 大安高工冷凍空調科 (1996~1998),網頁連結
經歷
  • 凱衛資訊資深軟體工程師(2015/10 ~ 迄今)
  • 1. 以C/C++開發與維護 Server/Client 軟體。
    2. 以C#、Python開發部分工具程式。
    3. Excel 與 MultiCharts 整合應用講師。

  • 仁寶電腦高級軟體工程師(2008/10 ~ 2015/09)
  • 1. 工廠產線測試軟體與硬體的維護與開發。
    2. 協助廠商開發ODM/OEM 測試軟體。
    3. 以C/C++為主,開發Console與GUI軟體,在Winpe、Windows、UEFI上運作。

  • 台北碩士文化教育事業業務專員(2003/09 ~ 2008/07)
  • 1. 幫助大學生規劃研究所考試的課程內容與分析各類研究所出路。
    2. 到各大專院校校園做行銷企劃與招生業務。
證照
  • 電腦軟體應用乙級技術士 (2006年 行政院勞工委員會發)
  • 電腦硬體裝修乙級技術士 (2009年 行政院勞工委員會發)
  • 冷凍空調裝修丙級技術士 (1998年 行政院勞工委員會發)
個人著作
  • 大學專題 2003/06
  • 指導教授:黃德豐助理教授

    專題題目
    Windows 2000 Server叢集伺服器環境之建構

  • 大學參與國內期刊 2003/06
  • 指導教授:黃德豐助理教授

    期刊題目
    多級FIR樣本刪減濾波器近似參數選擇
    The optimal multistage multirate digital FIR parameter design
    該期刊名已改成龍華電機系研究生的論文名

  • 研究所論文 2008/08
  • 指導教授:陳倩瑜教授 (現從台大借調 台灣人工智慧實驗室 服務)

    論文題目
    使用ab initio結構預測方法建構蛋白質功能區結構模型之研究
    Constructing Structural Model of Protein Functional Domains using ab initio Structure Prediction
    連結:Https://hdl.handle.net/11296/29qskk

  • 電腦書籍 
  • 2019/04/01碁峰資訊出版《Excel VBA 實戰技巧|金融數據x網路爬蟲》
    連結:Http://books.gotop.com.tw/v_ACI031700 
    1. 本書榮獲 金石堂網路書店 2019年度百大暢銷書 第4名 連結連結
    2. 本書榮獲 博客來書店 2019年度百大度暢銷書 第19名 連結
    3. 本書榮獲 天瓏網路書店 2019年度百大度暢銷書 第46名 連結
專長 
  • C/C++、 Excel VBA、VBScript、Python、Google Apps Script、Batch、C#、MultiCharts
  • 網路資料爬蟲 (Excel VBA、VBScript、Python、Google Apps Script)

教學、演講、活動
【教學】
  • 2020/02~2020/05 行政院勞動部勞動力發展署「Python大數據金融股票期貨網路爬蟲資料分析實務班第01期127617」連結1連結2
  • 2019/12 T客邦「Python打造股票交易策略與LINE股市小秘書」連結
  • 2019/10 輔大經濟系「Python金融大數據爬蟲課」。
  • 2019/08~2019/10 行政院勞動部勞動力發展署「Python大數據金融股票期貨網路爬蟲資料分析實務班第01期124995」連結1連結2
  • 2019/07 iInfo 「Excel VBA 基礎語法班」連結
  • 2019/07 T客邦「Excel VBA 爬蟲實戰技巧,分析網站結構擷取資訊、運用VBA+爬蟲打造數據分析工具」連結
  • 2018/10 輔大經濟系「Python抓取金融數據」。
  • 2017/12 東吳巨資系「Excel VBA爬蟲」。
  • 2017/10 輔大經濟系「Python網頁爬蟲」。
  • 2017/08 連結、2017/10 連結、2018/03 連結 凱衛資訊「Excel與MultiCharts結合」。
【演講】
  • 2019/04 天瓏書局「Excel VBA 實戰技巧|金融數據x網路爬蟲」連結
  • 2019/04 高雄科技大學金資系「金融資訊專題講座」。
  • 2018/08 凱基期貨台北總公司「摩台OI與台指對應策略」。
  • 2018/04 群益期貨台北總公司「Python與台股盤後大數據應用」。
  • 2018/02 群益期貨台北總公司「Excel與DDE應用」。
  • 2016/Q2 凱衛資訊MultiCharts網聚講師。
【活動】
  • 2016/03  iInfo版聚主持人兼講師
個人作品

關於「iInfo 資訊交流」
「iInfo 資訊交流」前身為2008年成立的「iInfo 愛資訊」,主要提供大學生考研究所所需的考情資訊網站,在2012年轉變為程式整合應用網站,希望藉由以下的程式語言,能在網路上結交各位程式愛好者,一起在投資方面創造出更近一步的應用。
  • Python、Excel VBA、MySQL、C/C++、JavaScript、CSS、Batch、C#

2012年8月28日 星期二

使用xmpp操控Gtalk

下載安裝xmpppy-0.4.0.win32.exe : http://sourceforge.net/projects/xmpppy/files/xmpppy/0.4.0/
開起Python輸入以下程式碼,並修改所需的測試帳號即可開始操控Gtalk
#Python語言: python gtalk機器人
# coding: utf-8
# 這是根據xmpp封裝的Jabber聊天機器人類, 可以通過繼承,重載部分函數來自定義功能.
# Jabber ID(JID): 比如gamcat@gmail.com
import xmpp

class Bot:
    """ Jabber Bot Base Class """
    JID = ''
    PASSWORD = ''

    client = None   

    def __init__ (self, jid, password):
        self.JID = xmpp.JID(jid)
        self.PASSWORD = password

        self.login()

    def login (self):         
        self.client = xmpp.Client(self.JID.getDomain(), debug=[])
        if self.client.connect() == '':
            raise 'JabberBot not connected.'
        if self.client.auth(self.JID.getNode(), self.PASSWORD) == None:
            raise 'JabberBot authentication failed.'
        
        self.client.RegisterHandler('message', self.message_callback)
        self.client.RegisterHandler('presence', self.presence_callback)
        self.client.sendInitPresence()

    def message_callback (self, client, message):
        """ 默認消息回調(可通過繼承自定義) """

    def presence_callback (self, client, message):
        """ 默認事件回調,包括下面幾個(可通過繼承自定義) """
        type = message.getType()
        who = message.getFrom().getStripped()

        if type == 'subscribe':
            self.subscribe(who)
        elif type == 'unsubscribe':
            self.unsubscribe(who)
        elif type == 'subscribed':
            self.subscribed(who)
        elif type == 'unsubscribed':
            self.unsubscribed(who)
        elif type == 'available' or type == None:
            self.available(message)
        elif type == 'unavailable':
            self.unavailable(who)

    def subscribe (self, jid):
        """ 加好友 """
        self.client.send(xmpp.Presence(to=jid, typ='subscribed'))
        self.client.send(xmpp.Presence(to=jid, typ='subscribe'))

    def unsubscribe (self, jid):
        """ 取消好友 """
        self.client.send(xmpp.Presence(to=jid, typ='unsubscribe'))
        self.client.send(xmpp.Presence(to=jid, typ='unsubscribed'))

    def subscribed (self, jid):
        """ 已加 """

    def unsubscribed (self, jid):
        """ 已退 """
        
    def available (self, message):
        """ 上線 """

    def unavailable (self, jid):
        """ 下線 """

    def send (self, jid, message):
        """ 發消息給某人"""
        self.client.send(xmpp.protocol.Message(jid, message))

    def step (self):
        """ 用在迴圈中 """
        try:
            self.client.Process(1)
        except KeyboardInterrupt:   # Ctrl+C停止
            return False
        return True

#===========================
# 測試
#===========================
class Bot(Bot):
    def message_callback (self, cl, msg):
        fromid = msg.getFrom().getStripped()
        cont = msg.getBody()
        self.send2admin(msg)

    def send2admin (self, message):
        self.send('admin@gmail.com', 'Test')

if __name__ == '__main__':
    gb = Bot ('yourbot@gmail.com', '******')
    gb.send2admin ('Bot Started')

    # 開始運行
    while (gb.step()): pass

程式碼來源 : Python Gtalk機器人

使用pyxmpp操控Gtalk


搭配以下Python程式碼,即可對Gtalk發送訊息
#!/usr/bin/python
# -*- coding: utf-8 -*-

from pyxmpp.jid import JID
from pyxmpp.message import Message
from pyxmpp.jabber.client import JabberClient
from pyxmpp.jabber.simple import send_message
from pyxmpp import streamtls

class Gtalk():
    def __init__(self, sid, spwd):
        self.sid = JID(sid)
        self.spwd = spwd

    def send_msg(self, rid,  msg):
        self.rid = JID(rid)
        if not self.sid.resource:
            self.sid = JID(self.sid.node, self.sid.domain, 'send_message')

        msg = Message(to_jid=self.rid, body=msg)
        def send(stream):
            stream.send(msg)

        self.xmpp_do(send)

    def xmpp_do(self, function):
        class Client(JabberClient):
            def session_started(self):
                function(self.stream)
                self.disconnect()

        tls = streamtls.TLSSettings(require=True, verify_peer=False)
        auth = ['sasl:PLAIN']
        gtalkClient = Client(self.sid, self.spwd, tls_settings=tls, auth_methods=auth)
        gtalkClient.connect()
        try:
            gtalkClient.loop(1)
        except KeyboardInterrupt:
            print u'disconnecting...'
            gtalkClient.disconnect()

if __name__ == '__main__':
    g = Gtalk('account@gmail.com', u'password')
    g.send_msg('to@gmail.com', 'Hello World')

程式碼來源 : 比較win32下python與java通過實現XMPP協定發送gtalk消息

2012年8月27日 星期一

在windows安裝pyxmpp,架設gtalk機器人

Google Talk是在geek中相當流行的一款IM用戶端,其採用了jabber的開放式協議xmpp,使得第三方開發非常方便。

jabber.py早已經被廢棄,不推薦
xmpppy是jabber.py的繼承者,使用方便簡單,有彩色debug輸出(如果你的shell支援彩色的話)
xmpppy適合羽量級的開發,不需要依賴其他python庫
pyxmpp是最符合XMPP和jabber協議的庫,作者本身就是Jabber標準組的成員之一
pyxmpp的安裝比xmpppy麻煩的多。需要libxml2、dnspython和M2Crypto,可惜不支持Win32

以下將介紹如何在windows下安裝pyxmpp環境

1. 下載安裝Python 2.7.3 : http://www.python.org/download/releases/2.7.3/
2. 下載安裝M2Crypto-0.20.2.win32-py2.7.exe : http://chandlerproject.org/Projects/MeTooCrypto#Downloads
3. 下載安裝dnspython-1.6.0.win32.exe : http://www.dnspython.org/kits/1.6.0/
4. 下載安裝libXML2 : http://xmlsoft.org/sources/win32/python/
5. 下載pyxmpp-1.1.2.tar.gz : https://github.com/Jajcus/pyxmpp/downloads/  (一定使用這裏這裡的安裝)
6. 將pyxmpp-1.1.2.tar.gz 解壓縮至C:\Python27\Lib中
7. 開啟命令提示字元,將操作目錄切換至C:\Python27\Lib\pyxmpp-1.1.2中 : "cd C:\Python27\Lib\pyxmpp-1.1.2"
8. 確認安裝pyxmpp所需的安裝資料庫與程式 : 輸入"configure.py" 執行
9. 建立pyxmpp安裝檔 : 輸入"python setup.py build" 執行
10. 開始安裝pyxmpp : 輸入"python setup.py install" 執行

2012年8月26日 星期日

Python與Excel連結的模組

在一次網路收尋資料中,發現了兩個可以透過python操作excel的簡單模組,分別是pyxll、openpyxl。代我先了解如何使用後,再將範例清楚的貼在文章上

2012年8月25日 星期六

Excel VBA使用正規化取得字串內容

一次的意外發現,原來VBA中也可以使用Regular Expression,以下使用個範例來幾單說明使用,後續再補充完整的內容
Option Explicit

Private Sub TestReg()
    Dim reg As Object
    Dim mc As Object
    Dim m As Object
    
    Set reg = CreateObject("vbscript.regExp")
    With reg
        .Global = True
        .IgnoreCase = True
        .Pattern = "\d+"
    End With

    Set mc = reg.Execute("123aaaaa987uiiui999")
    For Each m In mc
        MsgBox m.Value
    Next
End Sub

2012年8月23日 星期四

Excel VBA抓yahoo finance各項歷史成交資訊


歷史資料工作表中加入一個名為"下載"按鈕,如上圖中粉紅色按鈕,加入以下的程式碼
Option Explicit
Private Sub 歷史成交資訊_Click()
    Dim xlStockid As String, URL As String
    xlStockid = Range("B1")
    UsedRange.Offset(4).Clear
    URL = "http://ichart.finance.yahoo.com/table.csv?s=" & xlStockid & "&a=00&b=1&c=1998&d=" & Format(Month(Date) - 1, "00") & "&e=" & Day(Date) & "&f=" & Format(Year(Date), "0000") & "&g=d&ignore=.csv"
    
    With Workbooks.Open(URL)
        .Sheets(1).UsedRange.Offset(1).Copy [a5]
        .Close 0
    End With
End Sub

想要取得上市股票的歷史成交資訊,股票代碼請輸入".TW",如台泥 1101.TW
想要取得上櫃股票的歷史成交資訊,股票代碼 請輸入".TWO",如新普 6121.TWO
以上要注意有點"."的部份

各類指數名稱
對應代碼
美元兌台幣的歷史
USDTWD=x
台灣證交所

加權指數
^TWII
不含金融股
^TIWI
金融保險類
^TFNI
大陸

深圳綜合
^SZSC
深圳成份
^SZSC1
A股指數
^SZSA
A股成份
^SZSA1
B股指數
^SZSB
B股成份
^SZSB1
綜合指數
^SSEC
A股指數
^SSEA
B股指數
^SSEB
工業指數
^SSEI
商業指數
^SSEM
地產指數
^SSEP
公用事業
^SSEU
香港證交所

恆生指數
^HSI
金融指數
^HSNF
公用事業指數
^HSNU
地產指數
^HSNP
工商指數
^HSNC
中國企業指數
^HSCE
中資企業指數
^HSCC
亞太地區

中國 上海綜合指數
000001.SS
香港 恆生指數
^HSI
日本 Nikkei 225
^N225
新加坡 海峽時報指數
^STI
南韓 漢城綜合指數
^KS11
印度 BSE 30
^BSESN
印尼 雅加達指數
^JKSE
馬來西亞 KLSE Composite
^KLSE
澳洲 All Ordinaries
^AORD
菲律賓 PSE Composite
^PSI
斯里蘭卡 All Share
^CSE
歐洲

奧地利 ATX
^ATX
法國 CAC 40
^FCHI
德國
^GDAX
英國 FTSE 100
^FTSE
非洲/中東

埃及 CMA
^CCSI
以色列 TA-100
^TA100


2012年8月21日 星期二

Excel VBA抓取網頁數據的方法


目前在檯面上可以透過Excel VBA取的網頁數據的方法有以下5種,至於每項的說明與範例,後續再陸續補充說明

舉凡網站有提供CSV檔案下載服務,即可使用Workbook物件對遠端檔案進行檔案操作以達取得網頁數據存取。
如 Excel VBA抓yahoo finance各項歷史成交資訊

舉凡網站或資料庫的數據以表格或檔案形式提供,皆可使用WebQuery方法取得網頁列表數據。
Excel VBA抓取股票資料Excel VBA抓取上市交易明細Excel VBA抓取股票代碼Excel VBA抓每月營收Excel VBA抓特定股票合併營收Excel VBA抓取股票資料

舉凡網站需要藉由手動輸入或是點擊來達成進行網頁的操控,即可使用Internet Explorer物件控制DOM,使用這個方式需要熟悉網頁基本標籤。
Excel VBA抓取上市交易明細

Internet Explorer物件控制網頁下載資料。
如 Excel VBA 針對 js的資料網頁無法抓取的解法使用Internet Explorer object下載每日上櫃交易明細

舉凡抓取數據會需要用到編碼(如UTF8、BIG5)、網站內部參數傳遞(GetPOST)、檔案下載,皆可使用XmlHttp取得網頁表格數據。
Excel VBA抓元大寶來100Excel VBA抓取上櫃交易明細

Webbrowser操作網頁,尚在研究中

MSXML處理XML檔案,在Excel VBA中不適用

Excel VBA抓特定股票合併營收



2012年8月19日 星期日

Excel VBA抓元大寶來100網頁


近期處理一個想透過VBA抓取網頁表格數據的問題,http://www.p-shares.com/0051-4-1-1.asp 該網頁屬於元大寶來投信的網頁,網頁會亂碼的原因,可能受到網頁第8行word.css的影響,不過這還要再確認才知道。


當然各位可以將網頁的編碼設為UTF-8,即可見到正常的網頁資訊,不過這還不是最頭痛的問題,我在猜這個網頁撰寫人很喜歡用換行符號”\r\n”(就是DOS/Windows的換行0D0A),所以在表格數據每個欄位都加入換行符號,導致無法使用Trim函數,相對的這也考驗程式開發者的敏感度與對文件的熟析程度。


透過 Fiddler 工具抓出從網頁抓下來在Memory的中所呈現的16進制的數據,以下將網頁表格數據中的其中一個欄位節錄出來,如下紅色框框即是網頁資料的真實數據。


基於以上的分析再透過VBA的語法,即可取得亂碼資料的問題。

Option Explicit

Sub 寶來100()
    Dim oXMLHTTP As Object
    Dim objStream As Object
    Dim i As Integer, j As Integer, Rowstart As Integer
    Dim Webbadydata() As String, Webheader() As String, WebPageData As String
    Dim tmep As String
        
    '設定XMLHTTP與ADODB物件
    Set oXMLHTTP = CreateObject("Msxml2.XMLHTTP")
    Set objStream = CreateObject("ADODB.Stream")
    
    '使用UTF8,取得網頁資料
    With oXMLHTTP
        .Open "GET", "http://www.p-shares.com/0051-4-1-1.asp", False
        .setRequestHeader "Content-type", "application/x-www-form-urlencoded"
        .send
        If .Status = 200 Then               '網頁請求成功
            With objStream
                .Open
                .WriteText oXMLHTTP.ResponseBody
                .Position = 0               '從頭開始
                .Type = 2                   '以文字模式操作(adTypeText),用以text/ntext欄位保存純文本資料,另有二進位方式操作adTypeBinary
                .Charset = "Big5"          'UTF-8編碼(近期網頁有修改,請以Big5編碼)
                WebPageData = .ReadText     '取得主要資料欄位
                .Close
            End With
        Else
            MsgBox "無法取得資料"
        End If
        '釋放資源
        Set objStream = Nothing
    End With
    
    '釋放資源
    Set oXMLHTTP = Nothing

    MsgBox WebPageData
    Sheets("Sheet1").Select
    Webheader = Split(WebPageData, "<th class=""" & "word12" & """>") '取得header說明
    For i = 1 To UBound(Webheader)
        Cells(1, i) = Trim(Split(Mid(Webheader(i), 3, Len(Webheader(i))), "</th>")(0)) '先去除\r\n,再去除空白
    Next
    
    '對不需要資料先做刪除
    Webbadydata = Split(WebPageData, "<tr align=" & """center""" & " bgcolor=" & """#DDE4EE""" & " class=" & """word""" & ">") '去頭
    Webbadydata = Split(Webbadydata(1), "<tr align=" & """center""" & " bgcolor=" & """#E4DFFF""" & ">") '去尾
    Webbadydata = Split(Webbadydata(0), "<td>") '開始取值
    
    Rowstart = 2
    For i = 1 To UBound(Webbadydata) Step 3
        For j = 0 To 2
            tmep = Trim(Mid(Webbadydata(i + j), 3, Len(Webbadydata(i + j)))) '對0D0A進行刪除並去除空白
            Cells(Rowstart, j + 1) = Trim(StrReverse(Mid(StrReverse(Trim(Split(tmep, "</td>")(0))), 3, Len(StrReverse(Trim(Split(tmep, "</td>")(0))))))) '對0D0A進行刪除並去除空白
        Next
        Rowstart = Rowstart + 1
    Next
End Sub

2012年8月16日 星期四

美化部落格的程式碼 使用SyntaxHighlighter

你是否曾想過要在自己的部落格,將原始程式碼包裝有條有理,甚至可以根據不同程式語言的關鍵字進行上色,以提高程式碼的可讀性。

2012年8月15日 星期三

使用Visual Studio 2010建立 EDK application

編輯EFI code最常遇到幾點不方便像是沒有小番茄可用、沒有方便的操作介面,再加上全都是C code,這更是考驗你對程式語言的熟析程度。
在網路上找了好久,終於找到可以透過Visual Studio直接編譯EFI code的方法,以下就介紹如何透過Visual Studio的操作來編譯EFI application

Step1. 開新專案
        開啟Visual Studio 2010並點選 FileNewProject From Existing Code.

Step2. 指定專案類型Visual C++

Step3. 指定專案與程式碼來源
        (1)UDK2010資料夾存放路徑
        (2)指定專案名稱
        (3)加入需要使用附檔名
*.cpp;*.cxx;*.cc;*.c;*.inl;*.h;*.hpp;*.hxx;*.hm;*.inc;*.rc;*.resx;*.idl;*.rc2;*.def;*.odl;*.asm;*.asmx;*.xsd;*.bin;*.rgs;*.html;*.htm為預設附檔名,在此添加*.inf

Step4. 指定專案使用設定,選擇Use external build system選項

Step5. 設定偵錯組態
        (1)先建立一個批次檔UDK2010.bat並加入以下執行命令

call edksetup.bat
set EFI_SOURCE=%CD%\MyPkg

if not "%1"=="" goto ALL
build -a X64 -p MyPkg\MyPkg.dsc --log=build.log
goto end

:ALL
if not "%1"=="all" goto CLEAN
build %1 -p MyPkg\MyPkg.dsc --log=build.log
goto end

:CLEAN
if not "%1"=="clean" goto X86
build %1 -p MyPkg\MyPkg.dsc --log=build.log
echo %1
goto end

:X86
if not "%1"=="32" goto X64
build -a IA32 -p MyPkg\MyPkg.dsc --log=build.log
goto end

:X64
if not "%1"=="64" goto other
build -a X64 -p MyPkg\MyPkg.dsc --log=build.log
goto end

:other
echo ERROR ! Input variable
goto end

:end

        (2)在“Build command line”輸入“UDK2010.bat
        (3)在“Rebuild command line”輸入“UDK2010.bat 64(建立x64 EFI application)
        (4)在“Clean command line”輸入“UDK2010.bat clean

設定成功畫面


Step6. 建立UEFI application
點選BuildBuild Solution,成功建立時將出現以下紅色框框的訊息


2012年8月14日 星期二

Python抓集保資料

使用Python透過解析網頁元素來取得個股集保資訊

#!/usr/bin/python
# -*- coding: utf-8 -*-

#---------------------------------------------
#   抓個股集保資料
#   Version : 0.1
#   Author : Amin white
#   Release Date : 2012-01-01
#   Python version : 2.7.2
#---------------------------------------------

#引用函式庫
import urllib, csv, datetime, os, codecs, time
from datetime import date
from sgmllib import SGMLParser

def GetTdccinfo(stockid, stockname):
    startdate = ""
    enddate = ""

    #取得今天的日期
    today = datetime.datetime.today()
    year = today.strftime('%Y')
    month = today.strftime('%m')
    day = today.strftime('%d')

    #計算從1970到今天的總秒數
    todaysec = time.mktime(datetime.datetime(int(year), int(month), int(day)).timetuple())
    
    #指定儲存的路徑,可自行變更儲存路徑
    workdir = 'D:\\Stock_Concentration\\'

    #建立儲存資料夾
    if not os.path.isdir(workdir):
        os.makedirs(workdir)
    
    savefile = workdir + stockid + '.csv'

    print "寫入" + stockid + " " + stockname.encode('utf8') + " 集保資料到 " + savefile + " 開始..."
    
    #開始寫入檔案準備
    writefile = file(savefile, 'wb')

    #指定檔案以UTF8儲存
    writefile.write(codecs.BOM_UTF8)

    #指定CSV檔分隔的方式
    writer = csv.writer(writefile, delimiter=',', quotechar='"', quoting=csv.QUOTE_ALL)

    #寫入欄位說明,可自行變更儲存說明欄位
    writer.writerow([u'日期'.encode('utf8'), u'股票代號'.encode('utf8'), u'股票名稱'.encode('utf8'), \
                     u'1-999'.encode('utf8'), u'1-999'.encode('utf8'), u'1-999'.encode('utf8'), \
                     u'1,000-5,000'.encode('utf8'), u'1,000-5,000'.encode('utf8'), u'1,000-5,000'.encode('utf8'), \
                     u'5,001-10,000'.encode('utf8'), u'5,001-10,000'.encode('utf8'), u'5,001-10,000'.encode('utf8'), \
                     u'10,001-15,000'.encode('utf8'), u'10,001-15,000'.encode('utf8'), u'10,001-15,000'.encode('utf8'),\
                     u'15,001-20,000'.encode('utf8'), u'15,001-20,000'.encode('utf8'), u'15,001-20,000'.encode('utf8'), \
                     u'20,001-30,000'.encode('utf8'), u'20,001-30,000'.encode('utf8'), u'20,001-30,000'.encode('utf8'), \
                     u'30,001-40,000'.encode('utf8'), u'30,001-40,000'.encode('utf8'), u'30,001-40,000'.encode('utf8'),\
                     u'40,001-50,000'.encode('utf8'), u'40,001-50,000'.encode('utf8'), u'40,001-50,000'.encode('utf8'), \
                     u'50,001-100,000'.encode('utf8'), u'50,001-100,000'.encode('utf8'), u'50,001-100,000'.encode('utf8'), \
                     u'100,001-200,000'.encode('utf8'), u'100,001-200,000'.encode('utf8'), u'100,001-200,000'.encode('utf8'), \
                     u'200,001-400,000'.encode('utf8'), u'200,001-400,000'.encode('utf8'), u'200,001-400,000'.encode('utf8'), \
                     u'400,001-600,000'.encode('utf8'), u'400,001-600,000'.encode('utf8'), u'400,001-600,000'.encode('utf8'), \
                     u'600,001-800,000'.encode('utf8'), u'600,001-800,000'.encode('utf8'), u'600,001-800,000'.encode('utf8'), \
                     u'800,001-1,000,000'.encode('utf8'), u'800,001-1,000,000'.encode('utf8'), u'800,001-1,000,000'.encode('utf8'),\
                     u'1,000,001以上'.encode('utf8'), u'1,000,001以上'.encode('utf8'), u'1,000,001以上'.encode('utf8')])

    DataCount = 0
    for y in range(int(year) - 1, int(year) + 1):
        for m in range(1, 13):

            cell = []
            for d in range(1, 15):

                #排除2011年特殊的日子
                if y == 2011 and m == 5 and d == 2 and date(y, 5, 2).isoweekday() == 1:
                        continue;

                #計算要取得指定日期的秒數
                Revenuedaysec = time.mktime(datetime.datetime(y, m, d).timetuple())

                #判別指定日期是否有超過今天的日期
                if date(y, m, d).isoweekday() != 6 and date(y, m, d).isoweekday() != 7 and Revenuedaysec <= todaysec:

                    datestring = str(y) + str("%02d" % m) + str("%02d" % d)
                    
                    url = "http://www.tdcc.com.tw/smWeb/QryStock.jsp?SCA_DATE=" + datestring + "&SqlMethod=StockNo&StockNo=" + stockid + "&StockName=&sub=%ACd%B8%DF"
                    cell = TdccData(url)
                    if len(cell) == 0 :
                        break

                    #抓取第一筆集保日期
                    if startdate == "":
                        startdate = datestring
                        
                    #寫入集保資料,可自行變更儲存資料欄位
                    writer.writerow([datestring.encode('utf8'), stockid.encode('utf8'), stockname.encode('utf8'), cell[0].encode('utf8'), \
                                     cell[1].encode('utf8'), cell[2].encode('utf8'), cell[3].encode('utf8'), cell[4].encode('utf8'), \
                                     cell[5].encode('utf8'), cell[6].encode('utf8'), cell[7].encode('utf8'), cell[8].encode('utf8'), \
                                     cell[9].encode('utf8'), cell[10].encode('utf8'), cell[11].encode('utf8'), cell[12].encode('utf8'), \
                                     cell[13].encode('utf8'), cell[14].encode('utf8'), cell[15].encode('utf8'), cell[16].encode('utf8'), \
                                     cell[17].encode('utf8'), cell[18].encode('utf8'), cell[19].encode('utf8'), cell[20].encode('utf8'), \
                                     cell[21].encode('utf8'), cell[22].encode('utf8'), cell[23].encode('utf8'), cell[24].encode('utf8'), \
                                     cell[25].encode('utf8'), cell[26].encode('utf8'), cell[27].encode('utf8'), cell[28].encode('utf8'), \
                                     cell[29].encode('utf8'), cell[30].encode('utf8'), cell[31].encode('utf8'), cell[32].encode('utf8'), \
                                     cell[33].encode('utf8'), cell[34].encode('utf8'), cell[35].encode('utf8'), cell[36].encode('utf8'), \
                                     cell[37].encode('utf8'), cell[38].encode('utf8'), cell[39].encode('utf8'), cell[40].encode('utf8'), \
                                     cell[41].encode('utf8'), cell[42].encode('utf8'), cell[43].encode('utf8'), cell[44].encode('utf8') ])
                    DataCount += 1

                    #抓取第最後一筆集保日期
                    enddate = datestring

    #關閉檔案            
    writefile.close()
    print stockname.encode('utf8') + " 集保資料 " + startdate + '~' + enddate + "寫入 " + savefile + " 中,共完成 " + str(DataCount) + " 筆寫入\n"
    

def TdccData(URL):

    #解析網頁開始
    webcode = urllib.urlopen(URL)
    if webcode.code == 200:
        Tdcc = ParseWebData()
        Tdcc.parse(webcode.read())
        Tdcc.close()

    if len(Tdcc.cell) > 0 :
        return Tdcc.cell
    else:
        return []
        
    
class ParseWebData(SGMLParser):

    #初始化class等同constructor
    def __init__(self):
        SGMLParser.__init__(self)

    #初始化變數數值
    def reset(self):
        SGMLParser.reset(self)
        self.headname = False
        self.center = False
        self.right = False
        self.cell = []
        self.centercount = 0
        self.rightcount = 0

    #解析網頁    
    def parse(self,data):
        self.feed(data)
        self.close()

    #解析網頁標籤為td的內容    
    def start_td(self, attrs):
        for name,value in attrs:
            if name =='class' and value == 'wuc9':
                self.headname = True
                
            if name =='align' and value == 'center':
                self.center = True
                self.centercount+=1
 
            if name =='align' and value == 'right':
                self.right = True
                self.rightcount+=1

    #開始讀取集保資料到暫存list中            
    def handle_data(self, text):
        #print text
        if self.headname:
            #print text
            self.headname = False
            
        if self.center:
            if self.centercount == 1:
                #print "center : " + text
                self.center = False

            if self.centercount == 2:
                #print "center : " + text
                self.center = False
                self.centercount = 0

        if self.right :
            if self.rightcount == 1:
                #print "right : " + text
                self.cell.append(text.strip().replace(",", ""))
                self.right = False

            if self.rightcount == 2:
                #print "right : " + text
                self.cell.append(text.strip().replace(",", ""))
                self.right = False

            if self.rightcount == 3:
                #print "right : "  + text
                self.cell.append(text.strip())
                self.rightcount = 0
                self.right = False


class ParsestrModeWeb(SGMLParser):

    #初始化變數數值
    def reset(self):
        SGMLParser.reset(self)
        self.stockinfo = False
        self.cellno = 0
        self.stockid = []
        self.stockname = []
        self.cell1 = ""

    #解析網頁標籤為td的內容    
    def start_td(self, attrs):
        if len(attrs) == 1:
            if attrs[0][0] == 'bgcolor' and attrs[0][1] == '#FAFAD2':
                self.stockinfo = True
                self.cellno+=1
                self.cellno%=7

    #開始讀取股票代碼          
    def handle_data(self, text):
            if self.stockinfo:
                if self.cellno == 1:
                    self.cell1 = text.strip()
                elif self.cellno == 6 and text.strip() == 'ESVUFR':
                    data = self.cell1.strip().split('      \xa1@')
                    self.stockid.append(data[0].strip())                    
                    self.stockname.append(data[1].strip().decode('cp950'))                    
                elif self.cellno == 7:
                    self.cellno = 0
                self.stockinfo = False
                
def main():
    
    #上市, 上櫃股票代碼網址
    stocktype = [2,4]
    
    for i in range(0, len(stocktype)):
        url = "http://brk.twse.com.tw:8000/isin/C_public.jsp?strMode=" + str(stocktype[i])  
    
        #解析網頁開始
        webcode = urllib.urlopen(url)
        if webcode.code == 200:
            stock = ParsestrModeWeb()
            stock.feed(webcode.read())
            stock.close()

        #取得個股集保資料
        for j in range(0, len(stock.stockid)):
            GetTdccinfo(stock.stockid[j], stock.stockname[j])
                    
if __name__ == "__main__":
    main()

Python執行結果畫面

CSV檔案儲存內容如下