緣起:
有位網名叫 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 推薦的作法
好吧,我後來又折騰了一會,想換成用手動匯出 cookie 的方式。想說,跟 google 有關的 cookie 匯出的話好像不是很安全,所以我後來又再申請了一個 x 的帳號,在這邊還有得知 protonmail 這個可用來替代 gmail 的 mail 平台。
cookie 的匯出是使用 chrome extension 的
EditThisCookie。手動開 chromium,登入 x 後,開啟 EditThisCookie
extension,然後選擇 Export 功能,它會把 cookie 的值以 json
格式複製到剪貼簿。
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") 來把連結抓出,這邊只有先打列結果











沒有留言:
張貼留言