讓LINE幫忙提醒PChome口罩可購買狀態 – WIN10系統篇

使用幾乎人手一台的個人電腦筆電來定時關注網站商品是否開始販售或特價,並利用LINE的即時推撥功能隨時通知,讓我們能順利買到特價品


觀念篇中(如果沒有看過請務必前往後再回到這篇教學)有提到整個運作的原理跟流程

  1. 用flask建立網站建立與linebot API間的通訊
  2. 收到指令後,使用selenium開啟PChome的網頁,再利用BeautifulSoup爬蟲資料
  3. 比對網頁內容是否有變動,若是有變動即代表商品正在開賣或價格有變動
  4. 利用linebot的 REPLY_MESSAGE 與 PUSH_MESSAGE 在LINE端進行推播提醒

在WIN10系統下的桌機或筆電環境(以下簡稱PC)的設定也是依照上述,而為了讓LINE API能夠透過網際網路連線到PC,就必須要增加一項設定:

5. 使用ngrok 建立PC的SSL連線

在開始之前要在PC上確認已經安裝Python3的版本,而後續 flask建立網站與linebot API的設定步驟可以直接參考觀念篇的STEP 1說明。

完成Flask與linebot API的安裝設定後,接下來的 selenium與BeautifulSoup設定也是直接參考觀念篇的STEP 2說明,而其中在Chrome WebDriver的安裝上須要從chromium.org下載,而下載版本要跟安裝在PC上的Chrome瀏覽器的版本相同並選擇 chromedriver_win32.zip 檔名下載,下載完成後解壓縮會得到一個檔案”chromedriver.exe”,並放置於程式py檔的資料夾內,我們暫時就放在D:\My Works下。

如果後續chrome版本有更新,WebDriver也必須同步更新以免在無法執行,除了手動更新WebDriver版本外,也可以參考這篇教學文達到自動更新。

為了能夠與網際網路連線這時就利用到ngrok,ngrok 提供讓內網伺服器與外界溝通的一個服務,也就是會提供一個HTTPS的網址讓RPI可以與LINE服務溝通。

先到ngrok的網站註冊一個帳號,完成註冊後它會給你一個token,在使用ngrok時是不需要帳號密碼而是使用token跟帳號做連結的。再來到它的程式下載頁面去下載檔案並解壓縮,方便起見我們將解壓縮後的執行檔也一起放在程式py檔的D:\My Works資料夾內。

程式的部分基本上還是使用在觀念篇中的完整程式碼,但有做以下的調整:

  • 新增dir_path這個變數設定,可以自動讀取py檔所在的資料夾位置
  • WebDriver的位置用dir_path這個變數(不用費心設定絕對位置)
  • 最後一行改為app.run(host='127.0.0.1', port=5000,debug=True)

適用於PC的完整範例程式碼如下:

from flask import Flask, request, abort
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
import time, os
from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import *
  
# "PaymentContainer" => 價格有無變動 / 或可用折價券
# "fieldset_box orignbutton" => 有無貨
HTMLs=[ 
    ["https://24h.pchome.com.tw/prod/DABCE5-1900AQKMT","ul","class","fieldset_box orignbutton",""],
    ["https://24h.pchome.com.tw/prod/DYAM2M-A900AHXUD","div","id","PaymentContainer",""]
]
  
# Channel Access Token
line_bot_api = LineBotApi('YOUR_CHANNEL_ACCESS_TOKEN')
# Channel Secret
handler = WebhookHandler('YOUR_CHANNEL_SECRET')

try:
    dir_path = os.path.dirname(os.path.abspath(__file__))
except NameError: 
    import sys
    dir_path = os.path.dirname(os.path.abspath(sys.argv[0]))

options = Options()
options.add_argument('--headless')       
options.add_argument('--disable-setuid-sandbox') 
options.add_argument("--disable-notifications")
options.add_argument('--window-size=1920,1080')
options.add_experimental_option("excludeSwitches", ["enable-logging"])
options.add_argument('disable-blink-features=AutomationControlled')
options.add_argument('user-agent=Type user agent here')
  
chrome = webdriver.Chrome(dir_path+'\\chromedriver', options=options)
  
doGrap = 0
  
app = Flask(__name__)
  
def pageview(url, view_item, view_ID, view_contain):
    global chrome
    chrome.get(url)
    time.sleep(3)
      
    chrome.execute_script("window.scrollTo(0,document.body.scrollHeight)")
    soup = BeautifulSoup(chrome.page_source, 'html.parser')
    mainBlock = soup.find(view_item,{view_ID: view_contain})
    return mainBlock
  
# 監聽所有來自 /callback 的 Post Request
@app.route("/callback", methods=['POST'])
def callback():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']
    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)
      
    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        print("Invalid signature. Please check your channel access token/channel secret.")
        abort(400)        
    return 'OK'
  
# 處理訊息
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    global doGrap
    msg = event.message.text
    if msg == "Go":     
        doGrap = 1
        line_bot_api.reply_message(event.reply_token, TextSendMessage(text='start grapping!\n(with '+str(len(HTMLs))+' websites...)'))
        while doGrap:
            for thePage in HTMLs:
                print(thePage[0])
                hpage = pageview(thePage[0], thePage[1], thePage[2], thePage[3])
                if thePage[4]!='' and hpage != thePage[4]:
                    line_bot_api.push_message('YOUR_USER_ID', TextSendMessage(text='Page changed!\n'+str(thePage[0])))
                    print("change!!!!!")
                thePage[4] = hpage
                time.sleep(1)
            time.sleep(30)
    elif msg == "Stop":
        line_bot_api.reply_message(event.reply_token, TextSendMessage(text='stop!'))
        print("stop!")
        doGrap = 0    
  
if __name__ == "__main__":
    app.run(host='127.0.0.1', port=5000,debug=True)

接下來我們要做3件事讓PC與LINE可以連線:1.啟動ngrok2.設定LINE API的 Webhook URL3.執行python程式

1. 啟動ngrok:開啟”命令提示字元”,利用CMD指令將移到D:\My Works,輸入以下兩個指令(第一個指令可以直接複製ngrok網頁提供的使用指令):

ngrok authtoken XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 

ngrok http 5000

如果執行成功,就會出現以下畫面,裡面會有一個HTTPS網址,這個就是可以連結到PC的網址。

2.設定LINE API的 Webhook URL:來到LINE Developers網頁,在Messaging API裡面可以找到Webhook settings裡的Webhook URL 如下圖,將ngrok給的網址填入並勾選下方Use webhook的設定,這裡要注意一點,ngrok網址後面請加上/callback,以免出現404 NOT FOUND的錯誤。

3.執行python程式:這裡將上面的python碼存成app_PC.py檔,並開啟第2個“命令提示字元”視窗,輸入指令:

python3 app_PC.py

這樣就完成整個PC與LINE之間的通訊功能,這時在LINE端的聊天室輸入”Go”後,LINE就可以隨時幫我們監看PChome購物有沒有商品上架或是價格變動,讓我們能順利的買到東西。

ref: Office 指南