selenium破解B站极验验证码

最近刚接触python爬虫,跟大多数人一样网上视频+书籍的形式学习,不过有java基础,是直接跳过前几章内容,上手就是撸selenium模拟登陆知乎,过程倒是不难,这让我信心大增。
于是就想尝试有极验验证码的B站,然而网上包括书上都已经是过时的方法,懵逼的我回头一看买的这本《Python3 网络爬虫开发实战》,上面写的2018年4月第一版,不得不感叹技术的变化,你不进步就别想追上它

在百度了N种关键词后,我发现了这位信田玉大大写的**Python爬虫实践-破解哔哩哔哩滑动验证登录**
二话不说贴下来尝试一遍,详细代码全在这位大大那,我这边就说说在代码执行过程中出现的问题以及解决方式

1、加载chrome浏览器问题

# 初始化
def init():
    # 定义为全局变量,方便其他模块使用
    global url, browser, username, password, wait
    # 登录界面的url
    url = 'https://passport.bilibili.com/login'
    chromedriver_path = 'C:/Users/machenike/Anaconda3/Scripts/chromedriver.exe'
    # 此步骤很重要,设置为开发者模式,防止被各大网站识别出来使用了Selenium
    options = webdriver.ChromeOptions()
    options.add_experimental_option('excludeSwitches', ['enable-automation'])
    # 实例化一个chrome浏览器,并设置成窗口最大化
    browser = webdriver.Chrome(executable_path=chromedriver_path, options=options)
    browser.maximize_window()
    # 用户名
    username = 'XXXXXXXXXX'
    # 密码
    password = 'XXXXXXX'
    # 设置等待超时
    wait = WebDriverWait(browser, 20)

因为在用selenium登录知乎的时候发现有识别selenium的问题存在,于是在加载浏览器时设置成开发者模式,不怕一万就怕万一

2、裁剪验证码问题

#对某元素截图   
def save_pic(obj,name):
    try:
        pic_url=browser.save_screenshot('.\\bilibili.png')
        print("%s:截图成功!" % pic_url)
        
        #获取元素位置信息
        left = obj.location['x']                      
        top = obj.location['y']
        right = left + obj.size['width']
        bottom = top + obj.size['height']
        
        print('图:'+name)
        print('Left %s' % left)
        print('Top %s' % top)
        print('Right %s' % right)
        print('Bottom %s' % bottom)
        print('')
         
        im = Image.open('.\\bilibili.png')
        im = im.crop((left, top, right, bottom))    #元素裁剪
        file_name='bili_'+name+'.png'
        im.save(file_name)    #元素截图
    except BaseException as msg:
        print("%s:截图失败!" % msg)

采用 left = obj.location[‘x’] top = obj.location[‘y’]方式获取的x,y位置总是不对头,至少验证码的模块用css选择器寻找正确,猜测是电脑分辨率的问题,会导致最终图片裁剪出现下面的情况,那没有准确的上、下、左、右坐标,可如何是好?
补充:已经找到分辨率问题,我的分辨率是1920*1080,设置的是125%显示,然而这样显示比100%更好,不信你可以试试,成功率接近100%

在这里插入图片描述
没办法这块我更加懵逼,于是采取曲线救国的方式,前方极其骚操作出现,非战斗人员憋着别笑

#修改裁剪代码,保存带有验证码的图片

#对某元素截图   
def save_pic(obj,name):
    try:
        pic_url=browser.save_screenshot('.\\bilibili.png')
        print("%s:截图成功!" % pic_url)
    except BaseException as msg:
        print("%s:截图失败!" % msg)

def cut():
    c_background = wait.until(
        EC.presence_of_element_located((By.CSS_SELECTOR,'canvas.geetest_canvas_bg.geetest_absolute')))
    c_slice = wait.until(
        EC.presence_of_element_located((By.CSS_SELECTOR, 'canvas.geetest_canvas_slice.geetest_absolute')))
    c_full_bg = wait.until(
        EC.presence_of_element_located((By.CSS_SELECTOR, 'canvas.geetest_canvas_fullbg.geetest_fade.geetest_absolute')))
    print(c_background)
	#保存一张带有验证码的图片
    save_pic(c_slice, 'slice')

然后在本项目文件夹中出现了这样一张图片,当然也可以用微信截图截一个,类似就行
在这里插入图片描述
啊,万恶的验证码,让我们用Photoshop打开它,点击视图->标尺
在这里插入图片描述
然后…按住上下两个边拖出对齐线,拖动的时候可以看见XX厘米,用公式换算1厘米=28像素
我的电脑得出
left=1093
top=317
right=1405
bottom = 511
在这里插入图片描述

将代码还原并修改坐标,验证码图片裁剪成功

# 对某元素截图
def save_pic(obj, name):
	try:
		pic_url = browser.save_screenshot('.\\bilibili.png')
		print("%s:截图成功!" % pic_url)

		# 获取元素位置信息
		left = 1093
		top = 317
		right = 1405
		bottom = 511

		print('图:' + name)
		print('Left %s' % left)
		print('Top %s' % top)
		print('Right %s' % right)
		print('Bottom %s' % bottom)

		im = Image.open('.\\bilibili.png')
		im = im.crop((left, top, right, bottom))  # 元素裁剪
		file_name = 'bili_' + name + '.png'
		im.save(file_name)  # 元素截图
	except BaseException as msg:
		print("%s:截图失败!" % msg)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、滑块移动问题

三个地方可做修改,分别是计算滑块移动距离,构造滑块轨迹,和最后拖动滑块,代码如下
1、计算滑块移动距离
我理解就是 滑块最左边-缺口的最左边 这一段距离 ,滑块初始位置上方Phtotshop骚操作可计算出来 但是在实际移动过程中猜测还是因为分辨率的问题,要稍作调整,例如k = i-9 不减9我压根对不齐
2、构造滑块轨迹
不管是匀加速再匀减速,还是滑过头再回来,我都尝试过,均宣告失败,本着不服输的精神,考虑到模拟人动作还有一种可能,前面快速滑动到接近缺口马上停下来,再慢慢划过去,最后左右对一对齐
3、拖动滑块
代码跟一般的都一样,只是在滑动到缺口后又加了几下左右对一对齐的动作

# 计算滑块移动距离
def get_distance(bg_image, fullbg_image):
	'''
    :param bg_image: (Image)缺口图片
    :param fullbg_image: (Image)完整图片
    :return: (Int)缺口离滑块的距离
    '''

	# 滑块的初始位置
	distance = 21
	# 遍历像素点横坐标
	for i in range(distance, fullbg_image.size[0]):
		# 遍历像素点纵坐标
		for j in range(fullbg_image.size[1]):
			# 如果不是相同像素
			if not is_pixel_equal(fullbg_image, bg_image, i, j):
				# 返回此时横轴坐标就是滑块需要移动的距离
				k = i-9
				return k


# 构造滑动轨迹
def get_trace(distance):
	'''
	:param distance: (Int)缺口离滑块的距离
	:return: (List)移动轨迹
	'''
	#滑动70%的距离后停下,再滑动剩下的30%
	lu = [0.7,0.3]
	# 创建存放轨迹信息的列表
	trace = []
	# 设置加速的距离
	faster_distance = distance


	for i in lu:
		the_distance = i*faster_distance
		# 设置初始位置、初始速度、时间间隔
		start, v0, t = 0, 0, 0.2
		# 当尚未移动到终点时
		while start < the_distance:
			# 如果处于加速阶段
			if start < 0.5*the_distance:
				# 设置加速度为2
				a = 3
			# 如果处于减速阶段
			else:
				# 设置加速度为-3
				a = -3
			# 移动的距离公式
			move = v0 * t + 1 / 2 * a * t * t
			# 此刻速度
			v = v0 + a * t
			# 重置初速度
			v0 = v
			# 重置起点
			start += move
			# 将移动的距离加入轨迹列表
			trace.append(round(move,2))
	# 返回轨迹信息
	return trace


# 模拟拖动
def move_to_gap(trace):
	# 得到滑块标签

	slider = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div.geetest_slider_button')))
	# 使用click_and_hold()方法悬停在滑块上,perform()方法用于执行
	ActionChains(browser).click_and_hold(slider).perform()
	for x in trace:
		# 使用move_by_offset()方法拖动滑块,perform()方法用于执行
		ActionChains(browser).move_by_offset(xoffset=x, yoffset=0).perform()
	#小范围震荡一下,进一步迷惑极验后台,这一步可以极大地提高成功率
	ActionChains(browser).move_by_offset(xoffset=3, yoffset=0).perform()
	ActionChains(browser).move_by_offset(xoffset=-3, yoffset=0).perform()
	ActionChains(browser).move_by_offset(xoffset=-2, yoffset=0).perform()
	ActionChains(browser).move_by_offset(xoffset=2, yoffset=0).perform()
	# 模拟人类对准时间
	time.sleep(0.5)
	# 释放滑块
	ActionChains(browser).release().perform()

最后,经我实际调整测试,成功率极高,妈妈再也不用担心我的拼图被怪物吃了
在这里插入图片描述

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值