From b4a8c8dbd4a5ad439be44de43871b6094104d806 Mon Sep 17 00:00:00 2001 From: Victor Chang Date: Fri, 28 Feb 2025 03:48:54 +0000 Subject: [PATCH] first commit --- README.md | 2 + __pycache__/screenshot.cpython-38.pyc | Bin 0 -> 1240 bytes main.py | 148 ++++++++++++++++++++++++++ screenshot.py | 39 +++++++ 4 files changed, 189 insertions(+) create mode 100644 README.md create mode 100644 __pycache__/screenshot.cpython-38.pyc create mode 100755 main.py create mode 100755 screenshot.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..ce1b554 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +Run main.py +Monitor website every 2 hours and send Line message to target groupe if updates diff --git a/__pycache__/screenshot.cpython-38.pyc b/__pycache__/screenshot.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ab8281c10f684aeed6b5e5b6f4cbafb0eb875ab6 GIT binary patch literal 1240 zcmb7E&2rN^6qaH;Nln_)1;Y$0GcbkB;Ge+U0)_B1h2b*HO&7fvhHN~FB^>qIma&wi z^|Y(9qk&nH{|tghM!#zyaJ{LMn>yEe{` z1{hCZ%54x7QJkO@4>8tyBWa|@(5Q7IF^48Ksr3O3E!L#Xe;dUXvrZ78#vbane!zaz z#nsA;jcCEAtN^36n=39dIfyiRHVjbo+<_^-fKccJ9it<3iYfjCxofSl)QqKOE;UPQ zs5Zr^yfTzGAcxp{4H(>Ny;+ijRZYh zAb&C*k5%_Ud1bF&skzWu#>^QBr9`R;(BELW2B8?s1NuhKGyu4ila+ zjV`-8tn6PVTn0$q1c7i9+h>o_F>Kt%wqb%tzn9V|F2dTX9fm34Sr~R(!?t7z%lIUn zcYgKE^p;nE7u95Vi_f?wtR~GABw>#*SW@rm;0|s#+E?57 EKjYn95dZ)H literal 0 HcmV?d00001 diff --git a/main.py b/main.py new file mode 100755 index 0000000..9ffd785 --- /dev/null +++ b/main.py @@ -0,0 +1,148 @@ +import requests +import time +from bs4 import BeautifulSoup +import hashlib +import datetime +import screenshot +import os +try: + from zoneinfo import ZoneInfo +except ImportError: + from backports.zoneinfo import ZoneInfo # type: ignore for VS Code + +# === LINE API 設定 === +LINE_ACCESS_TOKEN = "uwfN1kiAdFfPoTF4QD8AFC0zO05tT341MBFxXk3n5wT/PAOvshAJqUei3EupTyxIgaTNhBF7zcDBTcq3Hg4SffYr1of0iREPqoCSYIpAS9MSnQ1EGDoYpquvzrDv8i4P8nwnOh/+vu/K/PcFs7QKqAdB04t89/1O/w1cDnyilFU=" +USER_ID = "C3c225be8353b74ecfaa202d5ae9c182c" # piccc group +LINE_API_URL = "https://api.line.me/v2/bot/message/push" + +# 本机图片路径 +IMAGE_PATH = "screenshot.png" + +headers = { + "Content-Type": "application/json", + "Authorization": f"Bearer {LINE_ACCESS_TOKEN}" +} + +def send_message(): + data = { + "to": USER_ID, + "messages": [ + { + "type": "text", + "text": "吉美網頁有新更新!請查看系統。" + } + ] + } + response = requests.post(LINE_API_URL, headers=headers, json=data) + if response.status_code == 200: + print("訊息發送成功!") + else: + print(f"發送失敗,錯誤代碼:{response.status_code}") + print(response.text) + +def send_image(): + headers = { + "Content-Type": "application/json", + "Authorization": f"Bearer {LINE_ACCESS_TOKEN}", + } + + # 先上传图片到外部服务器(因为 LINE API 需要图片的 URL) + image_url = upload_image_to_imgur(IMAGE_PATH) + + if not image_url: + print("图片上传失败") + return + + # 发送消息 + payload = { + "to": USER_ID, + "messages": [ + { + "type": "image", + "originalContentUrl": image_url, # 图片的 URL + "previewImageUrl": image_url, # 预览图的 URL + } + ], + } + + response = requests.post(LINE_API_URL, json=payload, headers=headers) + print(response.json()) + +# 使用 Imgur API 上传图片(或你自己的图床) +def upload_image_to_imgur(image_path): + IMGUR_CLIENT_ID = "5e67dbdeaafc7dc" # 需要去 Imgur 申请 + headers = {"Authorization": f"Client-ID {IMGUR_CLIENT_ID}"} + with open(image_path, "rb") as f: + files = {"image": f} + response = requests.post("https://api.imgur.com/3/upload", headers=headers, files=files) + + if response.status_code == 200: + return response.json()["data"]["link"] + else: + print("图片上传失败:", response.json()) + return None + +# === 目標網址與 session 設定 === +homepage_url = "https://tccmoapply.dba.tcg.gov.tw/tccmoapply/" # 首頁,先訪問以建立 session +target_url = "https://tccmoapply.dba.tcg.gov.tw/tccmoapply/maliapp/asp/aspcons_f000.jsp?MODE=SAVE&KIND=01&YY=109&NO1=0267&NO2=00&CG=05" # 目標頁面 +check_interval = 7200 # 每 7200 小時檢查一次 (7200) + +# === 取得網頁內容並計算 Hash === +def get_page_content(): + with requests.Session() as session: + # 先訪問首頁以建立 session + session.get(homepage_url) + + # 訪問目標網頁 + response = session.get(target_url) + + if response.status_code != 200: + print(f"請求失敗,錯誤代碼:{response.status_code}") + return "" + + soup = BeautifulSoup(response.text, 'html.parser') + + # 找出網頁內的主要內容 + main_content = soup.find("table") # 你可以改成特定的 `div` 或 `section` + + return main_content.text.strip() if main_content else "" + +def get_content_hash(content): + return hashlib.md5(content.encode()).hexdigest() + +def now_time(): + now_utc = datetime.datetime.now(ZoneInfo("UTC")) + taipei_time = now_utc.astimezone(ZoneInfo("Asia/Taipei")) + return taipei_time.strftime("%Y-%m-%d %H:%M:%S") + +previous_hash = "" + +while True: + try: + page_content = get_page_content() + current_hash = get_content_hash(page_content) + + if previous_hash and current_hash != previous_hash: + print(f"{now_time()}: 網頁有更新!") + screenshot.screenshot() + send_message() + send_image() + time.sleep(3) + os.remove(IMAGE_PATH) + else: + print(f"{now_time()}: 沒有變更") + ''' + screenshot.screenshot() + send_message() + send_image() + time.sleep(3) + os.remove(IMAGE_PATH) + ''' + previous_hash = current_hash + time.sleep(check_interval) + + + + except Exception as e: + print(f"ERROR: {e}") + time.sleep(check_interval) diff --git a/screenshot.py b/screenshot.py new file mode 100755 index 0000000..527b2b9 --- /dev/null +++ b/screenshot.py @@ -0,0 +1,39 @@ +from selenium import webdriver +from selenium.webdriver.chrome.options import Options +import time + +def screenshot(): + options = Options() + options.add_argument("--headless") # 無頭模式 + options.add_argument("--no-sandbox") # 避免權限問題 + options.add_argument("--disable-dev-shm-usage") # 避免資源不足 + options.add_argument("--disable-gpu") # 某些系統需要這個 + options.add_argument("--window-size=800x600") # 設定解析度 + + # 啟動瀏覽器 + driver = webdriver.Chrome(options=options) + + # 先訪問首頁,讓 Session 建立 + driver.get("https://tccmoapply.dba.tcg.gov.tw/tccmoapply/") + print("Waiting for session to establish...") + time.sleep(2) # 等待 2 秒確保 session 建立 + + # 再跳轉到目標頁面 + target_url = "https://tccmoapply.dba.tcg.gov.tw/tccmoapply/maliapp/asp/aspcons_f000.jsp?MODE=SAVE&KIND=01&YY=109&NO1=0267&NO2=00&CG=05" + driver.get(target_url) + print("Navigated to target page, waiting for it to load...") + time.sleep(2) # 等待 2 秒確保頁面載入完整 + + # 滾動到頁面底部 + driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") + print("Scrolling to the bottom...") + time.sleep(3) # 等待 3 秒確保頁面完全載入 + + # 截取整個頁面 + driver.save_screenshot("screenshot.png") + print("Screenshot saved as 'screenshot.png'") + + # 關閉瀏覽器 + driver.quit() +if __name__ == '__main__': + screenshot()