Python使用selenium过天眼查滑块验证码反爬实现模拟登录

Python使用selenium过天眼查滑块验证码反爬实现模拟登录

天眼查的滑块验证码样式

在输入账号和密码后会发现这个令人讨厌的东西——滑块验证码,此时需要点击滑块,然后才会出现缺口。
在这里插入图片描述
点击滑块之后会出现下面这种情况,需要将滑块移动至缺口的位置才算通过滑块验证码。按照这个步骤来人工操作肯定没问题,但是我们应该怎么样去通过selenium来实现电脑自动化操作来实现呢?网站有没有反爬机制来防止selenium操作呢?如果有,我们又应该怎么突破这种反爬机制呢?
在这里插入图片描述

一顿操作到滑块验证码阶段

在解决问题上述问题之前呢,我们要先走滑块验证码的面前。觉得这一步简单的可以跳过。下面我们来讲讲这一步怎么操作。

首先呢,我们可以看到主页面的样子
在这里插入图片描述
我们既然要实现登录功能, 第一步自然是点击右上角的登录,来到登录页面,用selenium来操作的话就是先获取到登录元素,然后实现点击功能,下面是实现这一步的代码。

#导入各种库
from io import BytesIO
from selenium import webdriver
import time
from selenium.webdriver import ActionChains
from PIL import Image


#打开页面
driver = webdriver.Chrome()
driver.get(url)
driver.maximize_window()

#点击登录按钮
time.sleep(2)
login_btn = driver.find_element_by_xpath('//*[@id="J_NavTypeLink"]')
login_btn.click()

这时我们来到了下面的页面
在这里插入图片描述
我们要用账号密码来登录,我们发现右上角有个电脑符号,我们点击这里就会跳转到账号密码登录的界面,下面我们用selenium来操作

#跳转到输入账号密码登录页面
time.sleep(2)
login_change = driver.find_element_by_class_name('toggle_box')
login_change.click()

这时我们到了这个页面:
在这里插入图片描述
现在呢,我们想要点击密码登录跳转到账号密码登录界面,但是,这里就出现问题了,如果像之前一样用xpath来获取元素的话,我们发现编译环境给报错了,找不到这个元素,那么我们就不得不换一种方法来获取元素。
在这里插入图片描述
我们发现了onclick对应有值,也就是说我们点击账号密码登录以后会用到这个值,学过前段的朋友应该知道,这是一段js代码,那么我们不妨用selenium直接执行这段js代码,那不就直接跳转到这个页面了吗?

#点击账号密码跳转到输入账号密码页面
time.sleep(2)
driver.execute_script("loginObj.changeCurrent(1);")

过不其然,我们来到了这个页面。那么下面就是根据xpath或者class属性值来获取账号输入框、密码输入框、并填入账号密码了。

#输入账号
time.sleep(2)
inputuid = driver.find_element_by_xpath('//*[@id="mobile"]')
inputuid.send_keys("在这里输入你的账号")

#输入密码
time.sleep(2)
inputpassword = driver.find_element_by_xpath('//*[@id="password"]')
inputpassword.send_keys('在这里输入你的密码')

下面就是点击登录按钮,我们发现通过xpath和class属性值同样获取不到,不过我们同样发现了onclick下的一段js代码
在这里插入图片描述
那么跟上面一样,执行这段代码就实现了点击登录的功能。

#点击登录
time.sleep(2)
driver.execute_script("loginObj.loginByPhone(event);")#由于获取不到登录按钮,于是直接执行登录按钮对应的js代码

于是我们就来到了滑块验证码的界面。

破解滑块验证码

我们应该如何来找到缺口的位置呢?我们又应该如何来操作滑块到达缺口的位置呢?下面我们来分析一下。

我们首先应该找到缺口所在的位置,我们肉眼很容易可以看出缺口所在的位置,但是机器应该如何去找呢?我们进入滑块验证码的页面可以看到一张完整的图片,当点击滑块以后才会出现滑块和缺口。我们可不可以让机器通过这两张图片的对比来获取缺口的位置呢?那么我们来试着获取这两张图片试试看。

首先我们应该获取到完整的图片,那么机器应该如何获取呢?我们可以获取到图片元素所在的位置和尺寸来获取图片的坐标,然后我们对整个屏幕来张截图,再对这张截图来根据图片的坐标来截取图片。

#获取图片左上角位置以及图片大小
time.sleep(2)
img = driver.find_element_by_xpath('/html/body/div[10]/div[2]/div[2]/div[1]')
location = img.location
size = img.size

#得到图片的坐标
top, buttom, left, right = location["y"], location["y"]+size["height"], location["x"], location["x"]+size["width"]
print(top, buttom, left, right)

#截取滑块验证码的完整图片
scrennshot = driver.get_screenshot_as_png()
scrennshot = Image.open(BytesIO(scrennshot))
captcha1 = scrennshot.crop((int(left), int(top), int(right), int(buttom)))
captcha1.save('./yanzhengma.png')

接下来我们点击滑块来获取带缺口的图片

#单击滑块按钮得到缺口图片并截图
slider = driver.find_element_by_xpath('/html/body/div[10]/div[2]/div[2]/div[2]/div[2]')
ActionChains(driver).click_and_hold(slider).perform()
time.sleep(1)
scrennshot = driver.get_screenshot_as_png()
scrennshot = Image.open(BytesIO(scrennshot))
captcha2 = scrennshot.crop((int(left), int(top), int(right), int(buttom)))
captcha2.save('./yanzhengma2.png')
time.sleep(2)

两张图片都获取到了,那么我们如何让机器比对两张图片来找到缺口所在的位置呢?图片在机器中是用数据的形式进行存储的,我们看着缺口的位置颜色有明显的不同,而机器也可以通过颜色的对比也就是在机器中存储的RGB也就是红黄蓝三元素的值来进行对比。但是除了缺口的位置有明显的差别之外,我们发现滑块本身也同样有巨大的颜色差别,为了解决这个问题,我们可以从滑块的右侧也就是避开滑块来进行从左到右的逐一比对不过我们注意到滑块中除了缺口外还有一些阴影的存在
在这里插入图片描述在这里插入图片描述
注意看上方的图,发现阴影了吗?如果让机器完全一模一样的去识别的话,这些阴影就会成为我们的绊脚石,难道就没有办法了吗?道高一尺魔高一丈,当然还是有办法的,阴影毕竟是阴影,颜色比起缺口位置来说是很浅的,那么我们就可以设置一个阈值,也就是允许图片有一些轻微的不同,直到遇到缺口这种颜色差别很大的才算成功。那我们就可以写代码了。我们为这个比对来写一个函数

def compare_pixel(image1, image2, i, j):
    #判断两个像素是否相同
    #返回的值是RGB的值
    #这里的i和j表示的是横坐标和纵坐标
    pixel1 = image1.load()[i, j]
    pixel2 = image2.load()[i, j]

    #阈值
    threshold = 50

    if abs(pixel1[0] - pixel2[0])<threshold and abs(pixel1[1] - pixel2[1])<threshold and abs(pixel1[2] - pixel2[2])<threshold:
        return True
    else:
        return False

下面就是进行比对来找到缺口的位置

#从滑块的右侧开始逐一比对RGB值来寻找缺口位置
left = 77
has_find = False
#i和j分别是图片的横坐标和纵坐标
for i in range(left, captcha1.size[0]):
    if has_find:
        break
    for j in range(captcha1.size[1]):
        if not compare_pixel(captcha1, captcha2, i, j):
            left = i    #进入这个if条件即表示寻到了缺口所在的位置,将缺口的横坐标赋值给left
            has_find = True
            break

#需要移动的距离减去滑块距离左边边框的位置从而得到实际需要移动的距离
move = left - 20

下面就是控制滑块移动到缺口的位置

#拖动滑块到缺口位置
ActionChains(driver).move_by_offset(xoffset=move, yoffset=0).perform()

然后我们控制松开鼠标的话,缺口对是对上了,但是却一直通过不了验证,这就是网站的一些反爬手段了。怎么去解决这个问题呢?

我们的思路就是,能不能让滑块不那么像机器,例如滑块划到缺口的位置停一会再松开、或者说让滑块的移动模仿人的滑动滑块的动作,比如说先加速后减速最后到滑块的位置。

本人经过无数次的实验得出结论,将滑块滑动到缺口的位置,然后停留三秒钟,即可通过检测。

结束

本文到这里就结束了,希望我信心苦苦码的这么多字对大家能够有所帮助!在文章的最后给大家附上全部代码!随文章一起发布的有一个代码实现视频,大家感兴趣可以看看。https://live.csdn.net/v/186077。
对于滑块位置的确定可以去上网下载一个屏幕坐标获取工具。

from io import BytesIO
from selenium import webdriver
import time
from selenium.webdriver import ActionChains
from PIL import Image


url = 'https://www.tianyancha.com/?jsid=SEM-BAIDU-PZ-SY-2021112-JRGW'

def compare_pixel(image1, image2, i, j):
#判断两个像素是否相同
#返回的值是RGB的值
#i和j表示图片的横坐标和纵坐标
pixel1 = image1.load()[i, j]
pixel2 = image2.load()[i, j]

#阈值
threshold = 50

if abs(pixel1[0] - pixel2[0])<threshold and abs(pixel1[1] - pixel2[1])<threshold and abs(pixel1[2] - pixel2[2])<threshold:
    return True
else:
    return False

#实现登录
def login():
    #打开页面
    driver = webdriver.Chrome()
    driver.get(url)
    driver.maximize_window()

#点击登录按钮
time.sleep(4)
login_btn = driver.find_element_by_xpath('//*[@id="J_NavTypeLink"]')
login_btn.click()

#跳转到输入账号密码登录页面
time.sleep(2)
login_change = driver.find_element_by_class_name('toggle_box')
login_change.click()

#点击账号密码跳转到输入账号密码页面
time.sleep(2)
driver.execute_script("loginObj.changeCurrent(1);")

#输入账号
time.sleep(2)
inputuid = driver.find_element_by_xpath('//*[@id="mobile"]')
inputuid.send_keys("你的账号")

#输入密码
time.sleep(2)
inputpassword = driver.find_element_by_xpath('//*[@id="password"]')
inputpassword.send_keys('你的密码')

#点击登录
time.sleep(2)
driver.execute_script("loginObj.loginByPhone(event);")#由于获取不到登录按钮,于是直接执行登录按钮对应的js代码

#获取图片左上角位置以及图片大小
time.sleep(2)
img = driver.find_element_by_xpath('/html/body/div[10]/div[2]/div[2]/div[1]')
location = img.location
# print("图片的位置", location)
size = img.size

#得到图片的坐标
top, buttom, left, right = location["y"], location["y"]+size["height"], location["x"], location["x"]+size["width"]
# print(top, buttom, left, right)

#截取滑块验证码的完整图片
scrennshot = driver.get_screenshot_as_png()
scrennshot = Image.open(BytesIO(scrennshot))
captcha1 = scrennshot.crop((int(left), int(top), int(right), int(buttom)))
captcha1.save('./yanzhengma.png')

#单击滑块按钮得到缺口图片并截图
slider = driver.find_element_by_xpath('/html/body/div[10]/div[2]/div[2]/div[2]/div[2]')
ActionChains(driver).click_and_hold(slider).perform()
time.sleep(1)
scrennshot = driver.get_screenshot_as_png()
scrennshot = Image.open(BytesIO(scrennshot))
captcha2 = scrennshot.crop((int(left), int(top), int(right), int(buttom)))
captcha2.save('./yanzhengma2.png')
time.sleep(2)

#从滑块的右侧开始逐一比对RGB值来寻找缺口位置
left = 77
has_find = False
#i和j分别是图片的横坐标和纵坐标
for i in range(left, captcha1.size[0]):
    if has_find:
        break
    for j in range(captcha1.size[1]):
        if not compare_pixel(captcha1, captcha2, i, j):
            left = i    #进入这个if条件即表示寻到了缺口所在的位置,将缺口的横坐标赋值给left
            has_find = True
            break

#需要移动的距离减去滑块距离左边边框的位置从而得到实际需要移动的距离
move = left - 20

#拖动滑块到缺口位置
ActionChains(driver).move_by_offset(xoffset=move, yoffset=0).perform()
# time.sleep(1)
ActionChains(driver).pause(3).perform()
ActionChains(driver).release().perform()
time.sleep(10)




if __name__ == '__main__':
login()
  • 16
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值