爬取 LINE TODAY 留言
這篇文章會解析 LINE TODAY 的留言頁面,搭配 Python 的 Requests 函式庫,實作一個可以爬取 LINE Today 某篇文章所有留言的網路爬蟲。
本篇使用的 Python 版本為 3.7.12,所有範例可使用 Google Colab 實作,不用安裝任何軟體 ( 參考:使用 Google Colab )
LINE Today 留言結構
使用 Chrome 瀏覽器,開啟 LINE TODAY 的頁面,點選任意一篇文章,開啟文章頁面。
LINE TODAY:https://today.line.me/tw/v2/tab
本篇範例開啟了一篇「英特爾基辛格已抵台 錄影片讚聲台積電」的文章。
將文章往下捲動,找到留言的位置,點擊「顯示全部」,會開啟留言的頁面。
文章對應的留言頁面:https://today.line.me/tw/v2/comment/article/oqay0ro
開啟留言頁面後,在網頁的任意位置,按下滑鼠右鍵,點擊「檢視」,開啟 Chrome 開發者工具,切換到「Network」頁籤,在 Network 頁籤裡,可以看到網頁開啟時,所有透過網路下載或上傳的內容 ( 如果沒有看到內容,重新整理網頁就會看到 )。
點擊前方的清除按鈕,清空內容 ( 方便待會觀察出現哪些項目 ),再將子頁籤切換到「Fetch/XHR」,該頁籤表示有哪些 XMLHttpRequest 物件在交換溝通。
重新整理網頁,開發者工具中就會陸續出現一些物件,在畫面裡找到名為「list?articleId=.....」的項目,點選這個項目,就能看到該文章的有多少留言以及所有留言的內容。
觀察一下這個物件的網址 ( 可以在該項目上按下滑鼠右鍵,開啟到新的 tab 裡 ),可先注意這篇文章的 articleId、每次顯示留言的數量 limit 和第二頁開始的次序 pivot。
https://today.line.me/webapi/interaction/comment/list?articleId=179673305&country=TW&postId=179673305&postType=Article&sort=POPULAR&direction=DESC&limit=30&pivot=0
因為留言物件的網址數量 limit 設定為 30,所以如果該網頁的留言很多 ( 範例網頁有超過兩百則留言 ),會產生「不止一筆」留言物件,這時從開發者工具裡就會看到 pivot=0、pivot=30、pivot=60...等的留言物件網址。
由於文章的網址並沒有 articleId,表示網頁一定是透過某些機制將網址對應到 articleId,檢視網頁原始碼後 ( 在網頁上點擊滑鼠右鍵,點選檢視網頁原始碼 ),搜尋 179673305 ( 這篇文章的 articleId ),會發現網頁原始碼有撰寫了相對應的轉換程式,如何轉換並不重要,重要的是記住下圖標註紅色的位置,待會會透過程式擷取對應的 articleId。
轉換網址,印出留言總數
由於 Fetch/XHR 的網址使用的是 articleId,所以必須先從原本的網址裡提取 articleId ( 目的在於如果有多個頁面,就不用一一開啟開發者工具找 articleId ),下方的程式碼執行後,會印出該篇文章的 articleId。
import requests
webUrl = requests.get('https://today.line.me/tw/v2/article/oqay0ro') # get 文章網址
# 取得文章的原始碼後,使用 split 字串拆分的方式,拆解出 articleId
article_id = webUrl.text.split('<script>')[1].split('id:"article:')[1].split(':')[0]
print(article_id)
取得 articleId 後,將使用變數與字串格式化的方式,將留言物件的 articleId 更換成該篇文章的 articleId,再度使用 requests,取得 json 格式的內容,並印出文章的總數。
import requests
webUrl = requests.get('https://today.line.me/tw/v2/article/oqay0ro') # get 文章網址
# 取得文章的原始碼後,使用 split 字串拆分的方式,拆解出 articleId
article_id = webUrl.text.split('<script>')[1].split('id:"article:')[1].split(':')[0]
print(article_id)
# 使用 requests get 留言物件
commentUrl = requests.get(f'https://today.line.me/webapi/interaction/comment/list?articleId={article_id}&country=TW&postId={article_id}&postType=Article&sort=POPULAR&direction=DESC&limit=30&pivot=0')
json = commentUrl.json()
num = int(json['count'])
print(num) # 印出文章總數
印出每一筆留言的內容
由於留言筆數過多時 ( 每頁留言一次顯示最多 100 篇 ),留言的物件會拆分成不同的項目,所以下方的程式定義了一個 getComment 函式,在函式執行時賦予「pivot」( 下一頁從第幾筆留言開始 ) 的參數,並透過 range 和 for 迴圈的搭配,就能印出所有的留言。
import requests
webUrl = requests.get('https://today.line.me/tw/v2/article/oqay0ro')
article_id = webUrl.text.split('<script>')[1].split('id:"article:')[1].split(':')[0]
print(article_id)
commentUrl = requests.get(f'https://today.line.me/webapi/interaction/comment/list?articleId={article_id}&country=TW&postId={article_id}&postType=Article&sort=POPULAR&direction=DESC&limit=30&pivot=0')
json = commentUrl.json()
num = int(json['count'])
print(num)
for i in json['comments']:
try:
name = i['displayName'] # 有名稱就印出名稱
except:
name = '???' # 沒有名稱就印出問號
print('<' + name + '>\n' + i['contents'][0]['extData']['content'])
小結
一個網頁在顯示的過程中,背後可能不斷的在與後端交換資料,只要善用 Chrome 的開發者工具,可以從中獲得很多在網頁上看不到的內容,搭配 Python 的函式庫,就能輕鬆抓取各種網頁內容了。
意見回饋
如果有任何建議或問題,可傳送「意見表單」給我,謝謝~