您好,登錄后才能下訂單哦!
準備工作
B站登錄頁 https://passport.bilibili.com/login
python3
pip install selenium (webdriver框架)
pip install PIL (圖片處理)
chrome driver:http://chromedriver.storage.googleapis.com/index.html
firefox driver:https://github.com/mozilla/geckodriver/releases
B站的滑塊驗證碼如上。
這類驗證碼可以使用 selenium 操作瀏覽器拖拽滑塊來進行破解,難點兩個,一個如何確定拖拽到的位置,另一個是避開人機識別(反爬蟲)。
確定滑塊驗證碼需要拖拽的位移距離
有三種方式
各有優缺點。人工智能機器學習,確定滑塊位置,需要進行訓練,比較麻煩,也可以看是否存在在線api可以調用。以下介紹其他兩種方式。
對比完整圖片與缺失滑塊的圖片
| 僅介紹,本文不進行實現。對于B站來說,是準確率最高的方式(100%),但不能保證未來B站的滑塊驗證升級,導致不可用。
B站的滑塊驗證模塊,一共有三張圖片:
完整圖、缺失滑塊圖、滑塊圖,都是由畫布繪制出的。類似于:
完整圖:
缺失滑塊圖:
滑塊圖:
HTML代碼類似于:
<div class="geetest_canvas_img geetest_absolute" > <div class="geetest_slicebg geetest_absolute"> <canvas class="geetest_canvas_bg geetest_absolute" height="160" width="260"></canvas> <canvas class="geetest_canvas_slice geetest_absolute" width="260" height="160"></canvas> </div> <canvas class="geetest_canvas_fullbg geetest_fade geetest_absolute" height="160" width="260" ></canvas> </div>
只需要通過selenium獲取畫布元素,執行js拿到畫布像素,遍歷完整圖和缺失滑塊圖的像素,一旦獲取到差異(需要允許少許像素誤差),像素矩陣x軸方向即是滑塊位置。
另外由于滑塊圖距離畫布坐標原點有距離,還需要減去這部分距離。
最后使用 selenium 拖拽即可。
邊緣檢測算法,確定位置
| 滑塊基本上是個方形,通過算法確定方形起始位置即可。
介紹兩種方式
第二種實現起來有些復雜,不進行實現了。
下面是第一種實現方式,會存在檢測不出或錯誤的情況,使用時需要換一張驗證碼。也可能存在檢測出的邊是另一條(因為B站的滑塊不是長方形,存在弧形邊),那么需要減去滑塊寬度
class VeriImageUtil(): def __init__(self): self.defaultConfig = { "grayOffset": 20, "opaque": 1, "minVerticalLineCount": 30 } self.config = copy.deepcopy(self.defaultConfig) def updateConfig(self, config): # temp = copy.deepcopy(config) for k in self.config: if k in config.keys(): self.config[k] = config[k] def getMaxOffset(self, *args): # 計算偏移平均值最大的數 av = sum(args) / len(args) maxOffset = 0 for a in args: offset = abs(av - a) if offset > maxOffset: maxOffset = offset return maxOffset def isGrayPx(self, r, g, b): # 是否是灰度像素點,允許波動offset return self.getMaxOffset(r, g, b) < self.config["grayOffset"] def isDarkStyle(self, r, g, b): # 灰暗風格 return r < 128 and g < 128 and b < 128 def isOpaque(self, px): # 不透明 return px[3] >= 255 * self.config["opaque"] def getVerticalLineOffsetX(self, bgImage): # bgImage = Image.open("./image/bg.png") # bgImage.im.mode = 'RGBA' bgBytes = bgImage.load() x = 0 while x < bgImage.size[0]: y = 0 # 點》》線,灰度線條數量 verticalLineCount = 0 if x == 258: print(y) while y < bgImage.size[1]: px = bgBytes[x, y] r = px[0] g = px[1] b = px[2] # alph = px[3] # print(px) if self.isDarkStyle(r, g, b) and self.isGrayPx(r, g, b) and self.isOpaque(px): verticalLineCount += 1 else: verticalLineCount = 0 y += 1 continue if verticalLineCount >= self.config["minVerticalLineCount"]: # 連續多個像素都是灰度像素,直線 # print(x, y) return x y += 1 x += 1 pass if __name__ == '__main__': bgImage = Image.open("./image/bg.png") veriImageUtil = VeriImageUtil() # veriImageUtil.updateConfig({ # "grayOffset": 20, # "opaque": 0.6, # "minVerticalLineCount": 10 # }) bgOffsetX = veriImageUtil.getVerticalLineOffsetX(bgImage) print("bgOffsetX:{} ".format(bgOffsetX))
總結
以上所述是小編給大家介紹的Python破解BiliBili滑塊驗證碼的思路詳解(完美避開人機識別),希望對大家有所幫助!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。