小屋創作

日誌2021-06-30 03:59

自動化小屋文章GP數圖表分析器

作者:熾炎之翼

度度度
暑假想做些酷事情
這個晚上就搞出了一個「自動化小屋文章GP數圖表分析器」

其實這只是我程式專案的其中一小部分而已
本來這個只是來測試而已
結果意外地順利 就乾脆寫一個圖表分析器出來了XD

這個分析器主要功能就是
可以用任意巴哈帳號的小屋第一篇文到最新一篇文的GP數量做一個折線圖表
這邊以我朋友早稻田學霸結城ちわ(chiwa9103)為例



然後這邊也依照每筆帳號的情況不同
我做了X軸是篇數還有文章標題兩種版本 其實篇數板只是標題版的閹割版本而已
容我先上個拙劣程式碼

程式碼(x軸篇數版)
import requests
from bs4 import BeautifulSoup
import matplotlib.pyplot as plt

GPs = []

send_headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
    "Connection": "keep-alive",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
    "Accept-Language": "zh-CN,zh;q=0.8"}

page = 1
final_page = 1
artNum = 0
owner = input('Please enter the ID : ')

URL = 'https://home.gamer.com.tw/creation.php?page=1&owner='+owner+'&v=3&t=0'
request = requests.get(URL, headers=send_headers)
html = request.content
bsObj = BeautifulSoup(html, "html.parser")
shouter = bsObj.findAll('a')
for p in shouter:
    if p.text.isdigit() and ('TS1' not in str(p)):
        if int(p.text) > final_page:
            final_page = int(p.text)

while page <= final_page:
    URL = 'https://home.gamer.com.tw/creation.php?page=' +
        str(page)+'&owner='+owner+'&v=3&t=0'
    request = requests.get(URL, headers=send_headers)
    html = request.content
    bsObj = BeautifulSoup(html, "html.parser")
    shouter2 = bsObj.findAll('span', {'class': 'BC4'})
    for item in shouter2:
        artNum += 1
        gp = item.text[:-3]
        GPs.append(gp)
    print('Analyzing {}/{} ......'.format(page, final_page))
    page += 1

GPs.reverse()
GPs = list(map(int, GPs))

x = [number for number in range(1, artNum+1)]
y = GPs

plt.figure(figsize=(60, 20))  # *100
plt.title('GP_analysis for '+owner)
plt.ylabel('GP')
plt.xlabel('Number of Articles')
plt.yticks([10, 20, 50, max(GPs)])
plt.axhline(10, color="Red")
plt.axhline(20, color="Blue")
plt.axhline(50, color="Orange")
for a, b in zip(x, y):
    plt.text(a, b+0.5, b, ha='center', va='bottom', fontsize=6)
plt.plot(x, y)
plt.show()

程式碼(x軸文章標題版)
import requests
from bs4 import BeautifulSoup
from matplotlib.font_manager import FontProperties
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei']
plt.rcParams['axes.unicode_minus'] = False

GPs = []
names = []

send_headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
    "Connection": "keep-alive",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
    "Accept-Language": "zh-CN,zh;q=0.8"}

page = 1
final_page = 1
artNum = 0
owner = input('Please enter the ID : ')

URL = 'https://home.gamer.com.tw/creation.php?page=1&owner='+owner+'&v=3&t=0'
request = requests.get(URL, headers=send_headers)
html = request.content
bsObj = BeautifulSoup(html, "html.parser")
shouter = bsObj.findAll('a')
for p in shouter:
    if p.text.isdigit() and ('TS1' not in str(p)):
        if int(p.text) > final_page:
            final_page = int(p.text)

while page <= final_page:
    URL = 'https://home.gamer.com.tw/creation.php?page=' +
        str(page)+'&owner='+owner+'&v=3&t=0'
    request = requests.get(URL, headers=send_headers)
    html = request.content
    bsObj = BeautifulSoup(html, "html.parser")
    shouter1 = bsObj.findAll('a', {'class': 'TS1'})
    for item in shouter1:
        names.append(item)
    shouter2 = bsObj.findAll('span', {'class': 'BC4'})
    for item in shouter2:
        artNum += 1
        gp = item.text[:-3]
        GPs.append(gp)
    print('Analyzing {}/{} ......'.format(page, final_page))
    page += 1

names.reverse()
GPs.reverse()
GPs = list(map(int, GPs))

x = [number for number in range(1, artNum+1)]
y = GPs

plt.figure(figsize=(60, 20))  # *100
plt.title('GP_analysis for '+owner)
plt.ylabel('GP')
plt.xlabel('Titles')
plt.xticks(x, names, rotation='vertical')
plt.yticks([10, 20, 50, max(GPs)])
plt.axhline(10, color="Red")
plt.axhline(20, color="Blue")
plt.axhline(50, color="Orange")
for a, b in zip(x, y):
    plt.text(a, b+0.5, b, ha='center', va='bottom', fontsize=6)
plt.plot(x, y)
plt.show()

但是我自己其實覺得文章標題版的先天問題有點大
原因下面細講


技術方面:

這次一樣是網路爬蟲pyplot(以下簡稱plt)的應用
值得注意的是 因為巴哈會擋爬蟲
你如果直接進去爬 伺服器不會給你正常的頁面
所以這邊用了header來偽裝成瀏覽器
send_headers就是提供給巴哈伺服器的header資訊
伺服器接收到就會把爬蟲的request給當成來自於一般瀏覽器(這裡是偽裝成Chrome)

而文章標題版在一開始則多import了FontProperties
下面也多了rcParams那兩行
目的只是為了讓plt圖表可以印出中文
plt原生並沒有支持中文字體 你打中文都會變成空心框框□
所以以前我都會避免打中文 但這次遇到文章標題沒辦法
所以還特別去下載了微軟正黑體的字體檔放到matplotlib資料夾裡
算是一勞永逸地讓plt可以印出中文字體XD

然後接著就是正確又完整輸入分析對象的巴哈ID以後
程式就會自己到對方小屋的「創作頁面」去一頁一頁爬資料了
這裡以我大哥台大電機大神幻雨(bkrn427)為例

我沒特別設計GUI
所以就...對...很樸(ㄔㄡˇ)素(ㄌㄡˋ)
但是可以看出來他的創作總共有19頁(正確數量為151篇)

這邊就很單純地用爬蟲去抓取資訊
標題版也只是多爬了文章標題而已
一開始程式會到創作的第一頁去試著尋找總頁數
然後得到總頁數以後就開心的從第一頁開始
收集文章右邊的GP數資料

所以就算設友限也能爬到資料
但是如果是設為隱藏就爬不到了(只有帳號主人才看的到)

至於關鍵的總頁碼獲得方式
我這邊用了很粗暴的方式就是把HTML裡全部的標籤是<a>(超連結)的內文給抓下來
同時很簡單的把判定範圍縮小成數字而已(使用isdigit()函式)
這時就只有這些頁碼要處理而已

用膝蓋想也知道數字最大的會是最後一頁的頁碼
用單純的比大小就能得到數字
輕鬆又快樂





但是真有這麼簡單嗎?



這邊要再次特別感謝幻雨大哥
因為當我跑他小屋的時候
爬蟲爬到的最後頁碼竟然是
222

對 等於差不多有2220篇文....
扯你媽ㄐㄐ的 這他媽鬼才信 = =


我很好奇為什麼會有這個奇怪的數字
於是自己點進他小屋才發現

...
對 我沒想到標題也可能是純數字組成的
按照剛剛的比大小的方法來看程式就會判斷222是最後頁碼
於是我又多設立一個條件 'TS1' not in str(p)
度的 因為文章標題的標籤裡面class = "TS1"
加上這個條件以後就可以排除所有文章標題了

其實對程式來說
存在這問題依舊能順利運行(超越總頁碼的頁數之頁面其實存在,只是爬不到東西)
但是爬蟲要一直浪費時間跳到沒東西可爬的一頁又一頁
如果今天有人標題寫了48763
這就要等爬蟲他媽跑到48763頁了 哭啊


搞到總頁碼之後就沒什麼問題了
這邊巴哈的網頁設計非常適合爬資料
標題名稱就在<a>裡class = "TS1"的區塊
GP數量就在<span>裡class = "'BC4"的區塊(爬出來會「XX GP」,用簡單的字串切割[:-3]就可以去除「 GP」的部分)
再把上述資料存在串列
準備丟給plt去繪圖

不過在開始繪圖之前
要特別先用reverse()函式去倒轉一下串列
不知道大家有沒有發現剛剛資料是從最新一筆存到第一筆
基本上圖表都是從最舊的開始畫到最新的
當然如果你想倒著畫我也沒什麼意見
但這邊會無可避免地把置頂貼文當成最新一篇文
要改進需要多判斷一個發布日期

而後面順便也用map()函式把GP串列的數量元素都轉成int型態(原本皆為str)

接著再把上述的值存到代表X軸資料與Y軸資料的x,y兩個變數
注意就算是標題版也不能直接把標題當成X軸
因為會遇到文章同名的問題
折線就會變成這樣

後續同名標題的GP資料的會跑到標題第一次出現的X座標那裡去
圖看起來就在搞事XDDDDDDD

所以X軸的定位要用從1到文章總數的數字排好的串列
我這邊用了串列生成式
x = [number for number in range(1, artNum+1)]
artNum是剛剛爬GP時順便記數的變數
假設文章總數是823
這個語法就會生成一個[1,2,3,...,823]的串列
可以正好跟每篇文的GP數元素們對好

後面就單純只是plt的修飾
像我利用axhline()函式用了不同顏色畫了三條標準線(10,20,50)
然後還用plt.text()函式在每個點上標GP總數
標題版用了xticks()函式去把標題貼到X軸上
然後最後plot()函式把值給畫到圖上
再用show()函式把圖印出來
稍微手工調整圖片細節(高度、寬度)後存下來就基本上大功告成了


技術方面差不多就是這樣
該來講講標題板會遇上的問題
最主要的就是空間問題
結城ちわ總共有44篇文
她的會是這樣呈現(經過人工拉長底部)

看起來還行?
因為我是把標題倒轉90度才比較有空間
但是看的出來標題長度又是一個明顯的問題

如果還沒什麼感覺
我就用文章數量多到哭(632篇)的我自己為例

首先是篇數版

再來是標題版

這片黑森林到底是個啥...
反正標題版對文章數量多的人來說幾乎就是沒用
根本看不出個所以然



尚未實現的功能:

這次的程式不敢說做的很完整
雖然頗具潛力 但我還是覺得實驗性質居多
我這次就沒寫個用日期/篇數去限定搜索範圍的功能
其實就是加幾行又小改一下的功夫
但你看一下發文時間 我打到這邊已經快他媽4點了 = =
之後有空再加上去

再來就是收藏數、人氣數其實也能統計
更進步一點甚至能統計每個留過言的人的總留言數量
但是收藏數跟留言必須要點進文章才會得知
如果你文章設友限就沒辦法得知(爬蟲都是以訪客身分在爬)
要是想讓爬蟲可以看到好友或是自己的友限文(還能看到自己的隱藏文章)
就要用到selenium套件來爬了(可以模仿人類瀏覽網頁,預先設好帳密就能以登入狀態查看)
但是這同時也會讓速度下降不少就是了
要怎麼跟requests套件搭配好要再思考

然後是GUI
這好像也不是這麼必要




這次的程式就差不多分享到這邊了
感謝觀看

71

39

LINE 分享

相關創作

啊~~~~~~~

【原神】買東西

【翻譯】Holo四格(ホロよん) 第554話

留言

開啟 APP

face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情⋯ 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】