用Python爬取PTT熱門新聞做成文字雲

閱讀時間約 20 分鐘
久久沒更新,把這幾天更新在wordpress的文章搬過來囉!
這是篇自己練習爬蟲,並把爬下來的文字內容透過jieba套件分析後產出文字雲的小練習專案

先來看成品長怎樣吧!

2022年6月12日的熱門新聞

會使用到的環境

  • Python: 3.7.10
  • requests: 抓取網頁
  • BeautifulSoup: 分析網頁
  • matplotlib: 繪圖並顯示
  • wordcloud: 將文字生成文字雲
  • jieba: 文字斷詞工具

先從網頁爬蟲開始

在網路上找到的PTT爬蟲大多是以ptt.cc作為爬蟲目標網站,由於我目標是希望能爬取熱門的討論新聞,雖然可以藉由標題分析來爬取,但出於懶人心態還是另外找尋了PTT熱門新聞網頁版的頁面如下

第一步觀察網頁

觀察網頁是最基礎但也是最難的第一步,觀察網頁的詳細教學可以搜尋Google上有很多大神的教學,這邊推薦一位整理了許多Python爬蟲上會運用到的CSS元素整理的教學網站
總之先來確定所要爬取的目標,在這個分頁裡面我想爬取的目標是標題以及文章網址的連結。透過chrome的「檢查」可以看到以下的畫面
透過「檢查」畫面可以看到,所需要的文章標題及連結被包裹在同一個區塊裡面

把需要的內容爬取下來

已經找到需要爬取的目標位置後,接下來開始進行爬蟲
首先先載入爬蟲需要的套件及設定
from bs4 import BeautifulSoup
import requests

# 掛上headers模擬使用者讀取網頁的行為 (主要用意是部分網站會有反機器人爬蟲機制)
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36'}

# 目標網站
url = 'https://www.pttweb.cc/hot/news/today'
# 發出 get請求
resp = requests.get(url, headers=headers)
# 網頁編碼
resp.encoding = 'utf-8'
# 透過 美麗的湯 進行網頁解析
soup = BeautifulSoup(resp.text, 'html.parser')
# 找出所有 div區塊中 帶有目標class名的元素
divs = soup.find_all('div', 'e7-right-top-container e7-no-outline-all-descendants')
以上的過程是先將上一步中所觀察到的元素抓出來,在這一步的過程裡很容易出現抓到不想要的東西,可以透過python的print函數隨時確認找出來的東西是不是符合原始設定的目標再進行修正
例如,在爬取以上的元素時,發現當標題過長會爬取到 \u3000 的文字內容,這是Unicode編碼標準中屬於CJK字元的全形空格符號,因此在爬取的過程裡需要將其剃除
# 新增個list存取爬下來的內容
articles = []

# 換個網頁爬文章內容
root = 'https://www.ptt.cc'

# 在美麗的湯整理好的 divs中的各個區塊把需要的元素取出
for div in divs:

# 文章連結
link = div.find('a')['href']

# 文章標題
title = div.find('span', 'e7-show-if-device-is-not-xs').text
articles.append({

# 文章標題中的全形空白編碼以空白取代
'title':title.replace('\u3000', ' '),
'link':root + link + '.html'
})
透過以上的步驟可以爬取出如下的結果
那這邊可能會有疑問的是,為什麼連結的部分要換成 ptt.cc 而不是在原網站中爬取呢?
主要原因是因為原網站中的留言有做其他的留言載入的處理,我看不太出來其爬取的位置在哪裡,或許可以透過selenium套件爬取,但太麻煩了就索性換到熟悉的 ptt.cc吧

文章留言爬蟲

在上個步驟中已經將所需要爬取的文章標題及連結都爬取下來了,接下來所要做的事情就是將各個文章中的留言內容取出並存下來
for article in articles:
# 從 articles的列表中取出連結 掛上headers (八卦版的cookie中需要加入 over18=1 才能看到內容喔)
res = requests.get(article['link'], headers = {'cookie': 'over18=1;'})
# 如果網頁掛掉了就跳過它
if res.status_code == 404:
articles.remove(article)
同樣的,在ptt.cc裡面也需要觀察網頁的元素來找出所想要爬取的目標位置在哪裡
從圖中可以看到,在ptt.cc裡,主要的文章內容都在 id='main-content'的區塊中,而要構成文字雲的關係,並不需要文章內容,僅需要爬取推文就行了,因此爬取的目標在 class="push"的推文內容
觀察class="push"的區塊中,可以看到所要爬取的推文內容存在 class="f3 push-content"之中,但文字內容也包含了「:」這個開頭的標點符號,因此在將其爬取下來的過程中一併剃除處理吧
for article in articles:
res = requests.get(article['link'], headers = {'cookie': 'over18=1;'})
if res.status_code == 404:
articles.remove(article)
else:
soup = BeautifulSoup(res.text, 'lxml')
main = soup.find('div', id='main-content')
main_tag = main.find_all('div', class_='push')
# 新增一個位置存取文章的推文內容
comment = []

for i in main_tag:
# 如果沒有推文就跳過
if not i.find('span', 'push-tag'):
continue
# 把: 標點符號替換掉
push_content = i.find('span', 'push-content').text.replace(': ',"")
# 推文內容存入
comment.append(push_content)

article['content'] = comment
以上就完成了各文章的推文內容爬蟲啦~~~

開始製作文字雲吧

什麼是文字雲?

文字雲其實就顧名思義,是以純文字所構成的雲朵圖。在這次的應用上來說,各個文章的推文內容,會依照每個字詞出現的頻率來構成文字雲。我們可以透過觀看文字雲中出現的詞語來快速了解到,鄉民們對於各個新聞的反應如何。

製作文字雲

不過單純地將文字輸出做成文字雲,很容易出現無意義的字詞,例如「你我他」之類的沒有實質意義的內容,因此需要將文字進行解析並取出有意義的詞語,再依照出現的頻率製作文字雲
而解析有意義的詞語的步驟稱作「斷詞」。相比於英文,中文的斷詞非常複雜,這邊就不多做解釋了,直接套用中文斷詞套件最有名的jieba套件 (台灣的中研院也有個繁體中文斷詞套件 ckiptagger 但使用起來非常緩慢 不是非常推薦使用)
製作文字雲的步驟為,透過jieba解析出文字詞頻後,輸出給 wordcloud套件做成文字雲,再藉由matplotlib輸出成圖

開始coding吧

首先載入需要使用的套件
import jieba
import matplotlib.pyplot as plt
from wordcloud import WordCloud
設定jieba分析詞頻所要使用的字典,這個字典可以自己設定或是到jieba的github上下載
jieba.set_dictionary('dict.txt.big')
由於爬取下來的推文留言是用逗號來區別開來並存在同一個列表之中,為了讓jieba能夠進行分析,需要將逗號改成空格,把推文內容連接起來成一個文本
之後抓中取前100個重要的字詞來象徵各個文章的推文代表詞
# 抓前十篇熱門新聞製作文字雲
for article in articles[:10]:
content_text = article['content']
content_list = " ".join(content_text)
tfidf_fre = jieba.analyse.extract_tags(content_list, topK=100, withWeight=True, allowPOS=(),withFlag=True)

# 把分析完的詞頻輸出成字典
count_dic = {}
for i in range(len(tfidf_fre)):
count_dic[tfidf_fre[i][0]] = tfidf_fre[i][1]
# 把字典交給wordcloud做成文字雲
myWordClode = WordCloud(
width=1200, # 圖的寬度
height=600, # 圖的長度
background_color="black", # 背景顏色 預設是白色
colormap="Dark2",
font_path='SourceHanSansTW-Regular.otf' # 輸出字體 必須將字體的檔案放在同個資料夾下
).fit_words(count_dic)
# 用PIL顯示文字雲
plt.figure(figsize=(8, 6), dpi=100)
plt.imshow(myWordClode)
plt.axis("off")
print(article['title'])
print(article['link'])
plt.show()
以上就完成了熱門新聞的推文留言文字雲囉!

完整的程式碼在這

from bs4 import BeautifulSoup
import requests
import jieba
import matplotlib.pyplot as plt
from wordcloud import WordCloud
import jieba.analyse as analyse

# 掛上headers模擬使用者讀取網頁的行為 (主要用意是部分網站會有反機器人爬蟲機制)
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36'}

# 目標網站
url = 'https://www.pttweb.cc/hot/news/today'
# 發出 get請求
resp = requests.get(url, headers=headers)
# 網頁編碼
resp.encoding = 'utf-8'
# 透過 美麗的湯 進行網頁解析
soup = BeautifulSoup(resp.text, 'html.parser')
# 找出所有 div區塊中 帶有目標class名的元素
divs = soup.find_all('div', 'e7-right-top-container e7-no-outline-all-descendants')
# 新增個list存取爬下來的內容
articles = []
# 換個網頁爬文章內容
root = 'https://www.ptt.cc'
for div in divs:
link = div.find('a')['href']
title = div.find('span', 'e7-show-if-device-is-not-xs').text
articles.append({
'title':title.replace('\u3000', ' '),
'link':root + link + '.html'
})

for article in articles:
res = requests.get(article['link'], headers = {'cookie': 'over18=1;'})
if res.status_code == 404:
articles.remove(article)
else:
soup = BeautifulSoup(res.text, 'lxml')
main = soup.find('div', id='main-content')
main_tag = main.find_all('div', class_='push')
# 新增一個位置存取文章的推文內容
comment = []

for i in main_tag:
# 如果沒有推文就跳過
if not i.find('span', 'push-tag'):
continue
# 把: 標點符號替換掉
push_content = i.find('span', 'push-content').text.replace(': ',"")
# 推文內容存入
comment.append(push_content)

article['content'] = comment

jieba.set_dictionary('dict.txt.big')

# 抓前十篇熱門新聞製作文字雲
for article in articles[:10]:
content_text = article['content']
content_list = " ".join(content_text)
tfidf_fre = jieba.analyse.extract_tags(content_list, topK=100, withWeight=True, allowPOS=(),withFlag=True)

# 把分析完的詞頻輸出成字典
count_dic = {}
for i in range(len(tfidf_fre)):
count_dic[tfidf_fre[i][0]] = tfidf_fre[i][1]
# 把字典交給wordcloud做成文字雲
myWordClode = WordCloud(
width=1200, # 圖的寬度
height=600, # 圖的長度
background_color="black", # 背景顏色 預設是白色
colormap="Dark2",
font_path='SourceHanSansTW-Regular.otf' # 輸出字體 必須將字體的檔案放在同個資料夾下
).fit_words(count_dic)
# 用PIL顯示文字雲
plt.figure(figsize=(8, 6), dpi=100)
plt.imshow(myWordClode)
plt.axis("off")
print(article['title'])
print(article['link'])
plt.show()

題外話

這次的文字雲製作算是拖延了好久好久才做成的小專案,先自我反省個幾秒。主要的問題大多發生在爬蟲的過程中,對於網站的組成架構不熟悉導致卡關。
另外,在中文斷詞分析的部分,只用了很簡單的分析方式取出斷詞,要做到更精細的調整,例如捕捉情緒等等的需要NLP自然語言分析的能力,但這一塊對我而言過於艱深難懂,而且沒什麼必要所以就此打住囉
透過文字雲的製作,可以大致上看出鄉民們對於新聞的想法,但文字雲並不代表全部,如果要對輿論進行分析還需要更多的研究觀察。
總之,就先這樣咧,歡迎留言討論其他細節囉!
為什麼會看到廣告
14會員
36內容數
這裡是我的文章收藏區 領域範圍與我的經歷一樣多元不設限 主要會包含的主題有 財經 宅宅 哲學 自我成長 職涯成長等
留言0
查看全部
發表第一個留言支持創作者!
DowDow的沙龍 的其他內容
國債,又被稱作國家債券或公債,是國家的中央政府或聯邦政府以其信用為基礎,向社會籌集資金所形成的債權債務關係。由於國債的發行主體為國家,因此被認為是最安全的投資工具,在財務學的教科書上也常用美國國債利率當作無風險利率作計算。
這篇大概是就職現職後,我的第一篇專欄文章。今天不知道為什麼突然想起這篇就索性也分享過來吧!
「條條大路通羅馬(All Roads Lead to Rome)」,被用來比喻為不論運用什麼方法,都能達到相同的結果。同時,也象徵著羅馬帝國的輝煌盛大,然而,條條大路的興建事實上正是羅馬帝國經濟崩塌的開始。淺談因劣質貨幣導致通膨而滅亡的羅馬帝國經濟史。
資產價值的評估是整個市場經濟的產物,小至隨手可得的商品,大至一個集團企業等,都有相對應的資產價值評估方式。要準確的評估資產真正的價值是一件非常困難的事情,不過我們還是能深入淺出的理解如何評估資產價值。讓這篇文章為您淺談關於資產價值評估的兩三事。
這篇是投稿參與Matters所發起的「我心中的NFT」主題投稿文章。
國債,又被稱作國家債券或公債,是國家的中央政府或聯邦政府以其信用為基礎,向社會籌集資金所形成的債權債務關係。由於國債的發行主體為國家,因此被認為是最安全的投資工具,在財務學的教科書上也常用美國國債利率當作無風險利率作計算。
這篇大概是就職現職後,我的第一篇專欄文章。今天不知道為什麼突然想起這篇就索性也分享過來吧!
「條條大路通羅馬(All Roads Lead to Rome)」,被用來比喻為不論運用什麼方法,都能達到相同的結果。同時,也象徵著羅馬帝國的輝煌盛大,然而,條條大路的興建事實上正是羅馬帝國經濟崩塌的開始。淺談因劣質貨幣導致通膨而滅亡的羅馬帝國經濟史。
資產價值的評估是整個市場經濟的產物,小至隨手可得的商品,大至一個集團企業等,都有相對應的資產價值評估方式。要準確的評估資產真正的價值是一件非常困難的事情,不過我們還是能深入淺出的理解如何評估資產價值。讓這篇文章為您淺談關於資產價值評估的兩三事。
這篇是投稿參與Matters所發起的「我心中的NFT」主題投稿文章。
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
Thumbnail
本篇內容介紹如何使用 Python中的 moviepy library 簡單的剪影片。 先安裝moviepy library , 用pip install moviepy , 可參考官方文件。 要剪的影片和python檔要在同個資料夾中,若不在同個位置要用 os library 更換路徑
Thumbnail
根據泰勒定理,f(x)可以寫成右邊一長串的導數的組合 為了更好理解這個東西我們可以用python實作 首先定義f(x)和定義factorial怎麼算 然後寫泰勒定理 f(x) = f(a) + f'(a)(x-a) ....後面還有一串 注意公式往後面看其實是有規律的 例如從
Thumbnail
前陣子因為Heroku被駭客入侵原因,導致Github串聯被封阻,一度無法進行教學,不過近日Heroku已重新全面開放串聯,因此我們將持續恢復教學文章,今天我們要教的是如何爬取個股的平均股利資訊,讓我們輕鬆一鍵了解個股股利的發放狀況
Thumbnail
在上一篇教學中,我們學會如從Goodinfo!中將個股的一些最新與基本資訊爬取下來並打印出來,而先前我們也教過如何爬取台股、全球等較大範圍的新聞爬取,而今天我們就打算將範圍縮小,只針對個股的新聞來進行抓取,那我們就開始今天的教學吧!! 匯入套件 爬取YAHOO!股市
Thumbnail
在上一篇教學中,我們學會了如何將鉅亨網上的新聞爬取下來,並且顯示在LINE BOT中,而我們今天則來教一下如何查詢個股的一些基本資訊,以及最新的開盤價、成交價等資訊吧!!
Thumbnail
在一系列的基礎教學過後,我們終於要來教學跟股票相關的文章了,那就是「如何爬取最新的財經新聞」,別嫌之前的基礎枯燥乏味,基礎打好我們才能夠將功能運用的千變萬化,所以還沒看過之前的基礎教學,可以先去觀看唷!!廢話不多說,我們就開始今天的教學吧!!
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
Thumbnail
本篇內容介紹如何使用 Python中的 moviepy library 簡單的剪影片。 先安裝moviepy library , 用pip install moviepy , 可參考官方文件。 要剪的影片和python檔要在同個資料夾中,若不在同個位置要用 os library 更換路徑
Thumbnail
根據泰勒定理,f(x)可以寫成右邊一長串的導數的組合 為了更好理解這個東西我們可以用python實作 首先定義f(x)和定義factorial怎麼算 然後寫泰勒定理 f(x) = f(a) + f'(a)(x-a) ....後面還有一串 注意公式往後面看其實是有規律的 例如從
Thumbnail
前陣子因為Heroku被駭客入侵原因,導致Github串聯被封阻,一度無法進行教學,不過近日Heroku已重新全面開放串聯,因此我們將持續恢復教學文章,今天我們要教的是如何爬取個股的平均股利資訊,讓我們輕鬆一鍵了解個股股利的發放狀況
Thumbnail
在上一篇教學中,我們學會如從Goodinfo!中將個股的一些最新與基本資訊爬取下來並打印出來,而先前我們也教過如何爬取台股、全球等較大範圍的新聞爬取,而今天我們就打算將範圍縮小,只針對個股的新聞來進行抓取,那我們就開始今天的教學吧!! 匯入套件 爬取YAHOO!股市
Thumbnail
在上一篇教學中,我們學會了如何將鉅亨網上的新聞爬取下來,並且顯示在LINE BOT中,而我們今天則來教一下如何查詢個股的一些基本資訊,以及最新的開盤價、成交價等資訊吧!!
Thumbnail
在一系列的基礎教學過後,我們終於要來教學跟股票相關的文章了,那就是「如何爬取最新的財經新聞」,別嫌之前的基礎枯燥乏味,基礎打好我們才能夠將功能運用的千變萬化,所以還沒看過之前的基礎教學,可以先去觀看唷!!廢話不多說,我們就開始今天的教學吧!!