搜尋此網誌

2026年3月11日 星期三

Telegram Bot 通知 X 新文章 (無完成)

緣起:


    有位網名叫 Lemon 的韓國繪師很喜歡畫勾芒 X 羿,我現在三不五時就會去她的 x 頁面刷新,看看她有沒有畫新的圖。後來想到,我是不是可以寫個爬蟲之類的在 Pi 上跑,當發現她有貼新的文章時,就送個通知提醒。

    搞了一天半,完成了 80% 左右的進度,中午時先休息個,躺床上滑手機時想到,我應該要在我手機上裝 x app 才對,裝好登入後,再去查看 Lemon 的個人檔案頁面,看到


    靠腰,這時才發覺,自己就像個傻X一樣,明明現在大部份的社群平台都有這種功能了,我怎麼還幹這種脫褲子放屁的事?哭啊。雖然這專案大概是用不到了,但時間成本都投入了,而且也確實學到不少東西,所以還是要寫文章記錄個。


Telegram Bot:


    原本在通知部份,我想要繼續用 Line Bot,但看到 gpt 提到 Telegram Bot,所以就想來玩看看。參考這篇文章來操作。

    首先加 BotFather 為聯絡人,然後輸入 /newbot,為你的 Bot 命名



    好了之後它會給你一個操作 Bot 的 API Key,記下來。它也會傳給你 Bot 的連結,直接點那連結把 Bot 加到自己的聯絡人。我那時點進去後,系統就自動幫我傳 /start 給我的 Bot,先隨便對 Bot 傳些訊息,接下來用網頁開啟網址

https://api.telegram.org/bot{你的 Bot API Key}/getUpdates

    會看到一個 json 資料,裡頭有包含你的 id,把 id 複製起來


    我有開個叫 LemonX_Telegram_Notify 的 python venv,用 request 套件來 post 

import requests
TOKEN = "{你的 Bot API Key}"
CHAT_ID = "{你的 id}"
msg = "NMSL"
url = f"https://api.telegram.org/bot{TOKEN}/sendMessage"
requests.post(url, data={
	"chat_id":CHAT_ID,
	"text":msg
})

    執行程式後,就能看到 Bot 向你傳送訊息。Telegram Bot 的部份到這裡就算完成了
    


Playwright:


    接著是爬蟲,關於動態網頁的爬蟲,我之前只認識 Selenium,但它說 Selenium 需要的資源會比較多,所以更推薦用 snscrape 或 Playwright 來做。我最後選 Playwright,這名字看比較順眼。

    在 python venv 裡安裝 Playwright

source {專案目錄}/bin/activate
pip3 install playwright

    要下載瀏覽器的話,在 python venv 裡下

playwright install chromium

    我 pi 的 Raspbian 預設就有裝 chromium,查了一下, playwright 是可以指定瀏覽器的執行位置,所以我就不再浪費空間再裝一次了。

    測試的程式碼,那個 input 用來等候用,執行程式碼後可以看到網頁成功開啟

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
	browser = p.chromium.launch(
		executable_path="/usr/bin/chromium",
		headless=False
	)
	
	page=browser.new_page()
	
	page.goto("https://google.com")
	
	input("按enter結束")
	browser.close()

    我再來碰上一個最大的問題是,怎麼用我的登入狀態來給爬蟲操作網頁。我首先是用 gpt 推薦的作法


    我的 x 是用 google 帳號登入的,當我想在 chromium 上登入我的 google 帳戶時,被擋了


    好吧,我後來又折騰了一會,想換成用手動匯出 cookie 的方式。想說,跟 google 有關的 cookie 匯出的話好像不是很安全,所以我後來又再申請了一個 x 的帳號,在這邊還有得知 protonmail 這個可用來替代 gmail 的 mail 平台。

    cookie 的匯出是使用 chrome extension 的 EditThisCookie。手動開 chromium,登入 x 後,開啟 EditThisCookie extension,然後選擇 Export 功能,它會把 cookie 的值以 json 格式複製到剪貼簿。


    資料長這樣,只需要 domain、name、path、value,其它有的沒的值可以去掉


     然後把檔案存成 cookie.json,放到專案目錄。最後是整個 python 程式

import requests
from playwright.sync_api import sync_playwright
import json

cookies=[]

with open('./cookie.json', 'r') as f:
    cookies = json.load(f)

with sync_playwright() as p:
	browser = p.chromium.launch(
		executable_path="/usr/bin/chromium",
		headless=True,
		args=["--no-sandbox", "--disable-dev-shm-usage"]
	)
	context = browser.new_context()
	context.add_cookies(cookies)
	page=context.new_page()
	
	page.goto("https://x.com/senrok1001")
	page.wait_for_selector("article")
	first_article_links = page.locator("article").first().locator("a[role=\"link\"]")
	
	for i in range(first_article_links.count()):
		href=first_article_links.nth(i).get_attribute("href")
		print(href)
	
	browser.close()

    7~8 行:載入 cookie.json 檔,放到 cookies 變數

    13 行:headless=True,你就不會看到瀏覽器開啟,但它實際上還是有在執行的。

    14 行:gpt 說這兩個是 Raspberry Pi 跑 Playwright 的標準配置,--no-sandbox 關閉安全沙箱(步戰免權限問題),--disable-dev-shm-usage 不使用 /dev/shm (避免 shared memory 不夠)。

    16~18 行:開啟 page 前載入 cookie

    21 行:playwright 的等待功能,等到網頁有出現 <article> 後再開始動作。開啟 chromium 的開發人員工具可以看到,每篇文章都是一個 article tag
    

    22 行:用 Locator 來把目標元素抓出,除了 tag 外,它還支援用 css selector 來抓。只取第一個元素的話,可以用 first。Locator 物件是可以再往下找子元素的,所以我還有再呼叫 locator("a[role=\"link\"]"),取出文章中有 role="link" 的 <a>


    24~26 行:我最後是做到這裡,Locator 不是 list,不能用 for 來列舉,正確做法是呼叫 count() 來取得元素的數量,然後用 nth() 方法來逐一取出,最後用 get_attribute("href") 來把連結抓出,這邊只有先打列結果


    我需要的就只有文章連結 (第四個),所以假如之後還要再接著做專案的話,應該會用正規表達式來過濾不必要的連結。以上就是我在這次的實作中學到的東西。


沒有留言:

張貼留言