在前一篇測試中已在 Mapleboard 的 Ubuntu Mate 上成功地利用 Firefox 與 Chromium 執行 Selenium 爬蟲程式, 經觀察 Chromium 的執行速度比 Firefox 快一倍, 因此正式上線時會使用 Chromium. 本篇是此任務的結尾, 目標是將擷取到的市圖 "我的書房" 網頁中的借閱與預約書籍資訊做進一步處理, 萃取出下列資料後用 Line Notify 推播到 "市圖借書" 群組 :
- 今日到期書目與續借次數
- 明日到期書目與續借次數
- 逾期書目與續借次數
- 近 7 日到期書目與續借次數
- 預約書目與順位
本系列之前的筆記參考 :
六. 借閱與預約資訊處理 :
先來計算借閱書目是否逾期, 這可以利用到期日與今日的 datetime 物件相減的結果來判斷, 到期日減今日如果值為 0 表示此書為今日到期, 負數表示逾期, -1 表示已逾期一天, -2 為逾期兩天 ... 如果是正數表示尚未到期. 這個計算要用到 Python 內建的 datetime 套件中的兩個模組 : datetime 與 timedelta :
>>> from datetime import datetime, timedelta
datetime 模組常用函式如下 :
datetime 模組常用函式 | 說明 |
now() | 傳回目前日期時間之 datetime 物件 |
today() | 傳回今日之 datetime 物件 |
datetime 物件的常用方法如下 :
datetime 物件常用方法 | 說明 |
strftime(格式字串) | 將 datetime 物件依格式字串 (例如 '%Y%m%d') 轉成字串 |
strptime(日期時間字串, 格式字串) | 將日期時間字串轉成 datetime 物件 |
先使用一個借閱紀錄範例來測試 :
>>> borrow_books=[{'book_name': 'PyTorch深度學習攻略 : 核心開發者親授!',
'due_date': '2024-05-27', 'due_times': '2'},
{'book_name': '一行指令學Python : 用機器學習掌握人工智慧',
'due_date': '2024-05-28', 'due_times': '1'},
{'book_name': '用Python學AIoT智慧聯網',
'due_date': '2024-05-29', 'due_times': '0'}]
以其中第一本書的到期日為例 :
>>> due_date=borrow_books[0]['due_date']
>>> due_date
'2024-05-27'
呼叫 datetime.strptime() 函式將此格式之日期字串轉成 datetime 物件 :
>>> due_date=datetime.strptime(due_date, '%Y-%m-%d')
>>> due_date
datetime.datetime(2024, 5, 27, 0, 0)
呼叫 datetime.today() 函式會傳回今日 (現在) 的 datetime 物件 :
>>> datetime.today()
datetime.datetime(2024, 5, 28, 15, 3, 21, 200197)
但計算日期差不需要時間部分, 只要呼叫 strptime() 方法並傳入格式字串 '%Y-%m-%d' 就可去除時間部分, 傳回日期字串 :
>>> today_str=datetime.today().strftime('%Y-%m-%d')
>>> today_str
'2024-05-28'
但要做日期相減須轉回 datetime 物件 :
>>> today=datetime.strptime(today_str, "%Y-%m-%d")
>>> today
datetime.datetime(2024, 5, 28, 0, 0)
用 due_date 去減 today 即可得到一個表示日期差的 timedelta 物件 :
>>> due_date-today
datetime.timedelta(days=-1)
若要取得日期差之整數值可利用其 days 屬性 :
>>> (due_date-today).days
-1
到期日與今日差為 -1 表示已經逾期一天了. 參考 :
寫一個迴圈來走訪上面的借閱紀錄範例 :
>>> for book in borrow_books:
book_name=book['book_name']
due_date=book['due_date']
due_date=datetime.strptime(due_date, '%Y-%m-%d')
today_str=datetime.today().strftime('%Y-%m-%d')
today=datetime.strptime(today_str, "%Y-%m-%d")
delta=(due_date-today).days
if delta < 0:
print(f'{book_name} 已逾期 {abs(delta)} 天')
elif delta == 0:
print(f'{book_name} 今日到期')
elif delta == 1:
print(f'{book_name} 明日到期')
結果如下 :
PyTorch深度學習攻略 : 核心開發者親授! 已逾期 1 天
一行指令學Python : 用機器學習掌握人工智慧 今日到期
用Python學AIoT智慧聯網 明日到期
因為今日是 2024-05-28, 第一本書到期日為 2024-05-27 故顯示 '逾期 1 天'; 第二本書到期日為 2024-05-28 故顯示 '今日到期'; 第三本書到期日為 2024-05-29 故顯示 '明日到期'.
七. 用 Line Notify 推播借閱與預約資訊 :
前面的測試已完全擷取到個人書房借閱與預約資訊, 接下來要將這些訊息透過 Line Notify 推播到手機 Line 聊天室. 首先在手機 Line 中建立一個個人群組 "市圖借書預約資訊" (也可以推播到個人 Line 帳號, 但那樣會與其他個人聊天訊息混在一起) :
輸入群組名稱後按右上角的 "建立" 鈕即可 :
可以加入所有想獲得此推播訊息的人進入群組, 但最重要的是要將 Line Notify 加進來, 這樣程式發送的訊息才會被送進此群組. 按右上方的三條槓按鈕進入群組的設定頁面 :
按 "邀請" 鈕後, 在下列頁面中點選 Line Notify 邀請它進來群組內 :
可見 Line Notify 已加入此群組 :
然後登入 Line Notify 網站 :
按右上角帳號名稱會出現下拉式選單, 點選 "個人頁面" :
將個人頁面拉到最底下, 按 "發行權仗" 鈕 :
在上面輸入權仗名稱 "市圖借書預約資訊", 選擇要接收要接收訊息之聊天室為與權仗同名的 "市圖借書預約資訊" 群組, 然後按底下的 "發行" 鈕就會獲得一個權仗 :
先按左邊的複製鈕將權杖複製到純文字檔中儲存才能關閉此視窗 :
這樣就可以來撰寫 Line Notify 程式碼了 :
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.options import Options
import re
from datetime import datetime
import time
import requests
def line_notify(msg, token):
url="https://notify-api.line.me/api/notify"
headers={"Authorization": "Bearer " + token,
"Content-Type": "application/x-www-form-urlencoded"
}
payload={"message": msg}
r=requests.post(url, headers=headers, params=payload)
return r.status_code
def get_books(account, password):
try:
# 登入我的書房
options=Options()
options.add_argument("--headless")
driverpath='geckodriver.exe'
browser=webdriver.Firefox(options=options)
browser.implicitly_wait(20)
browser.get("https://webpacx.ksml.edu.tw/personal/")
loginid=browser.find_element(By.ID, "loginid")
loginid.send_keys(account)
pincode=browser.find_element(By.ID, 'pincode')
pincode.send_keys(password)
div_btn_grp=browser.find_element(By.CLASS_NAME, 'btn_grp')
login_btn=div_btn_grp.find_element(By.TAG_NAME, 'input')
browser.implicitly_wait(20)
login_btn.click()
# 擷取借閱紀錄
div_redblock=browser.find_element(By.CLASS_NAME, 'redblock')
browser.implicitly_wait(20)
div_redblock.click()
books=browser.find_elements(By.CLASS_NAME, 'bookdata')
borrow_books=[]
for book in books:
item=dict()
book_name=book.find_element(By.XPATH, './h2/a').text
item['book_name']=book_name.replace('/', '').strip()
pattern=r'\d{4}-\d{2}-\d{2}'
due_date=book.find_element(By.XPATH, './ul[4]/li[2]').text
item['due_date']=re.findall(pattern, due_date)[0]
due_times=book.find_element(By.XPATH, './ul[5]/li[1]').text
item['due_times']=re.findall(r'\d{1}', due_times)[0]
borrow_books.append(item)
browser.back() # 回上一頁
# 擷取預約紀錄
div_blueblock=browser.find_element(By.CLASS_NAME, 'blueblock')
browser.implicitly_wait(20)
div_blueblock.click()
books=browser.find_elements(By.CLASS_NAME, 'bookdata')
reserve_books=[]
for book in books:
item=dict()
book_name=book.find_element(By.XPATH, './h2/a').text
item['book_name']=book_name.replace('/', '').strip()
sequence=book.find_element(By.XPATH, './ul[7]/li[1]').text
item['sequence']=re.findall(r'\d+', sequence)[0]
reserve_books.append(item)
browser.close()
return (borrow_books, reserve_books)
except Exception as e:
print(e)
return None, None
if __name__ == '__main__':
start=time.time()
token='7CLpVmFpNihuN6GB0bQcc5M1nOhpAtony1966QFMgzz' # 範例權仗
users=[['family87', '123456'],
['amy08123', '123456'],
['kelly19', '123456'],
['peter120', '123456'],
['shinping92', '123456'],
['daddy587', '123456']] # 範例帳號
for user in users: # 走訪每個帳號
account=user[0]
password=user[1]
borrow_books, reserve_books=get_books(account, password)
if borrow_books:
borrow=[]
for book in borrow_books:
book_name=book['book_name']
due_times=book['due_times']
due_date=book['due_date']
due_date=datetime.strptime(due_date, '%Y-%m-%d')
today_str=datetime.today().strftime('%Y-%m-%d')
today=datetime.strptime(today_str, "%Y-%m-%d")
delta=(due_date-today).days
if delta < 0:
msg=f'▶ {book_name} (逾期 {abs(delta)} 天, ' +\
'續借次數 {due_times})'
borrow.append(msg)
elif delta == 0: # 今日到期之書
msg=f'▶ {book_name} (今日到期, 續借次數 {due_times})'
borrow.append(msg)
elif delta == 1: # 明日到期之書
msg=f'▶ {book_name} (明日到期, 續借次數 {due_times})'
borrow.append(msg)
elif 1 < delta < 7: # 2~7 日內到期之書
msg=f'▶ {book_name} ({book["due_date"]} 到期, '\
f'續借次數 {due_times})'
borrow.append(msg)
if len(borrow) != 0: # 有 7 日內到期之書
borrow.insert(0, f'\n❖ {account} 的借閱 :')
msg='\n'.join(borrow)
code=line_notify(msg, token)
if code==200:
print('Line 訊息發送成功!')
else:
print(f'Line 訊息發送失敗! (code={code})')
if reserve_books: # 有預約書才處理
reserve=[] # 儲存處理後的預約書
i=1
for book in reserve_books: # 走訪每本預約書
book_name=book['book_name']
sequence=book['sequence']
this_year=str(datetime.today().year) # 取得今年西元年
if sequence == this_year:
msg=f'{i}. {book_name} (已到館)'
else:
msg=f'{i}. {book_name} (順位 {sequence})'
reserve.append(msg)
i += 1
if len(reserve) != 0:
reserve.insert(0, f'\n❖ {account} 的預約 :')
msg='\n'.join(reserve)
code=line_notify(msg, token)
if code==200:
print('Line 訊息發送成功!')
else:
print(f'Line 訊息發送失敗! (code={code})')
end=time.time()
print(f'執行時間:{end-start}')
此處的 token 變數即上面為了傳訊息到 "市圖借書預約資訊" 群組所申請的權仗 (此為範例而已), users 是記錄借書帳密的二維串列, 第一個元素是帳號, 第二個是密碼, 使用迴圈走訪此串列, 依序用各使用者之帳密呼叫 get_books() 去擷取市圖 "我的書房" 的借閱與預約資訊, 它會傳回兩個字典 : borrow_books 與 reserve_books, 分別用來儲存借閱資訊與預約資訊, 無資料則傳回 None, None. 傳回資訊經過處理後串成字串呼叫 line_notify() 推播至群組, 結果如下 :
八. 在 Mapleboard 上佈署爬蟲程式 :
由於我的兩塊 Pi 3 的桌面怪怪的, Putty 遠端存取 OK, 但用 VNC 做遠端開發因程式集選單要很久才會打開, 所以我這次把爬蟲改為佈署到 Mapleboard 上用 Chomium 的 WebDriver 來跑 Selenium 爬蟲, 最後設定 Chrontab 定時於每天下午 4 點執行, 作法與在樹莓派幾乎相同 (預設使用者目錄為 /home/使用者, 樹莓派是 /home/pi).
關於在 Mapleboard 上跑 Selenium 的測試參考 :
由於在 Mapleboard 跑 Chromium 速度比 Firefox 快, 所以將上面在 Win11 + Firefox 上跑的程式依據下面兩篇改寫為 Chromium 版 :
# ksml_books_7.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
import re
from datetime import datetime
import time
import requests
def line_notify(msg, token):
url="https://notify-api.line.me/api/notify"
headers={"Authorization": "Bearer " + token,
"Content-Type": "application/x-www-form-urlencoded"
}
payload={"message": msg}
r=requests.post(url, headers=headers, params=payload)
return r.status_code
def get_books(account, password):
try:
# 登入我的書房
options=Options()
options.add_argument("--headless")
driverpath='/usr/lib/chromium-browser/chromedriver'
service=Service(driverpath)
browser=webdriver.Chrome(options=options, service=service)
browser.implicitly_wait(20)
browser.get("https://webpacx.ksml.edu.tw/personal/")
loginid=browser.find_element(By.ID, "loginid")
loginid.send_keys(account)
pincode=browser.find_element(By.ID, 'pincode')
pincode.send_keys(password)
div_btn_grp=browser.find_element(By.CLASS_NAME, 'btn_grp')
login_btn=div_btn_grp.find_element(By.TAG_NAME, 'input')
browser.implicitly_wait(20)
login_btn.click()
# 擷取借閱紀錄
div_redblock=browser.find_element(By.CLASS_NAME, 'redblock')
browser.implicitly_wait(20)
div_redblock.click()
books=browser.find_elements(By.CLASS_NAME, 'bookdata')
borrow_books=[]
for book in books:
item=dict()
book_name=book.find_element(By.XPATH, './h2/a').text
item['book_name']=book_name.replace('/', '').strip()
pattern=r'\d{4}-\d{2}-\d{2}'
due_date=book.find_element(By.XPATH, './ul[4]/li[2]').text
item['due_date']=re.findall(pattern, due_date)[0]
due_times=book.find_element(By.XPATH, './ul[5]/li[1]').text
item['due_times']=re.findall(r'\d{1}', due_times)[0]
borrow_books.append(item)
browser.back() # 回上一頁
# 擷取預約紀錄
div_blueblock=browser.find_element(By.CLASS_NAME, 'blueblock')
browser.implicitly_wait(20)
div_blueblock.click()
books=browser.find_elements(By.CLASS_NAME, 'bookdata')
reserve_books=[]
for book in books:
item=dict()
book_name=book.find_element(By.XPATH, './h2/a').text
item['book_name']=book_name.replace('/', '').strip()
sequence=book.find_element(By.XPATH, './ul[7]/li[1]').text
item['sequence']=re.findall(r'\d+', sequence)[0]
reserve_books.append(item)
browser.close()
return (borrow_books, reserve_books)
except Exception as e:
print(e)
return None, None
if __name__ == '__main__':
start=time.time()
token='7CLpVmFpNihuN6GB0bQcc5M1nOhpAtony1966QFMgzz' # 範例權仗
users=[['family87', '123456'],
['amy08123', '123456'],
['kelly19', '123456'],
['peter120', '123456'],
['shinping92', '123456'],
['daddy587', '123456']] # 範例帳號
for user in users:
account=user[0]
password=user[1]
borrow_books, reserve_books=get_books(account, password)
if borrow_books: # 有借書, 不是傳回 None
borrow=[] # 儲存處理過的借書資訊
for book in borrow_books: # 走訪借書串列
book_name=book['book_name']
due_times=book['due_times']
due_date=book['due_date']
due_date=datetime.strptime(due_date, '%Y-%m-%d') # 轉成 datetime 物件
today_str=datetime.today().strftime('%Y-%m-%d') # 轉成日期字串去除時間
today=datetime.strptime(today_str, "%Y-%m-%d") # 轉回 datetime 物件
delta=(due_date-today).days # 計算逾期天數
if delta < 0: # 借書逾期了
msg=f'▶ {book_name} (逾期 {abs(delta)} 天, ' +\
'續借次數 {due_times})'
borrow.append(msg)
elif delta == 0: # 今日到期
msg=f'▶ {book_name} (今日到期, 續借次數 {due_times})'
borrow.append(msg)
elif delta == 1: # 明日到期
msg=f'▶ {book_name} (明日到期, 續借次數 {due_times})'
borrow.append(msg)
elif 1 < delta < 7: # 2~7 日內到期
msg=f'▶ {book_name} ({book["due_date"]} 到期, '\
f'續借次數 {due_times})'
borrow.append(msg)
if len(borrow) != 0: # 有處理過的借書資料
borrow.insert(0, f'\n❖ {account} 的借閱 :')
msg='\n'.join(borrow)
code=line_notify(msg, token)
if code==200:
print('Line 訊息發送成功!')
else:
print(f'Line 訊息發送失敗! (code={code})')
if reserve_books: # 有預約書, 不是傳回 None
reserve=[] # 儲存處理過的預約資訊
i=1 # 計數器
for book in reserve_books: # 走訪預約書串列
book_name=book['book_name']
sequence=book['sequence']
this_year=str(datetime.today().year) # 今年年分
if sequence == this_year: # 預約書到館 sequence 欄會抓到今年年分
msg=f'{i}. {book_name} (已到館)'
else:
msg=f'{i}. {book_name} (順位 {sequence})'
reserve.append(msg)
i += 1
if len(reserve) != 0: # 有處理過之預約資料
reserve.insert(0, f'\n❖ {account} 的預約 :')
msg='\n'.join(reserve)
code=line_notify(msg, token)
if code==200:
print('Line 訊息發送成功!')
else:
print(f'Line 訊息發送失敗! (code={code})')
end=time.time()
print(f'執行時間:{end-start}')
此檔案存放在 /home/tony1966/python 下, 這要用在編輯 Crontab 時要用到 :
tony1966@LX2438:~/python$ pwd
/home/tony1966/python
首先要用 chmod 指令將此程式檔改為可執行 :
tony1966@LX2438:~/python$ sudo chmod +x ksml_books_7.py
tony1966@LX2438:~/python$ ls -ls ksml_books_7.py
8 -rwxrwxr-x 1 tony1966 tony1966 5845 May 29 23:38 ksml_books_7.py
先手動下指令測試看看 :
tony1966@LX2438:~/python$ /usr/bin/python3 /home/tony1966/python/ksml_books_7.py
Line 訊息發送成功!
Line 訊息發送成功!
Line 訊息發送成功!
Line 訊息發送成功!
Line 訊息發送成功!
Line 訊息發送成功!
Line 訊息發送成功!
Line 訊息發送成功!
Line 訊息發送成功!
執行時間:161.23561120033264
看起來沒問題, 然後用 crontab -e 指令編輯 Cron table :
tony1966@LX2438:~/python$ crontab -e
no crontab for tony1966 - using an empty one
Select an editor. To change later, run 'select-editor'.
1. /bin/nano <---- easiest (選 1 用 nano 編輯 Crontab)
2. /usr/bin/vim.tiny
3. /usr/bin/code
4. /bin/ed
Choose 1-4 [1]: 1
這會開啟 Nano 來編輯 Cron table, 在最底下輸入 :
0 16 * * * /usr/bin/python3 /home/tony1966/python/ksml_books_7.py
這表示要電腦在每天下午 4 點執行 ksml_books_7.py, 關於 Crontab 用法參考 :
然後按 Ctrl + O, 按 Enter 存檔後按 Ctrl + X 跳出 Nano.
忙了一周終於把長久以來想做的事給完成了! 了了一樁心願, 而且透過此爬蟲任務也深刻地理解 Selenium 強大的功能, 也學會了 XPATH 用法, 哎呀, 真是一舉多得啊!
2024-06-05 補充 :
今天參考下面網站的網頁圖示對送出訊息樣式 (主要是項目的標示) 做了一些修改 :
程式修改部分為借閱之 delta :
if delta < 0:
msg=f'🅧 {book_name} (逾期 {abs(delta)} 天, ' +\
'續借次數 {due_times})'
borrow.append(msg)
elif delta == 0:
msg=f'❶ {book_name} (今日到期, 續借次數 {due_times})'
borrow.append(msg)
elif delta == 1:
msg=f'❷ {book_name} (明日到期, 續借次數 {due_times})'
borrow.append(msg)
elif delta == 2:
msg=f'❸ {book_name} (後天到期, 續借次數 {due_times})'
borrow.append(msg)
elif 2 < delta < 8:
msg=f'▶ {book_name} ({book["due_date"]} 到期, '\
f'續借次數 {due_times})'
borrow.append(msg)
❶ 表示當日到期; ❷ 表示明日到期; 新增 ❸ 為後天到期, 其餘至第七日才使用 ▶ 符號.
預約書項目符號修改部分 :
i=0
j=['①', '②', '③', '④', '⑤']
for book in reserve_books:
book_name=book['book_name']
sequence=book['sequence']
this_year=str(datetime.today().year)
if sequence == this_year:
msg=f'{j[i]} {book_name} (已到館)'
else:
msg=f'{j[i]} {book_name} (順位 {sequence})'
reserve.append(msg)
i += 1
此處增加一個 j 串列來儲存預約書數量, i 初始值從 1 改為 0.
2024-06-06 補充 :
我覺得上面修改的項目符號有點不合理, 借閱書當日到期應該顯示 ⓿ 才對, 因為已經不足一天, 明日到期才是 ❶. 另外, 到館之預約書改用黑底數字標示, 到期日 3 日以上的標示改用 ✦ 符號, 程式碼再度修改如下, 借閱書部分 :
if delta < 0:
msg=f'🅧 {book_name} (逾期 {abs(delta)} 天, ' +\
'續借次數 {due_times})'
borrow.append(msg)
elif delta == 0:
msg=f'⓿ {book_name} (今日到期, 續借次數 {due_times})'
borrow.append(msg)
elif delta == 1:
msg=f'❶ {book_name} (明日到期, 續借次數 {due_times})'
borrow.append(msg)
elif delta == 2:
msg=f'❷ {book_name} (後天到期, 續借次數 {due_times})'
borrow.append(msg)
elif 2 < delta < 8:
msg=f'✦ {book_name} ({book["due_date"]} 到期, '\
f'續借次數 {due_times})'
borrow.append(msg)
🅧 表示已逾期; ⓿ 表示當日到期; ❶ 表示明日到期; ❷ 為後天到期; 其餘至第七日才使用 ✦ 符號.
預約書顯示部分 :
i=0
j=['①', '②', '③', '④', '⑤']
k=['❶', '❷', '❸', '❹', '❺']
for book in reserve_books:
book_name=book['book_name']
sequence=book['sequence']
this_year=str(datetime.today().year)
if sequence == this_year:
msg=f'{k[i]} {book_name} (已到館)'
else:
msg=f'{j[i]} {book_name} (順位 {sequence})'
reserve.append(msg)
i += 1
此處新增一個 k 串列儲存黑底的 1~5, 當預約書為已到館狀態就用 k 串列顯示, 否則用 j 串列, 結果如下 :
經過以上修改後的外觀總算讓我滿意了.
2024-06-16 補充 :
由於發現一些小問題, 所以今天對程式做了一些修補, 一是當借書逾期時 due_times 欄位變成無值, 直接顯示變數名稱 {due_times}; 二是已到館的預約書只顯示 "已到館", 如果能加上取書的保留期限那就更完美了, 三是刪除了多餘的 implicitly_wait() 呼叫, 此方法只要在 WebDriver 物件建立後呼叫一次即可.
逾期的書一定要先還, 因此已續借次數沒有意義, 解決辦法就是直接拿掉逾期書的 {due_times} 輸出, 只顯示已逾期幾天 :
if delta < 0:
msg=f'🅧 {book_name} (逾期 {abs(delta)} 天)'
borrow.append(msg)
至於新增已到館預約書之保留期限日期, 我修改了判斷預約書是否為已到館之邏輯, 之前是用 sequnce 欄位, 因為預約中書籍的順位 sequence 的 XPATH 為 "./ul[7]/li[1]", 此位置在已到館書籍則為 "流通狀態", 裡面包著的 span 元素其內容就是保留期限 :
已到館的書順位就是 0, 此資訊不重要, 因此可以利用 XPATH="./ul[7]/li[1]" 這個原本是 sequence 順位的欄位來判別是否已到館, 如果 span 元素內容含有 "預約待取" 字樣表示已到館, 那麼就用正規式擷取後面的保留期限, 程式碼修改如下 :
sequence=book.find_element(By.XPATH, './ul[7]/li[1]').text
if '預約待取' in sequence: # 已到館
item['ready_for_pickup']=True # 已到館
reg=r'\d{4}-\d{2}-\d{2}' # 保留期限日期的正規式
item['expiration']=re.findall(reg, sequence)[0]
item['sequence']='0' # 預約順位不重要設為 0
else: # 預約中
item['ready_for_pickup']=False # 預約中
item['expiration']='' # 預約中保留期限日期無意義設為 ''
item['sequence']=re.findall(r'\d+', sequence)[0] # 取出目前順位
reserve_books.append(item)
此處 item 字典新增 ready_to_pickup 與 expiration 欄位, 前者值為 True/False 分別表示 "已到館"/預約中", 後者則用來儲存已到館書的保留期限.
主程式中處理預約書的部分修改為 :
for book in reserve_books:
book_name=book['book_name']
sequence=book['sequence']
ready_for_pickup=book['ready_for_pickup'] # 是否已到館
expiration=book['expiration'] # 保留期限日期
if ready_for_pickup: # 已到館
msg=f'{k[i]} {book_name} (已到館, 保留期限 {expiration})'
else:
msg=f'{j[i]} {book_name} (順位 {sequence})'
reserve.append(msg)
i += 1
經過這樣調整後程式的邏輯就更明確了, 結果也符合要求 :
佈署於 Mapleboard 的程式碼也隨之更新 (帳號密碼權杖等均為虛構) :