解析: Python 實現終端實時獲取股票價格
首發於我的博客 The North。
GitHub 里老早之前就 Star 了 felixglow/Stock 這個項目,原作者 felixglow。昨天晚上又想起這個來,於是今兒早上就拿出來看——我對其中相當多的部分都不熟悉,有些還是第一次了解。在這裡將我的理解記錄下來,其中的錯謬之處,還望各位大神指正。
實現效果
實現思路
在 README,作者這樣寫道:
通過調用新浪股票API,實時查詢股票價格
支持查詢多支股票,通過threading多線程同時查詢結果
通過Queue實現線程池requests請求介面optparse實現命令行參數處理
這就是這個項目的主要思路——爬取新浪股票 API 來獲取數據,通過 threading 實現多線程以達到同時查詢多支股票的目的,最後用 optparse 實現命令行參數的處理。
具體解析
__author__ = felixn# 原作者為 felixnnimport requestsn# requests 用於爬取新浪股票 APInimport timenimport sysn# sys 用於在解釋器中交互nimport threadingn# threading 用於多線程處理 nnfrom Queue import Queuen# Queue 是有關隊列的庫nfrom optparse import OptionParsern# OptionParser 用於在命令行中添加選項nnclass Worker(threading.Thread):n# 創建類 Work,多線程獲取nn def __init__(self, work_queue, result_queue):n # 寫入必須綁定的強制屬性 self, work_queue, result_queuen # __init__ 方法的第一個參數一定是 self,用於表示創建的實例本身n # 其中,實例是根據類來創建的n # 在 __init__ 方法內部,可將各種屬性綁定到 self,因為 self 指向創建的實例本身nn threading.Thread.__init__(self)n self.work_queue = work_queuen self.result_queue = result_queuen self.start()nn def run(self):n # 增加一個新方法 runnn while True:n func, arg, code_index = self.work_queue.get()n # 獲取 func, arg, code_indexn res = func(arg, code_index)n self.result_queue.put(res)n if self.result_queue.full():n res = sorted([self.result_queue.get() for i in range(self.result_queue.qsize())], key=lambda s: s[0], reverse=True)n # sorted() 是用於排序的方法,返回副本,原始輸入不變n # Queue.get() 用於獲取隊列n # Queue.qsize() 返回隊列大小 n # key=lambda s: s[0]:關鍵詞為 lambda s: s[0]n # lambda s: s[0]:匿名函數,返回第一個元素n # reverse=True:降序排列 n res.insert(0, (0, u名稱 股價))n # list.insert() 用於將指定對象插入列表的指定位置 n print ***** start *****n for obj in res:n print obj[1]n print ***** end *****nn self.work_queue.task_done()n # 在完成一項工作後,Queue.task_done() 會向任務已經完成的隊列發送一個信號 nnnclass Stock(object):n# 股票實時價格獲取nn def __init__(self, code, thread_num):n self.code = coden self.work_queue = Queue()n self.threads = []n self.__init_thread_poll(thread_num)nn def __init_thread_poll(self, thread_num):n self.params = self.code.split(,)n # parmas 會向函數傳入一個字典n self.params.extend([s_sh000001, s_sz399001]) n # 默認獲取滬指、深指n # extend(): 擴展,與 append() 的區別為,extend() 加入的元素是分別單個加入的n self.result_queue = Queue(maxsize=len(self.params[::-1]))n for i in range(thread_num):n self.threads.append(Worker(self.work_queue, self.result_queue))nn def __add_work(self, stock_code, code_index):n self.work_queue.put((self.value_get, stock_code, code_index))n # self.value_get 涉及到下面的裝飾器 nn def del_params(self):n for obj in self.params:n self.__add_work(obj, self.params.index(obj))nn def wait_all_complete(self):n for thread in self.threads:n if thread.isAlive():n # 判斷線程是否是激活的n # 從調用 start() 方法啟動線程,到 run() 方法執行完畢或者遇到未處理異常而中斷,這段時間內線程是激活的 n thread.join()n # join() 的作用是阻塞進程直到線程執行完畢n # 依次檢查線程池中的線程是否接觸,沒有結束就阻塞線程直到線程結束n # 如果結束則跳轉執行下一個線程的 join() 函數 nn @classmethodn # 裝飾器,返回函數的高階函數 n def value_get(cls, code, code_index):n slice_num, value_num = 21, 3n name, now = u——無——, u ——無——n if code in [s_sh000001, s_sz399001]:n slice_num = 23n value_num = 1n r = requests.get("http://hq.sinajs.cn/list=%s" % (code,))n # 爬取新浪股票 API n res = r.text.split(,)n if len(res) > 1:n name, now = r.text.split(,)[0][slice_num:], r.text.split(,)[value_num]n return code_index, name + + nownnnif __name__ == __main__:n# 該腳本用於直接運行,而不能被 importn parser = OptionParser(description="Query the stocks value.", usage="%prog [-c] [-s] [-t]", version="%prog 1.0")n # 生成命令行說明n # %prog 將會以當前程序名的字元串來代替 n parser.add_option(-c, --stock-code, dest=codes,n help="the stocks code that you want to query.")n # 使用 add_option() 來定義命令行參數,即加入選項n # dest 是儲存的變數 n parser.add_option(-s, --sleep-time, dest=sleep_time, default=6, type="int",n help=How long does it take to check one more time.)n parser.add_option(-t, --thread-num, dest=thread_num, default=3, type=int,n help="thread num.")n options, args = parser.parse_args(args=sys.argv[1:])n # 設置好命令行後,用 parse_args() 來解析命令行n assert options.codes, "Please enter the stock code!" n # 是否輸入股票代碼n if filter(lambda s: s[:-6] not in (sh, sz, s_sh, s_sz), options.codes.split(,)): n # 股票代碼輸入是否正確n raise ValueErrornn stock = Stock(options.codes, options.thread_num)nn while True:n stock.del_params()n time.sleep(options.sleep_time)n # sleep() 用於使程序休眠n
我的想法
從學習 Python 到現在也已經是不短的時間了,但最近覺得自己原地踏步了好久,一直沒什麼長進,於是想看一看真正有使用價值的代碼是什麼樣子的。上面這部分內容,與其說是 具體解析,還不如說是做了所有的注釋工作,但對於我這樣已經了解 Python 的基本語法和較為初級並常用的第三方庫的學習者來說,這樣一個不到百行的項目,應該是比較合適的練手材料。對這個項目中所用到的方法和庫,有些我只是了解,有些甚至以前還沒有聽說過,因而過一遍代碼思路和細節部分,是比較值得的。
記錄
截止到東八區 2016 年 12 月 19 日 14:46 ,這個項目一共有 4 個 Watch,37 個 Star 和 37 個 Fork。
最後再次感謝原作者 felix。
推薦閱讀: