
一、FB 爬蟲注意事項
1. FB 適合爬蟲的網址 對於新手而言,FB 網頁版(www.facebook.com)由於常常改版,寫好的爬蟲程式可能過陣子就不能用了。根據這個「FB 爬蟲討論串」,推薦的 FB 爬蟲網址如下:- m.facebook.com:此為 FB 行動版網址
- mbasic.facebook.com:此為 FB 簡易版網址,頁面沒有 Javascript,環境非常單純,是爬蟲程式首選
- 不要使用主帳號作為爬蟲
- 頁面存取要設定間隔一段時間,例如隨機 5~10 秒以上,避免被 FB 偵測到固定行動模式
- 別做看似浪費 FB 資源的事
- FB 網頁版:社團網址加上參數 "?sorting_setting=CHRONOLOGICAL" 即可依照貼文發佈時間排序
- FB 行動版:點擊右上角選單圖示(三條橫線) → 最新動態 → 社團,就可看到所有社團貼文依照發佈時間排序
- FB 簡易版:沒有提供排序的方法
二、Node.js 準備動作
1. Node.js 環境設定 使用 Node.js 的初始環境建構,可參考以下:- 「Node.js 爬蟲開發新手技巧」:瞭解 Node.js 基礎知識、開發工具
- 「使用 Node.js 爬蟲定期抓網頁資料」→「一、安裝 Axios、Cheerio 模組」:安裝 Cheerio 操作 DOM 比較方便
- 同一篇的「四、Windows 自動執行程式」可設定排程執行爬蟲程式
- 能模擬 Chrome 瀏覽器的操作,讀取 JS 載入後的頁面 HTML 內容
- 能模擬 FB 輸入帳號密碼的動作,解決帳號登入、網頁讀取 cookie 的問題
三、範例程式碼
以下為簡易的 FB 社團爬蟲範例程式碼,以「Blogger 經營學習資源分享」這個社團作例子,抓 10 篇貼文的內容及貼文網址。 程式碼代表的含意請參考註解文字,並請修改前幾個參數的數值(及帳號密碼等),因為只是能正常執行的簡單範例,需要更多功能請自行修改程式碼:const fbGroupId = "blogger.skill", // FB 社團 ID(為網址上的一串數字), 或社團自訂網址字串
fbHomeUrl = "https://mbasic.facebook.com", // FB 簡易版網址
fbUsername = "xxx@gmail.com", // FB 帳號
fbPassword = "xxxxx", // FB 密碼
maxPosts = 10, // 最多抓幾篇文章
cheerio = require("cheerio"),
puppeteer = require("puppeteer");
(async function() {
let fbPostsArrays = []; // 存放所有 FB 社團貼文
let browser, page;
// FB 初步動作
await fbInit();
// 抓 FB 社團貼文
await getFbGroupPosts();
console.log(fbPostsArrays); // 顯示爬文資料
// 關閉瀏覽器
await browser.close();
// FB 初步動作
async function fbInit() {
// 開啟瀏覽器
browser = await puppeteer.launch();
page = await browser.newPage();
// 載入 FB 首頁
await page.goto(fbHomeUrl);
// 登入 FB
await loginFB(page, fbUsername, fbPassword);
}
// 登入 FB
async function loginFB(page, username, password) {
await page.waitForSelector("#m_login_email");
await page.type("#m_login_email", username);
await page.waitForSelector("#password_input_with_placeholder");
await page.type("#password_input_with_placeholder input", password);
await page.waitForSelector("#login_form");
await page.click("#login_form input[name=login]");
}
// 抓 FB 社團貼文
async function getFbGroupPosts() {
let fbGroupUrl = fbHomeUrl + "/groups/" + fbGroupId;
let postCount = 0; // 已抓取的貼文數量
// 載入 FB 社團首頁
await page.goto(fbGroupUrl);
// 取得單一頁面貼文
await getSinglePagePosts();
// 取得單一頁面貼文
async function getSinglePagePosts() {
let nextPageUrl; // 下一頁連結
// 取得單一頁面所有貼文
await getSinglePagePosts();
// 貼文數量不到 maxPosts 則持續爬取
while (maxPosts > postCount) {
// 休息 10 秒
sleep(10);
// 前往下一頁
await page.goto(nextPageUrl);
// 繼續抓下一頁
await getSinglePagePosts();
}
// 取得單一頁面所有貼文
async function getSinglePagePosts() {
// 等待頁面載入 #m_group_stories_container
await page.waitForSelector("#m_group_stories_container");
//把網頁的body抓出來
let body = await page.content();
//丟給cheerio去處理
let $ = cheerio.load(body);
let $section = $("#m_group_stories_container section");
let $posts = $section.children("article");
let $nextPage = $section.next().children("a");
nextPageUrl = fbHomeUrl + $nextPage.attr("href"); // 下一頁連結
// loop 所有貼文
loopAllPosts();
function loopAllPosts() {
// 取得網址 內容
$posts.each(function() {
// 檢查貼文數量是否已達到 maxPosts
if (maxPosts < postCount){
return false;
}
let $this = $(this);
let $header = $this.find("header:eq(0)");
let $footer = $this.children("footer");
let postUrl = getPostUrl($footer); // 取得貼文連結
let body = $header.next().text(); // 取得貼文內容
fbPostsArrays.push([postUrl, body]);
postCount++; // 紀錄已爬取貼文數
});
}
// 取得貼文連結
function getPostUrl($footer) {
let postUrl;
$footer.find("a").each(function() {
let $this = $(this);
if ($this.text() == "完整動態") {
postUrl = $this.attr("href").split("?")[0];
postUrl = postUrl.replace("mbasic.", "");
return false; // 中止 loop
}
});
return postUrl;
}
}
}
}
// 休息 n 秒
function sleep(sec) {
var sharedArrayBuffer = new SharedArrayBuffer(4),
sharedArray = new Int32Array(sharedArrayBuffer);
Atomics.wait(sharedArray, 0, 0, sec * 1000);
}
})();
執行後的結果如下:
[
[
'https://facebook.com/groups/blogger.skill/permalink/1289039078370664/',
'[標籤選擇的問題] 因為 blogger 沒有把分類跟標籤拆開,撰文上原本把標籤當分類用,但因為覺得多一點標籤可以有利SEO(?),所以就標了一堆,但回到前台後就變得凌亂。 想說是有什麼方式可以指定只呈現要的標籤即可?'
],
[
'https://facebook.com/groups/blogger.skill/permalink/1291575704783668/',
'上面的圖是我找到的模板,但YT嵌入碼貼上後,高度被限制到很窄,同樣的YT預設的嵌入碼,在下面的圖中觀賞上比較舒適,HTML裡面找了很多但還是無解,因此來請教高手求解方'
],
[
'https://facebook.com/groups/blogger.skill/permalink/1290236434917595/',
'製作網頁如果需要用到一些素材、插圖時,可以使用「免費素材搜尋引擎」,一站直接搜尋所有熱門圖庫:https://icon.wfublog.com/ 同時本篇也介紹這些免費素材圖庫,依照CC0、圖示、向量、透明圖等類別進行重點說明:https://www.wfublog.com/2023/06/free-icon-vector-image-stock.html'
],
[
'https://facebook.com/groups/blogger.skill/permalink/1258260454781860/',
'最近因為要在文章裡插入表格,研究了一下方法,想將測試的結果回饋給社團,就把過程整理成文章,若有誤還請各位高手指點,謝謝。'
],
...
]
更多 NodeJs 相關文章:
沒有留言:
張貼留言注意事項:
◎ 勾選「通知我」可收到後續回覆的mail!
◎ 請在相關文章留言,與文章無關的主題可至「Blogger 社團」提問。
◎ 請避免使用 Safari 瀏覽器,否則無法登入 Google 帳號留言(只能匿名留言)!
◎ 提問若無法提供足夠的資訊供判斷,可能會被無視。建議先參考這篇「Blogger 提問技巧及注意事項」。
◎ CSS 相關問題非免費諮詢,建議使用「Chrome 開發人員工具」尋找答案。
◎ 手機版相關問題請參考「Blogger 行動版範本的特質」→「三、行動版範本不一定能執行網頁版工具」;或參考「Blogger 行動版範本修改技巧 」,或本站 Blogger 行動版標籤相關文章。
◎ 非官方範本問題、或貴站為商業網站,請參考「Blogger 免費諮詢 + 付費諮詢」
◎ 若是使用官方 RWD 範本,請參考「Blogger 推出全新自適應 RWD 官方範本及佈景主題」→ 不建議對範本進行修改!
◎ 若留言要輸入語法,"<"、">"這兩個符號請用其他符號代替,否則語法會消失!
◎ 為了過濾垃圾留言,所有留言不會即時發佈,請稍待片刻。
◎ 本站「已關閉自刪留言功能」。