first commit
This commit is contained in:
commit
b4a8c8dbd4
2
README.md
Normal file
2
README.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Run main.py
|
||||||
|
Monitor website every 2 hours and send Line message to target groupe if updates
|
BIN
__pycache__/screenshot.cpython-38.pyc
Normal file
BIN
__pycache__/screenshot.cpython-38.pyc
Normal file
Binary file not shown.
148
main.py
Executable file
148
main.py
Executable file
@ -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)
|
39
screenshot.py
Executable file
39
screenshot.py
Executable file
@ -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()
|
Loading…
x
Reference in New Issue
Block a user