3C科技 娛樂遊戲 美食旅遊 時尚美妝 親子育兒 生活休閒 金融理財 健康運動 寰宇綜合

Zi 字媒體

2017-07-25T20:27:27+00:00
加入好友
今天陳陳就來教大家如何抓取上市各支股票歷年最高價吧!! 首先就是開啟Anaconda3的Jupyter Notebook 如果還沒安裝Anaconda的可以先去看上一篇 【python】如何安裝Anaconda3(Jupyter Notebook) 【尋找所需資料的網站】 首先,我們要先找到能爬取我們要的資料網站 這裡我們是去抓取台灣證券交易所的資料 從台灣證券交易所抓資料的優點是網址為GET,所以抓取簡單方便,但缺點是太頻繁抓取會被封鎖,所以從這抓資料會花比較長的時間 進入證交所後,我們點選上方的交易資訊→盤後資訊的個股月成交資料 接下來我先隨便打個股票代碼做搜尋,並對「CSV下載」點選右鍵選擇「複製連結網址」 https://www.twse.com.tw/exchangeReport/FMSRFK?response=csv&date=20200615&stockNo=2330 這就是我們複製的網址,我們可以從date=後方的20200615知道,這是日期,stockNo=後方的2330知道是代碼 沒錯,這就是證交所爬取資料為什麼那麼簡單,因為規則就直接打在網址上,一看就知道,我們只要改變這兩個地方我們就能查詢不同年份跟不同的股票 那接下來就是要知道每個上市股票代碼才能替換stockNo=後方的代碼 這部分陳陳前也有發過一篇教學,可以先點去看唷 【python】如何利用python輕鬆抓取上市櫃股票清單 那我們找尋資料的部分就告一段落了,接下來就是撰寫程式的部分拉!!   【撰寫程式】 在撰寫程式前我們都要先設定一個目標,這樣才能快速清楚的知道自己是要抓取什麼資料 而我們今天的目標就是抓到上市各檔股票從1996年到2020年5月的每月最高價 那目標設定好後,我們就開始撰寫吧!!   【step1 import package】 首先我們習慣把要爬取的網站先用##標記在最上方,以方便使用 然後我們要import一些package 1     import requests 2     import pandas as pd 3     import io 4     import datetime 5     import time 6     import calendar 這次一樣會用到基本的requests以及pandas 外加io,io能讓我們讀寫一個虛擬的檔案,因為我們從證交所複製的csv檔網址並非實際下載下來的檔案,所以我們需要透過 io.StringIO 讓我們讀檔 datetime是之後讓我們抓取日期所用 time是為了之後不被證交所封鎖,我們需要time.sleep來限制每次抓取的間隔時間 calendar是為了讓我們的月份更改成英文 其實這一步我們一開始並不會import這麼多,都是往後在抓取時遇到問題我們才會一一加上去,所以剛開始學python的朋友不用太緊張,不用想說怎麼一開始我就要知道import什麼   【step2 先處理股票代碼】 我們透過【python】如何利用python輕鬆抓取上市櫃股票清單已經將股票代碼抓取下來,但還需要做一些整理,因為我們會遇到一個問題,那就是我們是要抓取1996年之後的每檔股票每月最高價,所以要區分該股票是在1996年之前還之後上市,這會影響我們抓資料的些許不同 那我們首先就是要將抓取的股票清單中的「公開發行/上市(櫃)/發行日」的年跟月分出來 7~12以及19行都是我們先前教的,這裡我們增加了幾行讓我們能分出「年」跟「月」 13、14是先在原先的DataFrame中增加我們要的欄位,也就是年跟月,一開始先設為0 15~17是利用for迴圈將每一個原本在「公開發行/上市(櫃)/發行日」中的年跟月分開加入我們創建的欄位,而年月日本身中間有「/」當作區隔,所以我們就利用split("/")來隔開,split的意思就是只要原文中()內的東西都變成分隔資料的間格,例如:2020/6/15,利用split("/")就會變成['2020', '6', '15'],而年的部分就變成字串[0],月的部分變成字串[1] 最後18就是將我們不要的「公開發行/上市(櫃)/發行日」drop掉,那我們就股票代碼清單整理就告一段落了 7         url2 = "https://isin.twse.com.tw/isin/class_main.jsp?owncode=&stockname=&isincode=&market=1&issuetype=1&industry_code=&Page=1&chklike=Y" 8         page2 = requests.get(url2) 9         df = pd.read_html(page2.text)[0] 10       df = df.drop([0,1,4,5,8,9],axis = 1) 11       df.columns = df.iloc[0] 12       df = df.iloc[1:] 13       df["年"] = 0 14       df["月"] = 0 15       for t in range(1,len(df)+1): 16           df["年"][t] = df["公開發行/上市(櫃)/發行日"][t].split("/")[0] 17          df["月"][t] = df["公開發行/上市(櫃)/發行日"][t].split("/")[1] 18       df = df.drop("公開發行/上市(櫃)/發行日",axis = 1) 19       df = df.set_index("有價證券代號") 將我們處理好的股票代碼清單用一個def來定義函式   【step3 開始抓取股票每月最高價】 這裡陳陳直接拿已經定義def的最終型態來講解 首先我們先定義def,後方名字可自行取,陳陳命名為stock,()內的名稱也能自行設定,因為這只是讓你方便知道要輸入什麼參數 21~24接下來就是處理先前說的從證交所抓取的csv檔,我們將有規律的date=後方以及stockNO=後方的位置改成我們的參數,而date=後方因為我們只需要更改年就好,所以月跟日我們隨便設,因為不影響我們要抓的資料 25行是用if來判斷我們抓的股票他是在1996年之前還之後上市,這樣才不會有股票在還未上市的年分抓不到資料 26~29行是因為證交所在2015年之後有修改他的版面,多了一行,所以我們要多刪掉一行 30、31行是將中文月份更改成英文,這樣在跑圖表時顯示英文比較好看,但如果你想要看中文也是可以不用這行 32、33行是將「有價證券名稱」這欄位名稱更改成最高價,因為我們最後合併放上圖表時,這行的標頭要顯示最高價 34、35行是將民國的年份更改成西元 36、37行是將修改好的年、月合併,例如:修改後的西元年為2020,月份為5月是Mar,合併後變成2020Mar,這就會變成我們圖表右下角跑動的年月份 38~42行是將我們的資料轉置,因為我們最後要合併需要是橫的形式,然後修改一下成我們要的樣式,然後最後加上產業別,這最後在做圖表時可以加入查看股王都是哪個產業的股票,但陳陳最後是沒有放上產業,因為太多產業圖表看上去太雜亂,但如果是要自己看的可以放上去看 44行是如果我們輸入該股票但年份卻在它上市之前,我們就回傳您輸入的年份該股票尚未上市 45行最後就是輸入我們的回傳值,也就是我們最終的答案 20       def stock(stock_id,date_time): 21           df2 = df_u(stock_id) 22           url = "https://www.twse.com.tw/exchangeReport/FMSRFK?response=csv&date=" + date_time + "0101&stockNo=" + stock_id 23           page = requests.get(url) 24           use_text = page.text.splitlines() 25           if date_time >= str(df2["年"][0]): 26               if date_time > str(2015): 27                   use_text1 = pd.read_csv(io.StringIO(''.join([text[:-1] + "\n" for text in use_text[1:len(use_text)-4]]))) 28               else: 29                   use_text1 = pd.read_csv(io.StringIO(''.join([text[:-1] + "\n" for text in use_text[1:len(use_text)-3]]))) 30               for i in range(0,len(use_text1)): 31                    use_text1["月份"][i] =  calendar.month_abbr[use_text1["月份"][i]] 32               df_text = use_text1[["年度","月份","最高價"]] 33               df_text1 = df_text.rename(columns={'最高價':df2["有價證券名稱"][0]}) 34               for i in range(0,len(df_text1)): 35                     df_text1["年度"][i] = int(df_text1["年度"][i]) + 1911 36               for i in range(0,len(df_text1)): 37                    df_text1["年度"][i] = str(df_text1["年度"][i]) + df_text1["月份"][i] 38                    df_text2 = df_text1.drop(["月份"],axis = 1) 39               df_text2_T = df_text2.T 40               df_text2_T.columns = df_text2_T.iloc[0] 41               df_text2_T = df_text2_T.iloc[1:] 42               df_text2_T.insert(0,"產業別",df2["產業別"][0]) 43           else: 44               df_text2_T = "您輸入的年份該股票尚未上市" 45           return df_text2_T   然後隨便輸入一檔股票跟年份來查看是否為我們要的格式 輸入後檢查一下,2330是台積電,產業是否為半導體業,年份部分對不對,最高價拿去跟證交所查詢的比對一下對不對,並且多查看幾家,如果都沒錯,那恭喜我們又完成一個段落了   【step4 單一股票年份合併】 接下來的工作就是將每檔股票從1996年到2020年5月的最高價資料合併起來 46行一樣先定義一個def 47行是先抓取現在的時間,因為後續會用到 48行一樣先定義前方寫的股票清單為stock_a 49~65行是判斷該股票是在1996年之前還之後上市,如果是之後,我們就從該股票上市那年開始抓取,如果是之前,我們就從1996年開始抓 接下來就是一連串的合併動作,中間記得要間隔8秒,因為在這間隔5秒一樣會被檔 66行是回傳我們要定義值出現的值 那單一股票合併的工作就也完成了 46           def stock_tw1(stock_id):  47               z = datetime.datetime.now() 48               stock_a = df_u(stock_id) 49               if stock_a["年"][0] > 1996: 50                   s_0 = stock(stock_id,str(stock_a["年"][0])) 51                   s_0_T = s_0.T 52                   for b in range(stock_a["年"][0]+1,z.year+1):  53                       time.sleep(8) 54                       s_1 = stock(stock_id,str(b)) 55                       s_1 = s_1.drop(["產業別"],axis = 1) 56                       s_0_T = s_0_T.append(s_1.T) 57                   return s_0_T.T 58               else: 59                   s_0 = stock(stock_id,"1996") 60                   s_0_T = s_0.T 61                   for b in range(1997,z.year+1): 62                       time.sleep(8) 63                       s_1 = stock(stock_id,str(b)) 64                       s_1 = s_1.drop(["產業別"],axis = 1) 65                       s_0_T = s_0_T.append(s_1.T) 66                   return s_0_T.T 然後出來結果大概會像下方這樣,因為康控-KY是2016年才上市,所以資料是從2016年開始到2020年   【step5 將各家股票下載下來】 接下來就是將股票一一下載成CSV檔,這裡可能會有人說為什麼不一起合併成一個檔案再下載下來,因為我們先前有說證交所會有阻擋機制,太頻繁抓取就會被檔,陳陳試了很多次,發現間隔5秒是最適合的抓取時間,但還是有機率會被檔,所以陳陳選擇一檔一檔抓取完後再進行合併,而且我們光上市公司就有900多家,如果每檔都沒失敗都抓成功,外加每檔每年間隔8秒,要抓20幾年,換算下來就要抓個2到3天的時間了,所以使用一檔一檔抓取方式就可以中斷,有空的時候再繼續 66行是先定義我們要存放CSV檔的位置 67行是用for迴圈將股票代碼一一跑過,所以如果中間有中斷,我們能先將df.index[0]額外取出來先看自己目前抓到的檔案位於股票清單第幾個位置,如果找到了就將該數字+1放回index去繼續跑,67行就會變成for a in df.index[要開始抓的股票代碼位置+1:]: 然後剩下的就是抓取每檔股票,try是嘗試執行,失敗話就會跳到except,所以我們在抓取成功的股票後方加上print("Successful!!" + " " + a),當我們成功時就會顯示successful!!,失敗的話print("Fails at" + ' ' + a + "1"),也就是出現failes,我們才知道我們該檔股票是成功還失敗,而陳陳還會在多加一個try然後間隔10秒是怕在抓取的過程中被封鎖IP,所以休息個10秒看看能不能被打開繼續抓,如果都失敗,我們之後抓完後再例外處理,像陳陳就有遇到一些股票上市日期跟資料提供開始日不同,這就可以事後單獨小修程式抓取出來 66                   file_path = r"D:\python\stock_high" 67                   for a in df.index[0:]: 68                       time.sleep(5) 69                       try: 70                           stock_tw2 = stock_tw1(str(a)) 71                           stock_tw2.to_csv(file_path + "\\" + str(a) + '.csv',encoding= 'utf_8_sig') 72                           print("Successful!!" + " " + a) 73                       except:  74                           print("Fails at" + ' ' + a + "1") 75                           time.sleep(10) 76                           try: 77                               stock_tw2 = stock_tw1(str(a)) 78                               stock_tw2.to_csv(file_path + "\\" + str(a) + '.csv',encoding= 'utf_8_sig') 79                               print("Successful!!" + " " + a) 80                           except:    81                                print("Fails at" + ' ' + a + "2")     【總結】 上市的部分做到這裡算是大功告成了,那最終合併的資料陳陳會跟上櫃的一起合併,所以留在下篇上櫃教學完後會一起教合併 其實爬蟲說難不難,說簡單也沒很簡單,但只要有心要學習,就一定能做出自己想要的東西,對未來一定有很大的幫助,因為在未來不論你從事什麼行業都會跟網路脫離不了關係,而python又是比較好入門的程式語言,所以大家一起加油的把python學好吧!!

本文由adsads023023pixnetnetblog提供 原文連結

寫了 5860316篇文章,獲得 23313次喜歡
精彩推薦