2022年7月2日 星期六

Python 學習筆記 : Line Notify 訊息推播 (三) : 圖片

在前一篇測試中使用 Line Notify 傳送 Line 貼圖, 本篇則要來測試傳送圖片, Line Notify 可傳送的圖片格式為 jpeg 與 png 兩種, 且解析度需在 2048×2048px 以下, 連同純文字與貼圖等, Line Notify 每個權杖每小時發出的推播限制為 1000 則, 參考 Line Notify API 文件 :




本系列之前的文章參考 : 



1. 使用 Curl 傳送圖片 :   

在 Linux 環境下可以使用 Curl 傳送 Line Notify 圖片, 指令與上一篇傳送貼圖的類似, 只要用 imageFile=@$ 指定圖檔位置即可, 格式如下 :

curl -X POST https://notify-api.line.me/api/notify -H "Authorization: Bearer 權杖" -F "message=文字訊息" -F "imageFile=@$圖檔位置字串"   

我先用 WinSCP 將一張貓咪圖 kitten.jpg 檔傳送到樹莓派 home@pi 下 :




例如 : 

pi@raspberrypi:~ $ ls -ls kitten.jpg    
268 -rw-r--r-- 1 pi pi 270528  7月  2 10:55 kitten.jpg     
pi@raspberrypi:~ $ image='./kitten.jpg'      
pi@raspberrypi:~ $ curl -X POST https://notify-api.line.me/api/notify -H "Authorization: Bearer ud7PaDL45fz849A0e1f5oaMCbRIkxMXapQCt7PfNkzz" -F "message=圖片測試" -F "imageFile=@$image"      
{"status":200,"message":"ok"}




可見圖片已順利送出. 


2. 使用 Python 傳送圖片 :   

利用 Python 與 HTTP 的 POST 方法可推播 Line Notify 圖片, 原本以為只要像傳送貼圖時那樣在 params 參數中指定 imageFile 屬性, 指向一個開啟的圖片二進位檔案物件即可, 但實測用 params 參數的作法是不行的 :

# 失敗的做法 : 
def notifyImage(msg, token, image):    
    url="https://notify-api.line.me/api/notify"
    headers={"Authorization": "Bearer " + token}
    payload={"message": msg, 
             "imageFile" : open(image, 'rb')}     # 無法在 params 中傳送檔案
    r=requests.post(url, headers=headers, params=payload)
    if r.status_code==requests.codes.ok:
        return '圖片發送成功!'
    else:
        return f'圖片發送失敗: {r.status_code}'

用此函式傳送圖片會出現 requests.exceptions.ConnectionError 錯誤而被遠端主機 (即 Line 伺服器) 強制關閉連線 :

>>> token="ud7PaDL45fz849A0e1f5oaMCbRIkxMXapQCt7PfNkzz"
>>> notifyImage('test', token, 'kitten.jpg')   
.....(略).....
    raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', ConnectionResetError(10054, '遠端主機已強制關閉一個現存的連線。', None, 10054, None))

正確做法是要用 POST 方法的 files 參數來指定所開啟的檔案物件, 若有同時傳文字訊息則是放在 data 參數中, 正確之程式碼如下 : 

def notifyImage(msg, token, image):
    url='https://notify-api.line.me/api/notify'
    headers={'Authorization': 'Bearer ' + token}
    data={'message': msg}
    image=open(image, 'rb')
    imageFile={'imageFile': image}
    r=requests.post(url, headers=headers, data=data, files=imageFile)
    if r.status_code==requests.codes.ok:
        return '圖片發送成功!'
    else:
        return f'圖片發送失敗: {r.status_code}' 

>>> token="ud7PaDL45fz849A0e1f5oaMCbRIkxMXapQCt7PfNkzz"
>>> notifyImage('test', token, 'kitten.jpg')  

這樣就可以順利傳送圖片了 : 




這個功能很棒, 可以應用到許多生活實用場景, 例如下面這篇文章的作者就用 Line Notify 圖片推播加上 crontab 每日定時傳送吉娃娃的早安圖, 非常有創意且提供完整程式碼 :


也可以配合 pyautogui 套件用來擷取螢幕截圖後推播到 Line, 作法參考下面這篇文章 :


另外在股票投資方面也可以用來傳送分析圖表, 因為 Line 無法像 email 那樣傳送 HTML 格式內容 (只能純文字), 但可以用 matplotlib 等套件將資料繪製成圖表推播到 Line. 例如 :

# send_2330.tw_image.py
import twstock
import requests
import matplotlib.pyplot as plt

def notifyImage(msg, token, image):
    url='https://notify-api.line.me/api/notify'
    headers={'Authorization': 'Bearer ' + token}
    data={'message': msg}
    image=open(image, 'rb')
    imageFile={'imageFile': image}
    r=requests.post(url, headers=headers, data=data, files=imageFile)
    if r.status_code==requests.codes.ok:
        return '圖片發送成功!'
    else:
        return f'圖片發送失敗: {r.status_code}' 

plt.rcParams["font.family"]=["Microsoft JhengHei"]   # 中文字型
plt.title('台積電近 31 日股價')
stock2330=twstock.Stock('2330')    
plt.plot(stock2330.price)      # 取得近 31 日股價串列
plt.grid(True)
plt.savefig('2330tw.jpg')       # 將圖存成 JPEG 檔
token="ud7PaDL45fz849A0e1f5oaMCbRIkxMXapQCt7PfNkzz"
notifyImage('台積電 2330', token, '2330tw.jpg')

此例使用 twstock 套件來取得台積電股價, 以 Matplotlib 把近 31 日股價變化圖存成 JPEG 檔後呼叫 notifyImage() 將圖檔推播出去. 關於 twstock 套件用法參考 :


而 Matplotlib 繪圖則參考 :


結果如下 : 




嗯, 效果還不錯. 


沒有留言 :