流程圖如上
程式碼:
#--------------------------載入模組------------------------------
import requests
from bs4 import BeautifulSoup
import time
from datetime import datetime
#--------------------------參數設定------------------------------
n_time = datetime.now() #現在時間
d_time1 = datetime.strptime(str(datetime.now().date())+"9:00","%Y-%m-%d%H:%M") #開盤時間 9:00
d_time2 = datetime.strptime(str(datetime.now().date())+"13:30","%Y-%m-%d%H:%M") #收盤時間 13:30
#-----Line Notify-----
token = 'sSnk6ptHXzweoZtU29YzLVoufk7CMh0pD6JF8CdCqQ5' #權杖代碼
#定義send_message,傳入權杖(token)和要推送的字串(msg)來達到字典型態。
def send_message(token,msg):
#Line Notify 推送已post的方式提交請求,因此要定義「headers」它是字點型態
#其中一個索引key名稱「Authorization」對應的值,是由持有人(Bearer)和權杖(token)組成的字串
token = 'sSnk6ptHXzweoZtU29YzLVoufk7CMh0pD6JF8CdCqQ5'
haeaders = {
'Authorization':"Bearer "+token,
"Content-Type":"application/x-www-from-urlencoded"
}
#將要推送的訊息字串存在字典內,放進Message的索引中
payload = {"message":msg}
#以post的方式,向'https://notify-api.line.me/api/notify'提出請求
r = requests.post('https://notify-api.line.me/api/notify',headers = haeaders,params = payload)
#可以做到例外排除,將請求的回傳用r接起,並把這個請求的執行狀態作為send_messaage函數的回傳
return r.status_code
#如果請求成功 r.status_code = 200
#-----爬蟲設定-----
def web_crawler():
url = 'https://tw.stock.yahoo.com/quote/2330' #設動網址
web = requests.get(url)
soup = BeautifulSoup(web.text,'html.parser')
return soup
soup = web_crawler()
title = soup.select('.D\(f\) h1')[1].text #標題
number = '('+ soup.select('.Fz\(24px\)')[1].text +")" #該檔股票代號
title += number #整理成 標題+代號
test = True #測試狀態
first = True #程式今日第一次執行
#--------------------------main---------------------------------
while (n_time >= d_time1 and n_time <= d_time2) or test:
#--------------------------爬取網站資料--------------------------
n_time = datetime.now()
soup = web_crawler()
now_type = soup.select('.C\(\#6e7780\)')[0].text #開盤收盤狀態
situation = soup.select("#main-0-QuoteHeader-Proxy")[0].select(".Fz\(16px\)")[2].text #該檔運勢
data = soup.select("#main-2-QuoteOverview-Proxy")[0].select(".Pos\(r\)")[0].select(".D\(f\)")[1]
data = data.select('.Pos\(r\) ul')[0].text #該檔即時的數據
#--------------------------資料整理--------------------------
def str_number_data(data): #將爬下的股票數據整理成'字典'的資料型態
#將'字'與'數字'分割
d = {}
data_name,Num = '','' #暫存數據名稱 暫存數字 資料型態為str
state = 0 #0表示目前為中文字 1表示目前為數字
for i in data:
if ord(i)==40 or ord(i)==41: #ASCII碼判斷'('or')'
data_name+=i
continue
if ord(i)>=37 and ord(i)<=57: #ASCII 符號是數字~number
if not state: #先判斷當前是否為中文字
Num = i
state = 1
else:Num+=i
else:
if state:
d[data_name] = Num
data_name = i
else:
data_name+=i
state = 0
d[data_name] = Num
return(d)
def FS(data): #格式化輸出資料
a= '\n'
s = 0
for key,Value in data.items():
a += '{:13s}'.format((f'{key} : {Value}'))
if s:
a += '\n'
s = 0
else: s+=1
return a
def write_data_txt(data): #將部分資料紀錄在記事本
print("更新data.txt ~~")
word = ['成交','開盤','漲跌','漲跌幅']
with open("data.txt",'w',encoding="utf-8") as f:
f.write('漲跌狀況 '+s+'\n')
for w in word:
meg = w+" "+data[w]+'\n'
f.write(meg)
def read_data_txt(): #讀取舊資料
print("讀取data.txt ~~\n")
old_data = {}
with open('data.txt','r',encoding='utf-8') as f:
for line in f.readlines():
a,b = line.split()
old_data[a] = b.strip("\n")
return old_data
data = str_number_data(data)
ups_and_down = f"{data['漲跌']}({data['漲跌幅']})" #漲跌
Instant_price = f'{data["成交"]}' #即時價
if float(data['成交'])>float(data['昨收']): s,emoji = '↑',['📈',' ⬆️']
elif float(data['成交'])<float(data['昨收']): s,emoji = '↓',['📉',' ⬇️']
else: s,emoji = '平',['-','-'] #s變數代表漲跌狀況
#--------------------------傳入Line Notify--------------------------
if first: #每天第一次啟動時 抓取當時狀況
write_data_txt(data)
old_data = read_data_txt()
send_msg=("\n開盤囉~🍉 \n排程啟動成功👌")
print("發送開盤通知~",send_message(token,send_msg))
send_msg = f"{title}🍉\n|| {now_type} ||\n連漲連跌 : {situation} \n即時價 : {Instant_price} {emoji[0]}{emoji[1]}"
send_msg += f"{ups_and_down} \n------------------------------------------------\n"
send_msg += FS(data)
print("發送開盤數據~",send_message(token,send_msg)) #傳送至Line notify
print(send_msg) #在終端機上檢查
print("啟動成功 fitst設定True")
first = False
else:
if old_data['漲跌']!=data['漲跌']: #成交價若有變化才傳送通知
if old_data["漲跌狀況"]==s: #判斷漲跌是否有變化
send_msg = (f'~目前持續{emoji[0]}{emoji[0]}\n即時價:{data["成交"]} {emoji[1]}{ups_and_down}\n')
if int(data['漲跌'])<int(old_data['漲跌']):
send_msg += (f'風向似乎有些變化唷🎃')
else:
send_msg = f'‼️‼️‼️‼️\n風向變了~由{old_data["漲跌狀況"]}轉{emoji[0]}\n'
send_msg += f'即時價:{data["成交"]}{emoji[0]}{emoji[1]}{ups_and_down}\n'
if data['成交']>old_data['成交']:
send_msg += (f'上漲囉~~{emoji[0]} ')
else :
send_msg += (f'往下掉囉~~{emoji[0]} ')
print("發送股價變化通知",send_message(token,send_msg))
print(f'{send_msg}\n')
write_data_txt(data) #將更新資料寫進data.txt內
old_data = read_data_txt() #讀取新資料
test = False
end_time = datetime.now()
print(f"目前即時價:{data['成交']} {s}{ups_and_down}")
print("等待60s...\n")
time.sleep(60 - float(end_time.timestamp() - n_time.timestamp())) #等待用一分鐘扣掉前面執行的過程
n_time = datetime.now()
print("Exit Loop")
send_msg = "🎃收盤囉~🍉\n"
send_msg +=(f"{title}🍉\n|| {now_type} ||\n連漲連跌 : {situation} \n即時價 : {Instant_price} {emoji[0]}{emoji[1]} {ups_and_down} \n------------------------------------------------\n")
send_msg += FS(data)
print('發送收盤通知',send_message(token,send_msg))
主要透過Python結合Line Notify與Windows排成工具實現全自動運行,將Yahoo上的股價資訊爬取下來做資料整理»將整理完的數據分析,判斷數據變化給予相應的回應。