python 爬蟲玉山匯率並部署到aws lambda

2023/08/21閱讀時間約 17 分鐘

最近開了複委託打算定期定額買美股,主要因為交割戶是設定外幣帳戶交割,先前設置了常用銀行的外幣到價通知,但是美金最近一直逆空高灰,幾乎不會啟動到價通知🥲,只好一直關注銀行即期價格,但因為上班常常會忘記要看一下外幣網銀換匯優惠,故想說練習python之餘,並順便做個爬蟲將資料發送到line群組,方便上班時看一下網銀優惠價格,以下是練習實作筆記供參,目前還是小菜雞,如有不對的地方歡迎指正

『實作流程』

這邊會使用github上開源工具 docker-selenium-lambda 幫助更快部署到aws lambda上,在搭配EventBridge 去指定啟動lambda的時間,於爬蟲取得匯率結果後發送line notify 到群組上

// git clone 開源工具
git clone ​https://github.com/umihico/docker-selenium-lambda.git


clone完成後可以看到工具檔案結構,這個開源專案方便我們練習aws lambda,利用最小化的方式完成功能實作,也不需擔心chrome、selenium與python造成版本衝突(python就是很容易套件衝突,哭~~),這邊實作我們不使用serverless.yaml的方式執行(主要是我還沒研究到這邊),單純只使用這邊的dockerfile檔案進行部署

圖一

圖一

接著我們要修改main.py這個檔案,一開始替我們先載入了selenium了,而def handler則是aws lambda 執行時的啟動function(這邊對應到Dockerfile的CMD [ "main.handler" ]),所以到時候程式邏輯我們會寫在這邊

圖二

圖二

這邊我習慣將chrome 設定另外寫在一個function裡,在到handler去呼叫

def get_chrome_driver():
options = webdriver.ChromeOptions()
options.binary_location = '/opt/chrome/chrome'
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument("--disable-gpu")
options.add_argument("--window-size=1280x1696")
options.add_argument("--single-process")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--disable-dev-tools")
options.add_argument("--no-zygote")
options.add_argument(f"--user-data-dir={mkdtemp()}")
options.add_argument(f"--data-path={mkdtemp()}")
options.add_argument(f"--disk-cache-dir={mkdtemp()}")
options.add_argument("--remote-debugging-port=9222")
options.add_argument("--incognito") # 無痕模式
chrome = webdriver.Chrome("/opt/chromedriver",
options=options)
return chrome

接著我們開始撰寫爬蟲玉山匯率網站程式邏輯

def handler(event=None, context=None):
driver = get_chrome_driver()
URL = "https://www.esunbank.com/zh-tw/personal/deposit/rate/forex/foreign-exchange-rates" # 玉山匯率網址

# 初始化一個空的字典
currency_dict = {}
for i in range(len(driver.find_elements(By.CLASS_NAME, 'col-auto.px-3.col-lg-5.title-item'))):
item_name = driver.find_elements(By.CLASS_NAME, 'col-auto.px-3.col-lg-5.title-item')[i].text
BBoardRate = driver.find_elements(By.CLASS_NAME, 'BBoardRate')[i].text
SBoardRate = driver.find_elements(By.CLASS_NAME, 'SBoardRate')[i].text
BuyIncreaseRate = driver.find_elements(By.CLASS_NAME, 'BuyIncreaseRate')[i].text
SellDecreaseRate = driver.find_elements(By.CLASS_NAME, 'SellDecreaseRate')[i].text
CashBBoardRate = driver.find_elements(By.CLASS_NAME, 'CashBBoardRate')[i].text
CashSBoardRate = driver.find_elements(By.CLASS_NAME, 'CashSBoardRate')[i].text
# 將貨幣資料轉存到字典
currency_info = {
'即期匯率買入': BBoardRate,
'即期匯率賣出': SBoardRate,
'網銀優惠買入': BuyIncreaseRate,
'網銀優惠賣出': SellDecreaseRate,
'現金買入': CashBBoardRate,
'現金賣出': CashSBoardRate
}

# 將取得的匯率存到 currency_dict
currency_dict[item_name] = currency_info

# 提取特定貨幣資料
currencies_to_extract = ['美元', '日圓']
selected_currency_dict = {currency: currency_dict[currency] for currency in currencies_to_extract}

撰寫程式時,有使用一些套件方法,故這邊需要import套件資料,套件使用了selenium、dotenv、pandas、requests,需要額外安裝,故還要設定dockerfile檔案,避免執行時找不到套件

from selenium import webdriver
from tempfile import mkdtemp
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from dotenv import load_dotenv
import time
import pandas as pd
import time
import requests
import os

dockerfile設定資料如下

RUN pip install requests
RUN pip install pandas
RUN pip install python-dotenv
圖三

圖三

因為這邊爬取了全部匯率,但我只需要追蹤['美元', '日圓'],額外過濾屬於美元日圓的資料,印出整理後的資料


# 提取特定貨幣資料
currencies_to_extract = ['美元', '日圓']
selected_currency_dict = {currency: currency_dict[currency] for currency in currencies_to_extract}
print(selected_currency_dict)
圖四

圖四

確定需要的資料都正常後,這邊開始設定line notify 的通知,首先先連結要通知的群組並產生權杖

LINE Notify 連結 : https://notify-bot.line.me/zh_TW/

選擇個人頁面進入,可以看到已經連動的服務

圖五

圖五

接著移到畫面下方有一個發行存取權杖,選擇發行權杖

圖六

圖六

會彈出設定頁面,要你填寫權杖名稱,這邊設定會是到時候顯示的名字(例如匯率通知),設定好後連結到你要通知的群組,並點擊發行,就可以取得權杖了,記得這邊要記得保存好權杖,因為離開後就無法再次取得

圖七

圖七

接著我們開始撰寫通知內容,這邊為了避免將token曝露出來,有使用到load_dotenv這個方法,而外創建一個環境變數

// 創建一個名為.env環境變數

touch .env​

接著指定dotenv_path路徑並使用load_dotenv方法載入,import os 並用os.getenv('LINE_NOTIFY_TOKEN'),取得寫在環境變數的檔案裡面。

這邊因為使用.env檔案,故在dockerfile裡面也需要將.env檔案複製到docker裡,可參考圖三

COPY .env ./

如果是直接clone我的專案的話,執行步驟如下

// 複製.env.example 並重新命名為 .env檔案
cp .env.example .env​

// 接著將line notify 權杖填入​.env檔案裡
LINE_NOTIFY_TOKEN = '你的權杖'
# 指定.env文件的路径
dotenv_path = '.env'

# 加载.env文件中的环境变量
load_dotenv(dotenv_path)

# 访问.env文件中的环境变量
line_notify_token = os.getenv('LINE_NOTIFY_TOKEN')


def line_notify(message):
# LINE Notify 權杖
token = line_notify_token

# HTTP 標頭參數與資料
headers = {"Authorization": "Bearer " + token}
data = {'message': message}
# 以 requests 發送 POST 請求
requests.post("https://notify-api.line.me/api/notify", headers=headers, data=data)

完成line notify通知function 後,我們在 selected_currency_dict 這行下繼續往下撰寫,這邊需要將字典轉換成字串形式塞入到message裡,接著執行line_notify通知

message = ""
for currency, info in selected_currency_dict.items():
message += f"{currency}:\n"
for key, value in info.items():
message += f"{key}: {value}\n"
message += "\n"

line_notify("\n" + message)

以上程式撰寫的部分就完成了,接著就是執行aws上的設定,首先你要先有一個aws帳號,開立帳號這邊就不細講

首先先將docker 部署到ECR上,選擇create repository

raw-image

設定你要取的名字,這邊visibility settings 我選擇不公開

raw-image

設定完後可以到前頁打勾以創建的ECR,點擊view push commands這邊會給出執行步驟讓你可以方便push 本地docker 到aws,基本上照步驟執行即可,如果是mac版本的話,指令要再加上 --platform=linux/amd64

docker build -t rate-crawler-selenium . --platform=linux/amd64
raw-image

部署完畢後點進去可以看到加上了tag lastest

raw-image

接著來到lambda創建function,點擊create function

raw-image

接著選擇container image 並點擊browse images可以選擇ECR的容器

raw-image

接著選擇下拉找到當時命名的容器名字打勾選擇image

raw-image

接著再設定兩個部分,一個選擇x86結構,根create a new role 這邊是設定他的permissions,接著往下滑有一個create function,就完成拉,接著等待部署完成後就會看到下一張圖的畫面

raw-image
raw-image

因為這邊每次執行時都會啟動一次容器執行,故這邊需要額外設定timeout時間,不然會因為容器還沒跑完,就已經timeout fail了,Memory也暫時先設定到512MB,實測預設128MB會有不足現象(之後再優化)

raw-image

接著我們執行一下 test 來這測試我們的程式碼是否有正常執行,新增一個new event,因為不用帶入JSON,我把系統預設的清除,接著按save,就會長成下面這個樣子,接著我們點擊TEST按鈕

raw-image

===============系統執行中===============

爬完匯率資料後就會正常發送到line notify 結果如下,這樣就大功完成拉

raw-image
貼心提醒:在執行爬蟲時,也要避免多次請求造成對方網站的困擾,建議不要執行太多次的請求,當個友善爬蟲者~共勉之

上述只是簡單快速練習製作出匯率爬蟲,爬蟲網站的挑選也是因為我購買外幣是使用玉山銀,所以匯率購買需要參考玉山網銀優惠賣出價格,故為了方便才需要爬下來line群組方便群組內的朋友們可以按照自己需要的價格去換外幣,供參考

這邊程式碼的部分也一併上傳到我的github哩,也歡迎大家取用下載參考,如有更好的方式也歡迎大家一起討論指教~~一起從小菜雞成為大菜雞💪💪💪

接著是設定EventBridge 去指定啟動lambda排程,利用設定crontab shell指令幫助我們處理例行性任務,但前提我們必須要先理解什麼是crontab?文章參考連結

理解 crontab 幫助處理例行性任務

參考連結

https://github.com/dale0502/rate-crawler-selenium







13會員
37內容數
學涯無止境,透過每日or每週模仿學習筆記,不管是哪些領域也好,總有一天也可以從菜雞變小雞
留言0
查看全部
發表第一個留言支持創作者!