想必大家一定會很困惑
我在去年不是就發過搶樓機器人的文了
因為當時做的時候我自己的程度還沒那麼高
基本上是網路查查胡亂拼湊的縫合怪
所以後來果然維護上出現困難就壞掉了
經過昨天用手搶到陽交串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 然後等到適當時機發文也有罪
那對 我有罪 快來抓我
記得順便把我的爬蟲銷毀 以免他爬到你褲子裡抓你ㄐㄐ = =
如果你是靠自己的雙手搶樓 那你可以不要用
如果你是怕搶不過機器人 那你可以也用機器人來搶
我是說 機器人不一定會搶到樓層
就如我上篇文所提出的 會有兩大無法解決的問題
面對這兩種情況 機器人就面臨了很多不確定性
舉個昨天陽交串的例子
多人同時搶樓導致程式在時間間隔內抓到的樓層一次多跳了五樓
不過我也不否認我沒用機器人搶輸過
但是其實就算我不用 異音就公開了搶樓的JS腳本
而且巴哈臥虎藏龍 要做出搶樓機器人真的不困難
唯一能做的就是不要把搶樓看那麼重
我自己比起搶到樓 更滿足於用親手寫的程式搶到樓這件事
打了好多內容呢
其實我對於之前的搶樓機器人是很不滿意的
因為畢竟超出自己當時的程度 感覺根本不是自己親手做的
然而今天打出這篇文某種意義也是重新奪回我的搶樓機器人吧
終於來到了可以掌握這機器人的一天
這樣也給之前的自己一個交代了
這次分享差不多就這樣
感謝觀賞~