返回列表 上一主題 發帖

python 融資融券彙總 (全部)"資料

python 融資融券彙總 (全部)"資料

還不會製作執行檔!其內容僅供參考之
  1. #-*- coding:utf-8 -*-

  2. '''
  3. 本程序由 Python 3.52 寫成,為作者參考麻辣家族討論區 "python上市櫃三大法人買賣超日報資料下載" 討論內容練習
  4. 其內容大部份參考 zyzzyva大大、c_c_lai 大大 、koshi0413 之討論內容,感謝!
  5. 本程序會自動生成 Access 的 twsedata.mdb資料庫,及建立各所需之資料表,但只能下載"融資融券彙總 (全部)"資料
  6. ㄟ!沒有信用交易統計資料 ,只建立其資料表
  7. 本程序需要 pip 安裝 requests 、BeautifulSoup4、pypyodbc
  8. 以及需下載 pywin32 : https://sourceforge.net/projects/pywin32/files/pywin32/Build%20220/
  9. 使用方法:只在 input 時 ,輸入開始擷取日期及結束擷取日期即可,第一次執行時,會建構資料庫,而後只增加資料,
  10. 每日資料擷取到儲存至資料庫的時間約 21秒(依作者電腦執行計時 )
  11. 本程序僅供參考,不負責更新內容,不負責除錯(因為我也是新手,除錯對我來說太#%%$...),搞壞使用者電腦,也不關作者的事!!
  12. 作者:麻辣家族討論區 lpk187
  13. 完成日期:2016/9/22
  14. '''

  15. import requests
  16. from bs4 import BeautifulSoup
  17. import random
  18. import os
  19. import win32com.client
  20. import pypyodbc
  21. import datetime
  22. import time

  23. # 隨機更改 headers
  24. def head_random():
  25.       for i in range(10):
  26.             hs = ['Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
  27.                    'Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16',
  28.                    'Mozilla/5.0 (Linux; U; Android 4.1.2; zh-tw; GT-I9300 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
  29.                    'Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10'
  30.                    'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)']
  31.             hes = {"User-Agent":random.choice(hs)}
  32.       return hes

  33. # 集台證所融資融券餘額全部資料
  34. def read_network_data(date,from_number):
  35.       url = 'http://www.twse.com.tw/ch/trading/exchange/MI_MARGN/MI_MARGN.php'
  36.       head =head_random()
  37.       payload = {"download":'',
  38.                  "qdate":date,
  39.                  "selectType":"ALL"}
  40.       res = requests.post(url, headers=head, data=payload)
  41.       soup=BeautifulSoup(res.text, "lxml")
  42.       tab = soup.select('tbody')[from_number] # 2個表格之2
  43.       regs=[] # 初始陣列
  44.    
  45.       for i in range(len(tab.select('tr')[0].select('td'))): # 定義2維陣列維度
  46.             regs.append([])

  47.       for tr in tab.select('tr'): #擷取表格資料
  48.             for i in range(len(tab.select('tr')[0].select('td'))):
  49.                   regs[i].append(tr.select('td')[i].text)
  50.       return regs

  51. def conn_db():
  52.       Conn = win32com.client.Dispatch("ADODB.Connection")
  53.       strMDB ='Provider=Microsoft.ACE.OLEDB.12.0; Data Source=' + os.getcwd() + '\\twsedata.mdb;'
  54.       Conn.ConnectionString = strMDB
  55.       Conn.Open()
  56.       return Conn

  57. def check_db_exists(regs):
  58.       if not os.path.exists('twsedata.mdb'):
  59.             pypyodbc.win_create_mdb( os.getcwd() + '\\twsedata.mdb')
  60.             Conn=conn_db()
  61.             sql = "CREATE TABLE 股票(股票代號  char(10) PRIMARY KEY,股票名稱  char(20));"
  62.             Conn.Execute(sql)
  63.             sql = "CREATE TABLE  融資融券信用交易統計(日期  datetime,項目  char(20),買進 INTEGER,買出 INTEGER,現金(券)償還 INTEGER,前日餘額 INTEGER,今日餘額 INTEGER);"
  64.             Conn.Execute(sql)
  65.       n = 0
  66.       Conn=conn_db()
  67.       for i in regs[0]:
  68.             try:
  69.                   Conn.Execute('select * from ' + i); # table does not exist
  70.             except Exception as e:
  71.                   sql="CREATE TABLE " + i + "(日期  datetime,"
  72.                   sql= sql + "資買進  INTEGER,"
  73.                   sql= sql + "資賣出 INTEGER,"
  74.                   sql= sql + "資現金償還 INTEGER,"
  75.                   sql= sql + "資前日餘額 INTEGER,"
  76.                   sql= sql + "資今日餘額 INTEGER,"
  77.                   sql= sql + "資限額 INTEGER,"
  78.                   sql= sql + "券買進  INTEGER,"
  79.                   sql= sql + "券賣出 INTEGER,"
  80.                   sql= sql + "券現金償還 INTEGER,"
  81.                   sql= sql + "券前日餘額 INTEGER,"
  82.                   sql= sql + "券今日餘額 INTEGER,"
  83.                   sql= sql + "券限額 INTEGER,"
  84.                   sql= sql + "資券互抵 INTEGER,"
  85.                   sql= sql + "註記 char(5));"
  86.                   Conn.Execute(sql)
  87.                   rs = win32com.client.Dispatch('ADODB.RecordSet')
  88.                   rs.ActiveConnection = Conn
  89.                   rs.Open('select * from 股票', Conn, 3, 3)
  90.                   rs.AddNew()
  91.                   rs.Fields.Item(0).Value = regs[0][n]
  92.                   rs.Fields.Item(1).Value = regs[1][n]
  93.                   rs.Update()
  94.             n += 1

  95. def add_data(regs,date):
  96.       Conn=conn_db()
  97.       for i in range(len(regs[0])):
  98.             rs = win32com.client.Dispatch('ADODB.RecordSet')
  99.             rs.ActiveConnection = Conn
  100.             sql='select * from ' + regs[0][i]
  101.             rs.Open(sql, Conn, 3, 3)
  102.             for j in range(2,len(regs)):
  103.                   if j==2:
  104.                         rs1 = win32com.client.Dispatch('ADODB.RecordSet')
  105.                         rs1.ActiveConnection = Conn
  106.                         sql="SELECT * FROM " + regs[0][i] + " WHERE 日期 = #" + date + "#;"
  107.                         rs1.Open(sql,Conn,3,3)
  108.                         if rs1.EOF:
  109.                               rs.AddNew()
  110.                               rs.Fields.Item(0).Value = date
  111.                               rs.Fields.Item(j-1).Value = regs[j][i]
  112.                               rs1.Close()
  113.                         else:
  114.                               rs1.Close()
  115.                               break
  116.                   rs.Fields.Item(j-1).Value = regs[j][i]
  117.             rs.Update()

  118. # 以下為程式的啟始點:
  119. StartDate=input('請輸入開始擷取日期(西元日期如:2016/1/1):')
  120. EndDate=input('請輸入結束擷取日期(西元日期如:2016/1/31):')
  121. #處理日期還真的很麻煩
  122. ts=time.time()
  123. StartDate = time.strptime(StartDate, "%Y/%m/%d")
  124. EndDate =time.strptime(EndDate, "%Y/%m/%d")
  125. StartDate = datetime.date(StartDate[0], StartDate[1], StartDate[2])
  126. EndDate =  datetime.date(EndDate[0], EndDate[1], EndDate[2])
  127. RangeDate = datetime.timedelta(days = 1)
  128. while StartDate <= EndDate:
  129.       yy,mm,dd=str(StartDate).split('-')
  130.       dat=datetime.datetime(int(yy), int(mm), int(dd))
  131.       dd=dat.strftime('%Y/%m/%d')
  132.       year=str(int(dd[0:4])-1911)
  133.       date=dd.replace(dd[0:4], year)
  134.       print('目前執行網路擷取',date ,'日的資料,請稍後...')
  135.       re=read_network_data(date,1)
  136.       if re[0][0]=='查無資料':
  137.             print(date,'日,可能為休市日,查無資料。')
  138.             StartDate = StartDate + RangeDate
  139.             continue
  140.       print('檢查是否有新股票加入,請稍後...')
  141.       check_db_exists(regs=re)
  142.       print('將資料寫入資料庫中,請稍後...')
  143.       add_data(regs=re,date=dd)
  144.       StartDate = StartDate + RangeDate
  145.       te = time.time()
  146.       print('截至目前,時間已耗費:', int(te - ts),'秒')

  147. print('執行完畢!')
複製代碼

小弟是程式新手,所以什麼都不懂,會亂發問,請見諒嘿~~

TOP

請問各位大大,最近不想從證交所抓資料,改向鉅亨網,不過在網頁解析上沒經驗(之前是請教別人後,再依樣劃葫蘆慢慢改出自已想要的)
原程式部份檔如附件,

  若改由鉅亨網下載資料的話,從網路上看文章,其中改成以下,不過好像沒辦法送出查詢,想請教是哪裡出問題??
          = "    cnyes.com/twstock/ps_historyprice/" + (cell21)+".htm"
    classSelectTextStart = (str(yy-1)+"/"+str(mm)+"/"+str(dd))
    classSelectTextEND = (str(yy)+"/"+str(mm)+"/"+str(dd))
  
    browser.find_element_by_id("ctl00_ContentPlaceHolder1_startText").send_keys(classSelectTextStart)
    browser .find_element_by_id("ctl00_ContentPlaceHolder1_endText").send_keys(classSelectTextEND)
    browser.find_element_by_id("ctl00_ContentPlaceHolder1_submitBut").send_keys(Keys.ENTER)
    time.sleep(10)

原始檔.tar (4.5 KB)

TOP

太棒了!  謝謝大大的分享~~

TOP

回復 52# lpk187
我的是 179 Records。

TOP

由於 sqlite3 在日期時間 是以文字串存入,而非以日期時間格式存入(如:#2016/01/06#)
而sqlite3的date函數的日期格式必須像'2016-01-06'年月日需以'-'隔開 ,若以'2016/01/06' 斜線 '/'隔開,以SQL語法會無法計算
所以在存入sqlite3資料庫的日期,必須先處理

在 dd=dat.strftime('%Y/%m/%d')的下行需加入另一句
sqldate=dat.strftime('%Y-%m-%d')

而這句add_data(regs=re,date=dd)必須修改為
add_data(regs=re,date=sqldate)

在以後的日期處理,就會容易處理了

sqlite3在日期查詢方面,例如說要查詢 '2016-01-01' 到 '2016-01-31'
在SQL語法方面 原來的用法 WHERE 日期 BETWEEN '2016-01-01' AND '2016-01-31'
而sqlite3 卻不能以 BETWEEN 去處理,就像前面說的,日期時間 是以文字串存入,文字串不能用在日期時間處理

所以sqlite3的SQL語法為
"select * from [0050] where julianday(日期)>=julianday('2016-01-01') and julianday(日期)<=julianday('2016-01-31')"

TOP

回復 49# c_c_lai


   你執行的情況,真的很奇怪!我執行了3次從2016/1/1到2016/9/29 也都沒有得到像你一樣的結果
你再把資料庫刪掉,觀察第一次是不是會不完整,從2016/1/1到2016/9/29共有170筆資料,看是不是會不夠
我程式裡面,只有插入INSERT INTO...並沒有修改的語句而且當有重覆值時,並不會執行任何動作
except Exception as e:
            pass
再麻煩你了

TOP

其實你提到的 :
"目前的想法是   python 抓取資料至 sqlite3,vba 從 sqlite3 取出資料"
在實務上這種 ...
c_c_lai 發表於 2016-9-30 15:22


原來如此,小弟是看長期月線的,所以是要統計歷史資料沒有錯
線上即時作業 小弟沒辨法,原來是操作手法的不同

故,泥用python取出sql內的表格,只是單純要畫圖?
印像中   台灣的 線上即時作業 都是用 excel (國外聽說改掉了)
用vba才可以即時互動   python應該還不行~~不過也不一定,說不定多google  就有高手作出來了呢

ps:咳咳~~大家上班不上班的在聊這個,哈哈哈

TOP

c大
可否請教一下,在python取出資料sql  是要在 python直接畫圖嘛?速度較快?還是單純練習呢?
因為看 ...
koshi0413 發表於 2016-9-30 14:43

其實你提到的 :
"目前的想法是   python 抓取資料至 sqlite3,vba 從 sqlite3 取出資料"
在實務上這種方式,只能當作是 『儲備作業』,提供作為 「歷史資料查詢」;
『線上即時作業』是 Excel 直接與券商 DDE 連結攫取資訊,直接進行繪圖分析;
除非 Python 也提供類似如此之功能 (連結券商DDE);接下來透過
Candlestick OHLC graphs with Matplotlib 來處理。

TOP

回復 44# lpk187
經比對後始發現不無重複鍵值;而是第一次執行時
部位依次完全寫入,再第二次執行時發現從 Rec#104後
又有新的紀錄寫入,才覺得訝異。
經大大再次分析解說,再次資料比對才發現其為新值。

現在的問題是: 第一次初始資料寫入時違和會是不完整?

TOP

        靜思自在 : 屋寬不如心寬。
返回列表 上一主題