python爬虫之利用selenium+opencv识别滑动验证并模拟登陆知乎功能
作者:eliwang 发布时间:2023-10-17 22:33:37
标签:selenium,opencv,滑动验证
滑动验证距离
分别获取验证码背景图和滑块图两张照片,然后利用opencv库,通过高斯模糊和Canny算法进行处理,然后通过matchTemplate方法进行两张图的匹配,获得滑动距离。需要注意的是,知乎验证码在进行操作的时候,需要在原有基础上再向右偏移10px距离
def get_distance(self, bg_img_path='./bg.png', slider_img_path='./slider.png'):
"""获取滑块移动距离"""
# 背景图片处理
bg_img = cv.imread(bg_img_path, 0) # 读入灰度图片
bg_img = cv.GaussianBlur(bg_img, (3, 3), 0) # 高斯模糊去噪
bg_img = cv.Canny(bg_img, 50, 150) # Canny算法进行边缘检测
# 滑块做同样处理
slider_img = cv.imread(slider_img_path, 0)
slider_img = cv.GaussianBlur(slider_img, (3, 3), 0)
slider_img = cv.Canny(slider_img, 50, 150)
# 寻找最佳匹配
res = cv.matchTemplate(bg_img, slider_img, cv.TM_CCOEFF_NORMED)
# 最小值,最大值,并得到最小值, 最大值的索引
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
# 例如:(-0.05772797390818596, 0.30968162417411804, (0, 0), (196, 1))
top_left = max_loc[0] # 横坐标
return top_left
滑块运动轨迹
模拟人的行为,到缺口位置时,继续向后滑动一段距离,然后再回退到准确位置
def get_tracks(self, distance):
'''滑动轨迹 '''
tracks = []
v = 0
t = 0.2 # 单位时间
current = 0 # 滑块当前位移
distance += 10 # 多移动10px,然后回退
while current < distance:
if current < distance * 5 / 8:
a = random.randint(1, 3)
else:
a = -random.randint(2, 4)
v0 = v # 初速度
track = v0 * t + 0.5 * a * (t ** 2) # 单位时间(0.2s)的滑动距离
tracks.append(round(track)) # 加入轨迹
current += round(track)
v = v0 + a * t
#回退到大致位置
for i in range(5):
tracks.append(-random.randint(1, 3))
return tracks
鼠标滑动操作
通过selenium中的鼠标动作链,按照滑动轨迹进行滑动
def mouse_move(self,slide,tracks):
'''鼠标滑动'''
#鼠标点击滑块并按照不放
ActionChains(self.driver).click_and_hold(slide).perform()
#按照轨迹进行滑动,
for track in tracks:
ActionChains(self.driver).move_by_offset(track, 0).perform()
ActionChains(self.driver).release(slide).perform()
规避知乎selenium检测
使用selenium自动化测试爬取知乎的时候出现了:错误代码10001:请求异常请升级客户端后重新尝试,这个错误的产生是由于知乎可以检测selenium自动化测试的脚本
使用chrome的远程调试模式结合selenium来遥控操作chrome进行抓取,这样就会规避selenium被网站检测到
添加环境变量
将chrome.exe的目录添加到系统环境变量,比如C:\Program Files\Google\Chrome\Application,这样就可以直接在命令行输入chrome.exe启动浏览器
打开cmd窗口,执行命令
chrome.exe --remote-debugging-port=9222 --user-data-dir="E:\eliwang\selenium_data"
注意端口不要被占用,user-data-dir用来指明配置文件的路径,自定义
此时会开启浏览器,并打开一个新的标签页
selenium接管的主要代码
options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
关闭浏览器窗口
1、使用浏览器对象的close()方法,quit()方法不行。
2、手动打开,手动关闭
完整登陆代码
# coding:utf-8
import cv2 as cv
import time
import random
from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait as WAIT
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from urllib.request import urlretrieve
class Zhihu_login:
'''知乎模拟登陆'''
def __init__(self):
options = webdriver.ChromeOptions()
#操控chrome浏览器
options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
self.driver = webdriver.Chrome(options=options)
self.wait = WAIT(self.driver, 5)
self.url = 'https://www.zhihu.com/'
self.bg_img_path = './bg.png'
self.slider_img_path = './slider.png'
def run(self):
'''执行入口'''
self.driver.get(self.url)
try:
if WAIT(self.driver,3).until(EC.presence_of_element_located((By.ID,'Popover15-toggle'))):
print('登陆成功')
self.save_cookie()
self.driver.close()
except:
# 切换到密码登陆
self.wait.until(EC.element_to_be_clickable((By.XPATH, '//div[contains(@class,"SignFlow-tabs")]/div[2]'))).click()
name_input = self.driver.find_element_by_name('username')
name_input.clear()
name_input.send_keys('账号')
pass_input = self.driver.find_element_by_name('password')
pass_input.clear()
pass_input.send_keys('密码')
self.wait.until(EC.element_to_be_clickable((By.XPATH, '//button[@type="submit"]'))).click() # 点击登陆按钮
time.sleep(1)
#进行滑动验证,最多尝试5次重新验证
if self.slide_verify():
print('登陆成功')
self.save_cookie()
self.driver.close()
else:
print('第1次登陆失败')
for i in range(4):
print('正在尝试第%d次登陆'%(i+2))
if self.slide_verify():
print('第%d次登陆成功'%(i+2))
self.save_cookie()
self.driver.close()
return
print('第%d次登陆失败' % (i + 2))
print('登陆失败5次,停止登陆')
self.driver.close()
def slide_verify(self):
'''滑动验证'''
slider_button = self.wait.until(EC.element_to_be_clickable((By.XPATH, '//div[@class="yidun_slider"]')))
self.bg_img_url = self.wait.until(EC.presence_of_element_located((By.XPATH, '//img[@class="yidun_bg-img"]'))).get_attribute('src') # 获取验证码背景图url
self.slider_img_url = self.wait.until(EC.presence_of_element_located((By.XPATH, '//img[@class="yidun_jigsaw"]'))).get_attribute('src') # 获取验证码滑块图url
urlretrieve(self.bg_img_url, self.bg_img_path)
urlretrieve(self.slider_img_url, self.slider_img_path)
distance = self.get_distance(self.bg_img_path, self.slider_img_path)
distance += 10 # 实际移动距离需要向右偏移10px
tracks = self.get_tracks(distance)
self.mouse_move(slider_button,tracks)
try:
element = self.wait.until(EC.presence_of_element_located((By.ID,'Popover15-toggle')))
except:
return False
else:
return True
def save_cookie(self):
cookie = {}
for item in self.driver.get_cookies():
cookie[item['name']] = item['value']
print(cookie)
print('成功获取登陆知乎后的cookie信息')
def mouse_move(self,slide,tracks):
'''鼠标滑动'''
#鼠标点击滑块并按照不放
ActionChains(self.driver).click_and_hold(slide).perform()
#按照轨迹进行滑动,
for track in tracks:
ActionChains(self.driver).move_by_offset(track, 0).perform()
ActionChains(self.driver).release(slide).perform()
def get_distance(self, bg_img_path='./bg.png', slider_img_path='./slider.png'):
"""获取滑块移动距离"""
# 背景图片处理
bg_img = cv.imread(bg_img_path, 0) # 读入灰度图片
bg_img = cv.GaussianBlur(bg_img, (3, 3), 0) # 高斯模糊去噪
bg_img = cv.Canny(bg_img, 50, 150) # Canny算法进行边缘检测
# 滑块做同样处理
slider_img = cv.imread(slider_img_path, 0)
slider_img = cv.GaussianBlur(slider_img, (3, 3), 0)
slider_img = cv.Canny(slider_img, 50, 150)
# 寻找最佳匹配
res = cv.matchTemplate(bg_img, slider_img, cv.TM_CCOEFF_NORMED)
# 最小值,最大值,并得到最小值, 最大值的索引
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
# 例如:(-0.05772797390818596, 0.30968162417411804, (0, 0), (196, 1))
top_left = max_loc[0] # 横坐标
return top_left
def get_tracks(self, distance):
'''滑动轨迹 '''
tracks = []
v = 0
t = 0.2 # 单位时间
current = 0 # 滑块当前位移
distance += 10 # 多移动10px,然后回退
while current < distance:
if current < distance * 5 / 8:
a = random.randint(1, 3)
else:
a = -random.randint(2, 4)
v0 = v # 初速度
track = v0 * t + 0.5 * a * (t ** 2) # 单位时间(0.2s)的滑动距离
tracks.append(round(track)) # 加入轨迹
current += round(track)
v = v0 + a * t
#回退到大致位置
for i in range(5):
tracks.append(-random.randint(1, 3))
return tracks
if __name__ == '__main__':
Zhihu_login().run()
来源:https://www.cnblogs.com/eliwang/p/15260822.html
![](https://www.aspxhome.com/images/zang.png)
![](https://www.aspxhome.com/images/jiucuo.png)
猜你喜欢
- 有2个不同的方法增加用户:通过使用GRANT语句或通过直接操作MySQL授权表。比较好的方法是使用GRANT语句,因为他们是更简明并且好像错
- 只是粗略的知道yield可以用来为一个函数返回值塞数据,比如下面的例子:def addlist(alist): &nbs
- 前言在php开发过程中,获取文件扩展名是非常常见的需求。比如我们在上传文件的时候,首先需要判断文件类型是否为我们允许上传的类型。这个时候就需
- 如何处理DataFrame的inf值在用DataFrame计算变化率时,例如(今天-昨天) / 昨天恰好为(2-0) / 0时,这些结果数据
- 在java的应用中,我们经常会对数据库进行必要的操作,下来我们就了解一下如何用java连接mysql数据库 以及java连接sql serv
- 一:取字符串中第几个字符print "Hello"[0] 表示输出字符串中第一个字符print "Hello&
- Python中可以用docx来生成word文档,docx中可以自定义文字的大小和字体等。其中要整体修改文字的字体大小和字体,可以用以下方法:
- 一.概述:Selenium是一个用于Web应用程序测试的工具,本文使用的是Selenium 2。Selenium就是一套类库,不依赖于任何测
- 1、设置数据库模式为简单模式:打开SQL企业管理器,在控制台根目录中依次点开Microsoft SQL Server-->SQL Se
- 目前广泛使用的图像分类数据集之一是MNIST数据集。如今,MNIST数据集更像是一个健全的检查,而不是一个基准。为了提高难度,我们将在接下来
- ASP有一个最重要的功能,就是它可以让你非常轻松地连接数据库。通常都是和一个Access或者一个SQL数据库相连。因为Access是最容易起
- 最近在D4得到一本(美) Penny Mcintire写的《Visual Design for the Modern Web》.突然觉得可用
- Django 提供内置的视图(view)函数用于处理登录和退出 (以及其他奇技淫巧),但在开始前,我们来看看如何手工登录和退出。 Djang
- 要求,输入一串数字,并以列表的形式打印出来。number = input('请输入一串数字:') print(number)
- 1. 安装Opencv包pip install opvencv-python2.实现代码:视频转为图片:import cv2cap=cv2.
- 一.filter函数简介filter函数主要用来筛选数据,过滤掉不符合条件的元素,并返回一个迭代器对象,如果要转换为列表list或者元祖tu
- 门限回归模型(Threshold Regressive Model,简称TR模型或TRM)的基本思想是通过门限变量的控制作用,当给出预报因子
- 强大的group by 代码如下:select stdname, isnull(sum( case stdsubject whe
- 加密算法分类 对称加密算法:对称加密采用了对称密码编码技术,它的特点是文件加密和解密使用相同的密钥发送方和接收方需要持有同一把密钥,发送消息
- ORM模型:ORM模型对于后端开发来说肯定是不陌生的,包括很多后端框架比如django,现在都自带这个模型了ORM(Object Relat