今天終於把 Telegram Bot API 我用得到的主要功能都測完了, 終於可以用這成果來改寫我前年寫的股價爬蟲程式了, 自從 LINE Notify 於 4/1 終止服務後它也就跟著停擺了, 只好轉換平台到 Telegram. 關於 Telegram Bot API 用法參考下列索引 :
爬蟲程式都是在樹莓派 Pi 3 與 Mapleboard 的 Linux 主機上透過 crontab 定時週期性執行, 所以首先要在 Pi 3 上安裝 python-telegram-bot 套件 :
pip3 install python-telegram-bot
pi@raspberrypi:~ $ pip3 install python-telegram-bot
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting python-telegram-bot
Downloading https://files.pythonhosted.org/packages/86/ea/52fc452521483e7e31138d4d58e29b00ca3de07085bff11a823a41d56e03/python_telegram_bot-20.3-py3-none-any.whl (545kB)
Collecting httpx~=0.24.0 (from python-telegram-bot)
Downloading https://files.pythonhosted.org/packages/ec/91/e41f64f03d2a13aee7e8c819d82ee3aa7cdc484d18c0ae859742597d5aa0/httpx-0.24.1-py3-none-any.whl (75kB)
Requirement already satisfied: sniffio in ./.local/lib/python3.7/site-packages (from httpx~=0.24.0->python-telegram-bot) (1.3.1)
Requirement already satisfied: idna in /usr/lib/python3/dist-packages (from httpx~=0.24.0->python-telegram-bot) (2.6)
Requirement already satisfied: certifi in ./.local/lib/python3.7/site-packages (from httpx~=0.24.0->python-telegram-bot) (2024.2.2)
Collecting httpcore<0.18.0,>=0.15.0 (from httpx~=0.24.0->python-telegram-bot)
Downloading https://files.pythonhosted.org/packages/94/2c/2bde7ff8dd2064395555220cbf7cba79991172bf5315a07eb3ac7688d9f1/httpcore-0.17.3-py3-none-any.whl (74kB)
Requirement already satisfied: h11<0.15,>=0.13 in ./.local/lib/python3.7/site-packages (from httpcore<0.18.0,>=0.15.0->httpx~=0.24.0->python-telegram-bot) (0.14.0)
Collecting anyio<5.0,>=3.0 (from httpcore<0.18.0,>=0.15.0->httpx~=0.24.0->python-telegram-bot)
Downloading https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl (80kB)
Requirement already satisfied: typing-extensions; python_version < "3.8" in ./.local/lib/python3.7/site-packages (from h11<0.15,>=0.13->httpcore<0.18.0,>=0.15.0->httpx~=0.24.0->python-telegram-bot) (4.7.1)
Requirement already satisfied: exceptiongroup; python_version < "3.11" in ./.local/lib/python3.7/site-packages (from anyio<5.0,>=3.0->httpcore<0.18.0,>=0.15.0->httpx~=0.24.0->python-telegram-bot) (1.2.1)
anyio 3.7.1 has requirement idna>=2.8, but you'll have idna 2.6 which is incompatible.
Installing collected packages: anyio, httpcore, httpx, python-telegram-bot
Successfully installed anyio-3.7.1 httpcore-0.17.3 httpx-0.24.1 python-telegram-bot-20.3
也可以用下列指令查詢 telegram 套件版本 :
pip list | grep telegram
pi@raspberrypi:~ $ pip3 list | grep telegram
python-telegram-bot 20.3
v20.3 表示必須使用非同步方式呼叫 Bot 物件的方法.
接下來改寫股價爬蟲程式, 用 Telegram 取代 LINE Notify, 原程式參考 :
將文中的 yahoo_twstock_monitor_table.py 改寫為下面的 yahoo_twstock_monitor_table_2.py :
# yahoo_twstock_monitor_table_2.py
import time
import random
import requests
from bs4 import BeautifulSoup
import matplotlib.pyplot as plt
from datetime import datetime
import asyncio
from telegram import Bot, InputFile
def yahoo_twstock_crawler(stock):
headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) \
AppleWebKit/537.36 (KHTML, like Gecko) \
Chrome/102.0.0.0 Safari/537.36'}
url=f'https://tw.stock.yahoo.com/quote/{stock}'
r=requests.get(url, headers=headers)
soup=BeautifulSoup(r.text, 'lxml')
# 擷取股票名稱
tag=soup.find('h1', class_='C($c-link-text) Fw(b) Fz(24px) Mend(8px)')
name=tag.text
# 擷取股價
tag=soup.select('span[class*="Fz(32px) Fw(b) Lh(1) Mend(16px) D(f) Ai(c)"]')
price=float(tag[0].text)
# 擷取漲跌價
tag=soup.select('span[class*="Fz(20px) Fw(b) Lh(1.2) Mend(4px) D(f) Ai(c)"]')
if 'C($c-trend-up)' in tag[0].attrs['class']:
change_price='+' + tag[0].text
elif 'C($c-trend-down)' in tag[0].attrs['class']:
change_price='-' + tag[0].text
else:
change_price=tag[0].text
# 擷取漲跌幅
tag=soup.select('span[class*="Jc(fe) Fz(20px) Lh(1.2) Fw(b) D(f) Ai(c)"]')
change_quote=tag[0].text[1:-1]
if 'C($c-trend-up)' in tag[0].attrs['class']:
change_quote=f'(+{change_quote})'
elif 'C($c-trend-down)' in tag[0].attrs['class']:
change_quote=f'(-{change_quote})'
else:
change_quote=f'({change_quote})'
# 擷取趨勢摘要
tag=soup.select('span[class*="Fz(16px) Mb(4px)"]')
if tag:
trend=tag[0].text.split()[0]
else:
trend=''
return price, change_price, change_quote, trend, name
async def telegram_send_text(text):
bot=Bot(token=token)
try:
await bot.send_message(
chat_id=chat_id,
text=text,
parse_mode='Markdown'
)
return True
except Exception as e:
print(f'Error sending text: {e}')
return False
async def telegram_send_photo(photo_path, caption=None):
bot=Bot(token=token)
try:
with open(photo_path, 'rb') as f:
photo=InputFile(f, filename=photo_path) # 用 InputFile 包裝本機檔案
await bot.send_photo(
chat_id=chat_id,
photo=photo,
caption=caption,
parse_mode='Markdown'
)
return True
except Exception as e:
print(f'Error sending photo: {e}')
return False
plt.rcParams["font.family"]=["Microsoft JhengHei"]
plt.figure(tight_layout=True)
plt.axis('off')
columns=["代號", "成交價", "漲跌幅"]
stocks=['0050', '0056', '2330', '2303', '2412', '00894', '00878']
data=[]
msg=['股價趨勢']
for stock in stocks:
price, change_price, change_quote, trend, name=yahoo_twstock_crawler(stock)
row=[stock, f'{price} ({change_price})', change_quote[1:-1]]
print(row, name, trend)
data.append(row)
msg.append(f'{stock}({name}): {trend}')
time.sleep(random.randint(1, 5))
table=plt.table(cellText=data, colLabels=columns, loc="center",
colWidths=[0.25, 0.5, 0.25], colColours=['yellow']*3)
table.auto_set_font_size(False)
table.set_fontsize(25)
for key, cell in table.get_celld().items():
cell.set_linewidth(0.5)
cell.set_height(0.13)
if key[0] != 0:
if key[0]%2 == 0: # 判斷是否為偶數列
cell.set_facecolor('cyan')
else:
cell.set_facecolor('white')
image='yahoo_twstock_monitor.jpg'
plt.savefig(image)
token='Telegram Bot API Token'
chat_id='Telegram Chat ID'
now_str=datetime.now().strftime('%Y-%m-%d %H:%M:%S')
caption=f'目前股價 {now_str}'
if asyncio.run(telegram_send_photo(image, caption)):
print('圖片傳送成功!')
else:
print('圖片傳送失敗!')
text='\n'.join(msg)
if asyncio.run(telegram_send_text(text)):
print('訊息傳送成功!')
else:
print('訊息傳送失敗!')
此程式使用 Bot 物件的 send_message() 與 send_photo() 方法來傳送圖片與文字訊息, 注意, v.20 版以上的 telegram 套件必須使用非同步方式呼叫 Bot 物件的方法. 測試結果如下 :
>>> %Run yahoo_twstock_monitor_table_2.py
['0050', '162.35 (-3.00)', '-1.81%'] 元大台灣50 漲→跌
['0056', '32.85 (-0.29)', '-0.88%'] 元大高股息 連4漲→跌
['2330', '855.0 (-22.00)', '-2.51%'] 台積電 漲→跌
['2303', '44.95 (+0.25)', '+0.56%'] 聯電 連5漲
['2412', '128.5 (-0.50)', '-0.39%'] 中華電 漲→跌
['00894', '16.37 (-0.38)', '-2.27%'] 中信小資高價30 連4漲→跌
['00878', '19.99 (-0.18)', '-0.89%'] 國泰永續高股息 連4漲→跌
圖片傳送成功!
訊息傳送成功!
查看 Telegram App 有收到一則圖片訊息與一則文字訊息 :
將此程式上傳至 Pi 3 後要先用 chmod 修改為可執行 (x 屬性) :
pi@raspberrypi:~ $ sudo chmod +x /home/pi/yahoo_twstock_monitor_table_2.py
pi@raspberrypi:~ $ ls -l yahoo_twstock_monitor_table_2.py
-rwxr-xr-x 1 pi pi 4267 4月 17 00:54 yahoo_twstock_monitor_table_2.py
然後修改 crontab, 將原本要執行的程式改為上面這個 yahoo_twstock_monitor_table_2.py 即可定時週期性地收到報價訊息 :
pi@raspberrypi:~ $ crontab -e
crontab: installing new crontab
pi@raspberrypi:~ $ crontab -l
0 16 * * 1-5 /usr/bin/python3 /home/pi/twstock_dashboard_update.py
*/31 9-13 * * 1-5 /usr/bin/python3 /home/pi/yahoo_twstock_monitor_table_2.py
0 8,18 * * * /usr/bin/python3 /home/pi/btc_eth_prices_line_notify.py
1 12,17 * * * /usr/bin/python3 /home/pi/technews_2.py
0 9 * * * /usr/bin/python3 /home/pi/books.com.tw_66.py
0 13 * * * /usr/bin/python3 /home/pi/ksml_books_8.py
關於 crontab 用法參考 :
沒有留言 :
張貼留言