創作內容

71 GP

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

作者:熾炎之翼│2021-06-30 03:59:12│巴幣:142│人氣:834
度度度
暑假想做些酷事情
這個晚上就搞出了一個「自動化小屋文章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
這好像也不是這麼必要




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

引用網址:https://home.gamer.com.tw/TrackBack.php?sn=5193476
All rights reserved. 版權所有,保留一切權利

相關創作

留言共 39 篇留言


可不可以看到誰給go

06-30 04:02


Gp

06-30 04:02

熾炎之翼
誰給GP網頁是用JS動態生成 所以用selenium 套件一樣可以實現 06-30 08:48

乾我認真看完了 程式的部分是完全看不懂,好強

06-30 04:07

熾炎之翼
其實程式部分還好 就是一直在鑽牛角尖的感覺06-30 08:48
出桶下車(消失模式)
看不懂,反正就佬

06-30 04:14

熾炎之翼
感謝感謝06-30 08:48
三個月換一次小熊 ♪

不是很懂爬蟲...

06-30 04:38

熾炎之翼
爬蟲不難又好玩
很快樂06-30 08:49
阿霞
佬,我看不懂

06-30 05:08

熾炎之翼
沒關係 知道程式會幹嘛就可以了06-30 08:49
kasumi_ MyGo單推人
佬 先跪

06-30 05:27

熾炎之翼
不佬 程式的部分真的不難06-30 08:49
依霏。
佬。

06-30 05:34

熾炎之翼
謝謝06-30 08:49
我的巴哈超爛
程式佬,我先跪了

06-30 05:35

熾炎之翼
還行還行06-30 08:50
費玟
挺有印象的函式庫,然後matplotlib不能顯示中文字型已經是眾所皆知的問題了XD

06-30 05:39

熾炎之翼
對 這個問題網路上查就一堆06-30 08:51
費玟
要選用哪個字型就是一門學問了 因為顯示出來可能字體大小會不太一樣(就我自己電腦的狀況是這樣

06-30 05:40

熾炎之翼
我是沒有一個個去嘗試 直接用了個人喜好的微軟正黑體XDDD06-30 08:52
費玟
不過最近沒啥在用python,與其叫它pyplot,應該叫它matplotlib吧?
在我印象中pyplot是屬於matplotlib的一個套件(module)
直接叫它pyplot這樣484有點喧賓奪主XD

06-30 05:42

熾炎之翼
對 但是我這邊只有用到plt部分的功能 我覺得這樣說明可能比較直接一點06-30 08:53
費玟
然後爬蟲不能直接爬、會看user-agent,這點好像是基本的樣子?
我之前寫爬巴哈小屋創作標題的時候也是這樣
哦不過我真的懶,只取最新的前幾個
不像你還可以爬到之後幾頁
因為我懶得找頁碼在哪裡然後再換url參數找其他幾頁了ㄏㄏ

06-30 05:44

熾炎之翼
其實不一定 有些會檔有些不會檔 雖然的確大多網站都會檔就是了 不過既然分享文章就特別寫出來讓大家知道而已XD06-30 08:54
費玟
selenium感覺也不錯啊,雖然沒用過,不過聽說好像是一個可以模擬滑鼠跟按鍵的套件,讚

話說
我當初寫爬蟲的時候,原本用python
後來覺得url網址要換參數的時候,還有requests套件用XPath去定位某些tag的位置的時候
(例如標題的ST1、時間的TS1)

塞了一堆字串讓整個程式碼看起來有夠亂,搞到我很不爽

一氣之下怒跑去看豬腳的爬蟲文
然後看他說雖然這次用python介紹,但他自己會用go語言去寫爬蟲
看到這我就直接去學Golang了,氣死


另外多嘴個幾句
爬出來的東西,我是模仿解凍豬腳的小屋首頁那個「最後上線時間」的文字轉圖片的格式(SVG檔)
而沒有用圖表,這點跟你不太一樣

不過挺好玩的就是了,讚XD

06-30 05:55

熾炎之翼
slelenium我用過
我之前寫過巴哈自動發文機器人
他的確就是完全模擬正常鍵鼠
但是速度上卻因此被犧牲掉很多
我想如果像我600多篇文
那一篇一篇點進去假設搞個一秒鐘
(載入網頁、滑到底下balabala,回到上一頁)
這樣就要搞個10分鐘欸wwwwwww06-30 08:57
費玟
啊selenium好像是模仿登入、註冊那一類的
我剛剛可能一瞬間誤解成按鍵精靈了(?)

06-30 05:56

熾炎之翼
你剛剛講的沒有錯喔06-30 08:58
可撥指考仔
完全看不懂 放棄

06-30 06:41

熾炎之翼
你繼續當你的醫生啦XD06-30 08:58
無鹽粄條
感謝分享XD
我不太懂爬蟲,但看著你的思路和實作手法還是覺得很有意思。
每次看別人的python code,都會驚嘆python怎麼有那麼多神奇的function可以用XD

06-30 08:43

熾炎之翼
Python最大最大的優點就是多到不行的酷function了XDDDD06-30 09:02
皮克西斯.日進
大推!期待完整版

06-30 08:46

熾炎之翼
感謝支持!06-30 09:03
結城ちわ
跪了我看不懂

06-30 08:54

熾炎之翼
謝謝讓我舉例w06-30 09:03
星爆凱留-東方傳教士

06-30 08:58

熾炎之翼
過獎了06-30 09:03
費玟
原來我對selenium的理解沒錯啊?
我憑去年只看了大概2分鐘的selenium介紹文的印象打出來的東西居然是對的(?)
話說10分鐘真的好久, 沒事幹嘛模擬鍵鼠發文啦ww

06-30 09:19

熾炎之翼

你搞錯我的意思了XD
我是說用selenium去每篇文點進去看GP、收藏數還有留言
至於窩剛剛說的發文是這這篇(我沒透漏程式碼)
https://home.gamer.com.tw/creationCategory.php?owner=h32902227&c=480012

我當時的用途是拿來搶樓就是了XD06-30 09:24
熾炎之翼
連結貼錯 這個才是XD
https://home.gamer.com.tw/creationDetail.php?sn=498519206-30 09:39
費玟
然後會擋只是防爬蟲的安全機制做得比較好吧(大概啦猜的
畢竟就像你說的不是所有網站都會擋

但我覺得那應該是資安的基本…啦
我所謂的基本是那個意思~

06-30 09:21

熾炎之翼
其實跟資安是沒什麼關係
因為爬蟲能爬到的資料一般使用者按F12也能找到
最大的危害是對伺服器流量的占用
如果程式不斷對伺服器端發出request
很多人一起積少成多就會演變成小型的DDOS攻擊了w06-30 09:27
樂小呈
爬蟲佬

06-30 10:11

熾炎之翼
否否06-30 10:16
費玟
說得也是齁 一般使用者也找得到
然後 嗯 如果沒有設置timing的話 對伺服器流量佔用就真的挺大的

話說我有時候會擔心做的爬蟲會不會導致我IP被BAN XD
雖然想了想應該是不會啦 我發佈在heroku上當巴哈簽名檔 有讀取才會載入
不像單機程式那樣沒設好time.sleep就會一直發請求 所以應該是沒事

06-30 10:12

熾炎之翼
其實確實有機會被ban
我自己的巴哈大樓樓層爬蟲是有設0.3秒的sleep
還是要注意一下06-30 10:17
費玟
豪 不過我不知道怎麼在發佈到網站上而不是單機程式的前提下設sleep
更何況我還不熟golang
哭啊

06-30 10:21

熾炎之翼
加油 慢慢研究吧06-30 10:36
Decision
看不懂 先跪大佬再說

06-30 10:47

熾炎之翼
不敢當06-30 10:54
小小喵兒
很強!
最近剛好也在研究XD

06-30 10:51

熾炎之翼
爬蟲真的很有趣06-30 10:54
你媽的,為什麼
看不懂先gp再跪

06-30 10:54

熾炎之翼
感謝GP~06-30 11:07

佬..好猛ㄛ

06-30 10:58

熾炎之翼
還可以 這次的邏輯不難06-30 11:07
jenny
都看不懂,佬

06-30 11:18

熾炎之翼
只要知道程式的功能就好了ㄛ06-30 11:32
朝輝夕嵐
selenium真的慢
而且有時候網頁渲染速度不夠快
還會抓不到資料= =

你可以試試看在request裡面放帳號密碼去post看看

06-30 11:26

熾炎之翼
這是真的 之前用過的感想就是很慢
之後可以來試試放個帳密06-30 11:38
空白
妨害⋯電腦⋯

06-30 11:32

熾炎之翼
你媽…死了…06-30 11:39
希無冀
佬吧

06-30 12:05

熾炎之翼
還行06-30 12:06
舒潔艾拉
你是不是整個晚上沒睡覺

06-30 13:07

熾炎之翼
我全部做完是2點 打完文章是4點 起床是9點半06-30 13:10
夜雨繁塵
妨害電腦88

06-30 13:25

熾炎之翼
你在幹米恐龍06-30 14:55
煙雨迷濛
文組看不懂 下拉

06-30 13:26

熾炎之翼
我要去買非洲阿姨的影片祝你生日快樂了06-30 14:56
月下一點墨

06-30 13:42

熾炎之翼
沒有吧06-30 14:56
費玟
嗯?話說不考慮放到github之類的地方嗎

07-15 20:06

熾炎之翼
我其實放了也不會特別講XD07-15 20:08
費玟
啊不過剛剛又考慮了一下 也有可能是你顧慮到會增加伺服器負擔的關係
所以只貼在小屋給需要(?)的人用吧

07-15 20:07

熾炎之翼
其實放到github更沒人會看啦XD07-15 20:09
我要留言提醒:您尚未登入,請先登入再留言

71喜歡★h32902227 可決定是否刪除您的留言,請勿發表違反站規文字。

前一篇:2021/06/29 生... 後一篇:2021/06/30 L...

追蹤私訊切換新版閱覽

作品資料夾

Niwaiwaiwai大家
小屋更新了插畫喔,這次是可愛的妹妹看更多我要大聲說昨天16:54


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

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