这里我们选择用《网络爬虫》作者:崔庆才提供的实战网站https://captcha1.scrape.center/
对于输入框等输入直接略过进入正题(在这里我有个疑惑,有没有人在点击登录的时候偶尔会出现多次点击一样没有反应的情况,希望可以提供解决方案
在这之前需要你拥有一些opencv的知识,这样更方便理解,如果你看不懂的话可以硬记
在完成登录之后会遇到验证码

首先我们在遇到这种验证码的时候要得到俩样东西
只有缺口的背景图片
需要滑动的图片
在得到后我们思路是:用opencv把缺口图片与需要滑动的图片进行模板匹配得到最大的值,最大的值对应的坐标x,然后就可以进行拖动,这时候要尽量不能太快,就可以达到效果了
只有缺口的图片如何获得?

思路:找到需要滑动的图片,把它去除就可以得到只有缺口的背景图片
broswer.execute_script("document.querySelector('.geetest_canvas_slice').style.display='none'")#用JavaScript代码找到对应的节点然后把需要滑动的图片修改成不显示
然后可以进行截图
这里用的是寻找到对应元素然后进行截图的方法
broswer.find_element(by.By.XPATH,'.//canvas[@class="geetest_canvas_bg geetest_absolute"]').screenshot('bg.jpg')
需要滑动的图片怎么找?
在你看到上一个用找对应的元素方法进行截图后你可能会想故技重施,但我试过了后来得到的好像还是只带缺口的背景图
这时候就要用另一种思路:找到滑动图片的元素然后转换成base64,在把base64写成图片
data=broswer.execute_script('return document.querySelector(".geetest_canvas_slice").toDataURL()')#找出滑动图片元素转换成base64
base64url=data.split('data:image/png;base64')[1]#在转换后会得到(data:imgae/png;base64,数据)这种,我们只要得到数据就可以变成图片
png=base64.b64decode(base64url)#进行解码得到二进制
with open('template.jpg','wb') as f:#写入时候要用二进制进行写入
f.write(png)
会得到图片(由于验证码刚刚按错切换了,只能拿之前的了)


这时候要注意,template.jpg是和bg大小一样的,所以进行模板匹配效果会非常差
这个是template.jpg的分辨率

所以要进行切割,这个可以用opencv处理
用opencv处理图片
bg=cv2.imread('bg.jpg')#读取只带缺口的背景图片
template=cv2.imread('template.jpg')#读取滑动的图片
#opencv的处理步骤都是先读取在转化灰度图片
cbg=cv2.cvtColor(bg,cv2.COLOR_BGR2GRAY)#转化灰度图片
ctem=cv2.cvtColor(template,cv2.COLOR_BGR2GRAY)#转化灰度图片
#该代码是为了把template.jpg的滑动图片轮廓给找出来
contours=cv2.findContours(ctem,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)[0]
#这个其实没必要用for的,但我懒得改了,其实结果也只会循环一次而已
for i in contours:
x,y,w,h=cv2.boundingRect(i)
#为什么要先纵坐标再横坐标,这是因为...好像是numpy数组的原因,算了你记着就行
cv2.imwrite('newtemplate.jpg',template[y:y+h,x:x+w])

经过处理得到的是这个这时候

这时候就可以进行匹配了
template=cv2.imread('newtemplate.jpg')
cv=cv2.cvtColor(template,cv2.COLOR_BGR2GRAY)
# 进行多个匹配模式,我发现TM——SQDIFF_NORMED效果最好
#我猜测这个模式就是用来在这种情况下用的
data=cv2.matchTemplate(cbg,cv,cv2.TM_SQDIFF_NORMED)
return cv2.minMaxLoc(data)[3][0]#会得到 最小值,最大值,最小值坐标,最大值坐标,这里我们只要最大值x坐标
滑动的问题
思路: 我们要先找到滑动按钮再进行点击滑动按钮并且点击不放,然后移动x个位置,然后再松开
这过程需要我们不能这么快也不能这么慢
#place就是上一个返回的x距离
button=broswer.find_element(by.By.XPATH,'.//div[@class="geetest_slider_button"]')#找到滑动按钮
action=ActionChains(broswer)
action.click_and_hold(button).perform()#执行点击并且不松开
#下面部分是模拟一些滑动速度,我乱写的没想到真的成功了
x=0
while True:
number=random.randint(5,10)#每次移动大概5到10个像素之间
if x+number>=place:#在最后加上了可能会超过所以要设置(看不懂可以忽略不计)
#这里是用来移动的,代码意思是让鼠标移动多少位置 设置random.randint这里可能是点晴之笔,我之前一直没办法成功
#后来说在滑动的时候可能会有上下微微的偏移,所以需要设置
#过程中如果有点慢,看我下面操作设置
action.move_by_offset(place-x,random.randint(-2,2)).perform()
action.release().perform()
break#到这里大概就执行成功了
else:
x+=number
action.move_by_offset(number,random.randint(-2,2)).perform()
关于移动的时候速度可能会太慢
这里可以去时候要去Lib\site-packages\selenium\webdriver\common\actions 找到pointer_actions.py
把duration默认250进行修改,我改成了1

然后就成功了
