創作內容

40 GP

爬蟲實作 - 改良版巴哈自動搶樓機器人

作者:熾炎之翼│2021-07-26 22:56:45│巴幣:1,078│人氣:1439
想必大家一定會很困惑
我在去年不是就發過搶樓機器人的文了
因為當時做的時候我自己的程度還沒那麼高
基本上是網路查查胡亂拼湊的縫合怪
所以後來果然維護上出現困難就壞掉了

經過昨天用手搶到陽交串10000樓後
我也想到也是時候修復這個機器人了
現在我也總算有能力搞懂這一切到底在幹嘛
不只成功重寫了搶樓機器人
同時我也在原有的功能上繼續加強
變得全自動 而且可以連續蓋樓

而且這次我也會公布&講解程式碼
這邊也要特別感謝異音大佬發了這篇文
反正大佬都已經公布了JS的搶樓程式碼
那我這邊自然也不需隱藏
而且我這邊的環境設定相較之下還比較繁瑣XDDDD

先上個程式碼
import requests
from bs4 import BeautifulSoup
import time
import os
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains

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"}
options = webdriver.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-logging'])


UID = 'YOUR_UID' #你的帳號
PW = 'YOUR_PW' #你的密碼
content = '蓋' #你蓋樓的內容


def starter():
    driver.get(URL)
    driver.find_element(By.ID, "postTips").click()
    time.sleep(0.3)
    ActionChains(driver).send_keys(content).perform()  


URL = input('URL:')
floor_target = int(input('欲搶樓層:'))

if '&last=1' not in URL:
    URL += '&last=1'

driver = webdriver.Chrome(chrome_options=options)
driver.get('https://www.gamer.com.tw/')
driver.find_element(By.LINK_TEXT, "我要登入").click()
driver.find_element(By.ID, "uidh").send_keys(UID)
driver.find_element(By.NAME, "passwdh").send_keys(PW)
driver.find_element(
    By.CSS_SELECTOR, ".form__buttonbar:nth-child(6) > .btn--primary").click()
time.sleep(0.5)
starter()
os.system('cls')
while True:
    request = requests.get(URL, headers=send_headers)
    html = request.content
    bsObj = BeautifulSoup(html, 'html.parser')
    shouter = bsObj.findAll('a', {'class': 'floor'})
    for page in shouter:
        floor_now = page.get_text()
    print(floor_now)
    floor_now = int(floor_now[:-2])
    t = 60

    if floor_now >= floor_target:
        t = 60
        print('已超過預定樓層 請重新輸入下一欲搶樓層')
        floor_target = int(input('欲搶樓層:'))
        os.system('cls')
        starter()
        continue

    elif floor_target - floor_now <= 10:
        t = 0.4

    if floor_now == floor_target - 1:
        driver.find_element(By.CLASS_NAME, "btn--send").click()
        time.sleep(0.3)
        driver.find_element(By.CLASS_NAME, "btn-primary")
        try:
            driver.find_element(By.CLASS_NAME, "btn-primary").click()
        except:
            pass
        print("已發文")

    time.sleep(t)

不得不說 selenium IDE真的是神器
大概靠他就能解決八成的問題了 = =

一開始send_headers正如之前分享的文章所說得一樣
就是給爬蟲丟給伺服器 用來偽裝成正常瀏覽器訪問的資訊
因為巴哈會擋爬蟲 所以這是不可缺少的部分

接下來
options = webdriver.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-logging'])
這兩行的作用就是讓selenium操控的瀏覽器不要印出log檔
以免影響版面跟干擾操作

我這邊帳密和發文內容是直接紀錄在code上
因為我自己認為在拉個input有點耗時間和沒必要

接下來我宣告個函式starter()
用途就是讓selenium瀏覽器可以進入準備發文的狀態

這部分老實說我搞最久
本來之前的機器人都是要手動打好回覆內容
連異音版本的也是要你先打好

可是我架構的環境都比異音的JS版本麻煩很多了
如果沒有把這功能做出來真的就沒有甚麼意義
所以我挺堅持這部分的


因為巴哈的發文框框挺難搞的
本來我想用一般的send_key功能都失敗
後來我發現可以只點擊回應框框
然後又從網路上學到不鎖定元素直接輸入的方法(因為我游標已經在框框內
就是用ActionChains就能實現
所以繞了一大圈總算搞好這功能了
並且正式完成全自動化

不過這邊等他轉圈圈要花個幾秒
沒辦法 selenium唯一的缺點就是慢 = =


就這樣完成了前置作業
正式進入程式運行的部分
這邊會一開始會要你輸入討論串的連結以及想要搶的樓層

欲搶樓層會記錄在變數floor_target

可是這邊遇到一個問題
因為可能會遇到沒有貼到討論串最後一頁的連結的情況
這樣爬蟲抓樓層就沒辦法抓到最新的樓層
所以我這邊做了一個小防呆
if '&last=1' not in URL:
    URL += '&last=1'
因為巴哈討論串網址只要最後加上「&last=1」就會直接導向最後一頁
所以這邊會為沒有「&last=1」的網址自動加上這一段
確保所有網址最後都能導向到正確的頁碼

而且也讓使用上更方便
可以直接貼任何頁碼的巴哈討論串的網址上來
不用特別調到最後一頁

接著selenium就開始工作了
本來我是打算直接進入目標討論串
但是因為selenium操控的Chrome_webdriver不會記憶每次的使用紀錄
所以每次都要重登巴哈姆特
(其實我之前就是特別開一個設定檔讓他不用每次登入 但可是這樣做挺容易發生問題的又攜帶性不高 所以後來我決定不採用)
而當我使用紀錄的帳密登入後 發現又會回到巴哈姆特的首頁
所以我索性先來到到巴哈首頁
登入完後再配合自訂函式starter()來到要搶的討論串
並自動完成發文準備



在這之後就是進入利用requests獲取最新樓層的階段

但在進入爬樓層階段之前
我用了os.system('cls')來清潔個版面
這邊也是預防如果某天要輸入帳密
也能達到安全的效果

雖然一個頁面會爬到好幾個樓層資訊
但是透過疊代就會讓變數抓到最後一個也就是最新的樓層資訊
而這當然也會印在終端機上

不過因為巴哈標籤是「xxxx 樓
所以這邊字串要slice成[:-2]來過濾掉「 」才能轉int來做數學運算

然後我這邊是設計每60秒爬一次最新樓層(t = 60)
而要是偵測到距離目標樓層(floor_target)距離剩下10樓以內就會開始每0.4秒爬一次(t = 0.4)
來因應白熱化的搶樓戰局

0.4秒也算是巴哈伺服器的底線了吧
我自己之前測試都沒有被ban ip
要是擔心也可以調長一點

然後離目標樓層只剩下一樓就馬上發文
大家注意到我這邊用了try...except
這是因為巴哈有時候發文會多跳一個視窗要你遵守發文規則和注意法律責任
目前我也不知道觸發條件是什麼 反正就是有機會要按兩次確認(class都是「btn--send」)
所以就用try...except來見招拆招

而這邊我特別設計了一個判斷式
如果當前樓層超過或等於目標樓層(可能是已經被搶了 或是單純你輸入時打錯數字)
程式就會要重新輸入下一個目標樓層

然後程式就會再次使用starter()來回到準備狀態
並且再次把爬樓間距設為60秒

簡單來說這功能可以讓你搶了又搶
你搶到了以後就能繼續再設下一個目標樓層
然後只要程式不關 電腦就能持續幫你監視並代你搶到樓層
雖然除非你自架伺服器通常你不會等到下一個100或1000樓啦


好 講解差不多就到此為止了
其餘沒有細講的部分大部分都是網頁元素
那個講了大概也沒人想聽吧XDDD
然後那些time.sleep()都是給程式一點緩衝
不然selenium控制瀏覽器會跟不上而出錯


然後這邊特別也回一下常見問題

Q:這會不會觸犯妨害電腦使用罪
A:
如果你一直狂按F5 然後等到適當時機發文也有罪
那對 我有罪 快來抓我
記得順便把我的爬蟲銷毀 以免他爬到你褲子裡抓你ㄐㄐ = =

Q:啊這樣搶樓不就沒樂趣了
A:
如果你是靠自己的雙手搶樓 那你可以不要用
如果你是怕搶不過機器人 那你可以也用機器人來搶
我是說 機器人不一定會搶到樓層
就如我上篇文所提出的 會有兩大無法解決的問題
1.網速問題
2.多人同時蓋樓
面對這兩種情況 機器人就面臨了很多不確定性
舉個昨天陽交串的例子
多人同時搶樓導致程式在時間間隔內抓到的樓層一次多跳了五樓

不過我也不否認我沒用機器人搶輸過
但是其實就算我不用 異音就公開了搶樓的JS腳本
而且巴哈臥虎藏龍 要做出搶樓機器人真的不困難
唯一能做的就是不要把搶樓看那麼重
我自己比起搶到樓 更滿足於用親手寫的程式搶到樓這件事  



打了好多內容呢
其實我對於之前的搶樓機器人是很不滿意的
因為畢竟超出自己當時的程度 感覺根本不是自己親手做的
然而今天打出這篇文某種意義也是重新奪回我的搶樓機器人吧
終於來到了可以掌握這機器人的一天

這樣也給之前的自己一個交代了


這次分享差不多就這樣
感謝觀賞~


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

相關創作

留言共 16 篇留言


幹我以為你真的是自己搶到的 [e10] [e10] [e10] [e10] [e10] [e10] [e10] [e10] [e10] [e10] [e10] [e10]

07-26 22:58

熾炎之翼
昨天是我自己搶到的沒錯啊 只有看爬蟲來知道現在樓層到哪而已 還是用手發文的XD07-26 22:59
只是個安弟
佬...

07-26 23:03

熾炎之翼
合太子宮屌虐我ㄅ07-26 23:07
玥晴 Luna (#ΦωΦ#)
我媽問我說為什麼我要跪著看手機

07-26 23:05

熾炎之翼
你走浮誇風欸07-26 23:07
Mago
原來是自己搶的,當下我看到10001真的挺悶的,但是沒被隔壁搶去就很開心ㄌ[e19]

07-26 23:08

熾炎之翼
抱歉啦 搶樓就是一人開心眾人鬱卒@@
不過幸好還是阿御幫的勝利(?07-26 23:10
Mago
沒錯,這是阿御幫的勝利[e22]

07-26 23:12

熾炎之翼
阿御是青椒老大07-26 23:17
葡萄lala
其實ㄋ可以用requests.get() 的params 來送參數就可以不用額外加那個判斷式了
也可以考慮作個簡單的IO把常用的大樓參數存起來
巴哈bsn 是看板id,snA是串的id。

07-26 23:15

熾炎之翼
感謝大佬指教
這邊還會再繼續修改的07-26 23:18
葡萄lala
範例:
params_YJ = {
"last":1,
"bsn":60076,
"snA":4981464,
}
丟進去就可以了
不過selenium大概還是要先登入

07-26 23:18

熾炎之翼
行 感謝範例07-26 23:20
望塵莫及
我一直以為是小精靈搶的還我感動oMo

07-27 00:32

熾炎之翼
:)07-27 11:18
無鹽粄條
感謝你的分享
爬蟲的套件好神秘

07-27 08:32

熾炎之翼
應用層面挺廣的07-27 11:19
費玟
先GP一波

07-27 09:20

熾炎之翼
感謝感謝07-27 11:19
御安鴨·摸頭害鴨哭
佬!
我記得有一種網路攻擊俗稱叫F5攻擊,是明文寫在美國聯邦法裡面的,所以...真的是犯法的喔,但我不知道台灣法律有沒有這條法律

07-27 15:14

熾炎之翼
不過說真的 我單一設備根本不會對伺服器造成任何傷害 更何況在我造成影響之前就會被ban掉ip 性質上來說更像是你用電腦一直按F5(人手按的速度還可能低於0.4秒) 法律上我是覺得站得住腳的07-27 16:24
月夜藍黑貓
像這種正常的爬蟲在法律上是沒有禁止的,但短時間內大量的request是不符爬蟲道德的,而且也大機率會被對方的防火牆擋下來,做到這種程度我就不知道會不會觸法了

07-27 19:28

熾炎之翼
如果沒有被伺服器擋掉的程度
我認為這也算是伺服器端允許的應用範圍
更何況這並非殭屍網路這種足以影響甚至癱瘓伺服器的等級
所有功能也是任何一個使用者都可以做到手動重現的
要說觸法還是挺讓人難以接受的07-27 19:59
FRENIA
我要去檢舉你.jpg
程式佬欸,我覺得我學了coding也不知道要拿來幹嘛(´・ω・`)

08-01 02:52

熾炎之翼
可能總有一天會派上用場 吧08-01 02:55
FRENIA
笑死 你怎麼還沒睡
可能派上用場的那天我也全忘光了吧

08-01 02:56

熾炎之翼
每天3、4.睡算常態了吧
我覺得忘掉還好 老實說我自己同一個東西也會忘個3、4次
重點是要有印象 要知道怎麼去查
本來就很少人把全部的函式背的滾瓜爛熟
上網查資料不是什麼可恥的事08-01 02:59
漆黑鼠鼻子
讚....
我三年前剛學python爬蟲拿巴哈試
結果突然在今年三四月左右的時候程式都動不瞭 爬html tag都只會有巴哈姆特電玩資訊站 系統忙碌中和一堆js碼
還特地換ptt 發現都可以爬,所以當時認為應該是巴哈加了什麼防爬機制
發過資工串 也沒大佬幫解答

因緣際會看到這篇原來加了偽裝就可以動了
舒服 感謝大佬 直接贊助1000

08-02 02:30

熾炎之翼
沒事 很高興能夠幫到你
基本上爬蟲最好都裝一下偽裝
不然其實挺多網站都會擋的08-02 02:35
看起來就有在援
好膩害喔 受益良多

12-09 12:32

熾炎之翼
沒想到過了快半年還有人看XD12-09 12:49
我要留言提醒:您尚未登入,請先登入再留言

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

前一篇:2021/07/26 生... 後一篇:【歌詞翻譯】「Starl...

追蹤私訊切換新版閱覽

作品資料夾

ms0489223每天換一首的人
Theater of Life · 鈴木このみ看更多我要大聲說7小時前


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

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