b站使用的滑动验证码为由极验提供服务,其登录过程:
- b站向自己服务器请求得到 gt,challenge 参数
- 携带 gt,challenge 参数请求极验服务器get.php,得到图片滑动的相关参数,包括缺口图,完整背景图,滑块图等数据(图片被打乱)
- 浏览器使用canvas渲染出正常的图片
- 用户拖动滑块至缺口,本地js会记录拖动过程中鼠标的移动轨迹,进行加密得到参数 w,携带参数 w 请求极验服务器ajax.php,验证码轨迹是否异常,验证通过会得到一个 validate 参数
- gt,challenge,validate,username,password 提交表单完成登录
使用selenium登录
- 从canvas获取完整图片
# canvas 有一个属性 toDataURL,获取到图片流数据
def save_img(self, img_name, class_name):
# img_name 图片保存名称
# class_name 图片在HTML中ClassName
getImgJS = 'return document.getElementsByClassName("' + class_name + '")[0].toDataURL("image/png");'
img = self.driver.execute_script(getImgJS)
base64_data_img = img[img.find(',') + 1:]
image_base = base64.b64decode(base64_data_img)
file = open(img_name, 'wb')
file.write(image_base)
file.close()
- 比较图片得到滑动距离
# 判断颜色是否相近
def is_similar_color(self, x_pixel, y_pixel):
for i, pixel in enumerate(x_pixel):
if abs(y_pixel[i] - pixel) > 50:
return False
return True
# 计算距离
def get_offset_distance(self, cut_image, full_image):
# 两个参数为图片流数据
for x in range(cut_image.width):
for y in range(cut_image.height):
cpx = cut_image.getpixel((x, y))
fpx = full_image.getpixel((x, y))
if not self.is_similar_color(cpx, fpx):
img = cut_image.crop((x, y, x + 50, y + 40))
# 保存一下计算出来位置图片,看看是不是缺口部分
img.save("1.png")
return x
- 模拟用户滑动
# 开始移动
def start_move(self, distance):
# 定位滑块
element = self.driver.find_element_by_xpath('//div[@class="geetest_slider_button"]')
# 这里就是根据移动进行调试,计算出来的位置不是百分百正确的,加上一点偏移
distance -= element.size.get('width') / 2
distance += 25
# 按下鼠标左键 move_by_offset 从当前坐标移动到 (x,y)
ActionChains(self.driver).click_and_hold(element).perform()
time.sleep(0.2)
while distance > 0:
if distance > 10:
# 如果距离大于10,就移动快一点
span = random.randint(5, 8)
else:
# 快到缺口了,就移动慢一点
span = random.randint(2, 3)
# 每次移动的速度不一样,看起来卡顿,比较慢
randy = random.randint(-3,3)
ActionChains(self.driver).move_by_offset(span, randy).perform()
distance -= span
# time.sleep(random.randint(10, 30) / 100)
ActionChains(self.driver).move_by_offset(distance, 1).perform()
# 释放鼠标
ActionChains(self.driver).release(on_element=element).perform()
表单提交登录
参考文章:
极验js分析
网友评论