from selenium.webdriver import Chrome, ActionChains
from selenium.webdriver import Chrome
from selenium.webdriver.common.keys import Keys
#显示等待
import requests
from selenium.webdriver.support.wait import WebDriverWait
from time import sleep
import cv2,base64
from Slide import Slide
#
driver = Chrome()
driver.maximize_window()
driver.implicitly_wait(10)
driver.get('https://passport.jd.com/new/login.aspx')
driver.find_element_by_xpath('//*[@id="content"]/div[2]/div[1]/div/div[3]/a').click()
driver.find_element_by_xpath('//*[@id="loginname"]').send_keys('majinihaobang')
driver.find_element_by_xpath('//*[@id="nloginpwd"]').send_keys('majizhendehaobang')
driver.find_element_by_xpath('//*[@id="loginsubmit"]').click()
sleep(3)
slide = Slide(driver)
slide.slide_verify('//*[@id="JDJRV-wrap-loginsubmit"]/div/div/div/div[1]/div[2]/div[1]/img',
'//*[@id="JDJRV-wrap-loginsubmit"]/div/div/div/div[1]/div[2]/div[2]/img',
jsonp='{"zoom":1.25,"template-zoom":0.76,"offset":3,"offset-x":1,"offset-y":0,"slide":"pyautogui","target":"./target.png","template":"./template.png","host":"","refresh":"//div/div/div/div[1]/div[1]/div[2]/span"}')
# driver.close()
from selenium.webdriver import Chrome, ActionChains
from selenium.webdriver import Chrome
from selenium.webdriver.common.keys import Keys
#显示等待
import requests,json,pyautogui,random
from selenium.webdriver.support.wait import WebDriverWait
from time import sleep
import cv2,base64
class Slide:
def __init__(self,driver):
self.driver = driver
self.target_xpath = ""
self.template_xpath = ""
self.base_param = None
def FindPic(self,target="./target.png",template="./template.png"):
"""
找出图像中最佳的匹配位置
param targer:目标(背景图)
param template: 模板即需要找的图
return : 返回最佳的匹配及其最差的匹配和对应 的坐标
"""
# 读取图片 背景图片
target_rgb = cv2.imread(target)
# 灰度处理
target_gray = cv2.cvtColor(target_rgb, cv2.COLOR_BGR2GRAY)
# 读取模块图片
temlate_rgb = cv2.imread(template,0)
# 匹配模块位置
res = cv2.matchTemplate(target_gray,temlate_rgb,cv2.TM_CCOEFF_NORMED)
# 获取最佳与最差匹配
value = cv2.minMaxLoc(res)
print(value)
# 反回最佳的匹配值
return value[2][0]
def slide_img(self,src='',host=None,filepath="./t.png"):
"""
下载验证码图片
:param src: 图片
:param host: 相对地址需要添加的主机地址
:param filepath: 保存图片的位置
:return:
"""
if src is None:
return None
# 处理base64图片
if src.startswith('data:'):
src = src[src.find('base64,')+7:]
self.base64_to_img(src,filepath=filepath)
return
if not src.startswith('http'):
src = host+"/"+src
# 使用requests下载图片
response = requests.get(src)
img = response.content
with open(filepath,'wb')as f:
f.write(img)
return
def base64_to_img(self,base64_str,filepath="./t.png"):
"""
base64图片转二进制存储
:param base64_str: base64字符串
:param filepath: 保存图片地址
:return:
"""
imgdata = base64.b64decode(base64_str)
file = open(filepath,'wb')
file.write(imgdata)
file.close()
def slide_verify(self,xpath1,xpath2,jsonp=None):
"""
验证码滑动实现
:type jsonp: object
:param xpath1: 背景图片定位器
:param xpath2: 模板图片定位器
:param jsonp: 微调参数json配置字符串
jsonp 详解:
slide: 滑动方式,selenium : 使用selenium原生滑动 更稳定:pyautogui:效验滑动轨迹的滑动
target: 背景图片保存位置
template: 模块图片保存位置
host: 图片相对地址host主机地址
offset-x: 开始位置,x左边偏移(右边为正,左边为负)
offset-y: 开始位置,y左边偏移(下方为正,上方为负)
offset: 滑动位置偏移量(右边为正,左边为负)
temlate-zoom: 模板文件缩放比例
zoom:windows 缩放比例
refresh: 刷新重试元素xpath
:return:
"""
self.base_param = {
'zoom':1,
'target':'./target.png',
'template':'./template.png',
'host':'',
'offset-x':0,
'template-zoom':1,
'offset-y':0,
'slide':'selenium',
'refresh':'',
}
# 获取第一次匹配的y坐标开始位置
y = 0
# 处理微调函数
if not jsonp is None:
jsonp = json.loads(jsonp)
self.base_param.update(jsonp)
print(self.base_param)
i = 0
# 重试10次
while i<10:
# 如果不是第一次那么久等待三秒
if i>0:
sleep(3)
# 获取背景图片元素
try:
ele = self.driver.find_element_by_xpath(xpath1)
print("获取到xpath1",xpath1)
except Exception as e:
break
# 如果匹配成功,背景图不显示则返回成功
succ = False
try:
succ = ele.is_displayed()
except:
break
if i>0 and succ == False:
break
else:
# 如果滑动失败,则点击重试元素,重新获取图片
if i>0 and self.base_param["refresh"] != "":
eler = self.driver.find_element_by_xpath(self.base_param["refresh"])
eler.click()
sleep(2)
i +=1
# 背景图片地址
src1 = ele.get_attribute('src')
# 如果是selenium滑动,需要计算图片缩放比例
w1 = ele.size['width']
# 获取滑块元素
ele1 = self.driver.find_element_by_xpath(xpath2)
# 获取滑块图片
src2 = ele1.get_attribute('src')
# 下载图片
self.slide_img(src1,filepath=self.base_param['target'],host=self.base_param['host'])
self.slide_img(src2,filepath=self.base_param['template'],host=self.base_param['host'])
# 获取背景图片的实际大小
img = cv2.imread(self.base_param['target'])
w2 = img.shape[1]
# 获取匹配到滑块的x坐标滑动距离
x = self.FindPic(target=self.base_param['target'],template=self.base_param['template'])
print(x)
# 使用selenium原生滑动
if self.base_param['slide'] == 'selenium':
# 计算缩放比例,计算偏移量
x = int(x * w1/w2)
print(x)
return
# action = ActionChains(self.driver) # 实例一个action对象
# action.click_and_hold(ele1).perform() # perfrom 用来执行ActionChains中存储的行为
# action.move_by_offset(x,0).pause(0.5)
# action.release().perform()
# 使用pyautogui滑动
else:
# 获取元素位置
ele_x = ele.location['x']
ele_y = ele.location['y']
# 计算缩放比例
if self.base_param['zoom'] != 1:
x = int(x*self.base_param['zoom'])
ele_x = int(ele_x * self.base_param['zoom'])
ele_y = int(ele_y * self.base_param['zoom'])
# 计算开始位置x的偏移量
if self.base_param['offset-x'] !=0:
ele_x = ele_x + self.base_param['offset-x']
# 计算开始位置y的偏移量
if self.base_param['offset-y'] != 0:
ele_y = ele_y+self.base_param['offset-y']
# 计算移动距离模板的缩放比例
if self.base_param['template-zoom'] != 1:
x = int(x * self.base_param['template-zoom'])
# 计算移动距离x的偏移量
if self.base_param['offset'] != 0:
x = x+self.base_param['offset']
# 取第一次元素y的坐标
if i == 1:
y = ele_y
print(ele_x,ele_y)
# 调用pyautogui,实现轨迹变化滑动
self.slide_by_pyautogui(ele_x,y,x)
def slide_by_pyautogui(self, x, y, offset):
"""
使用pyautogui滑动
:param x: 开始位置x
:param y: 开始位置y
:param offset: 互动横坐标偏移量
:return:
"""
xx = x+offset
pyautogui.moveTo(x,y,duration=0.1)
pyautogui.mouseDown() # 按下鼠标键
y += random.randint(9,19)
pyautogui.moveTo(x + int(offset * random.randint(15,23)/20),y,duration=0.28)
y += random.randint(-9,0)
# 鼠标拖到坐标(1566,706)处
pyautogui.moveTo(x + int(offset * random.randint(17,21)/20),y,duration=(random.randint(20,31))/100)
y += random.randint(0,8)
pyautogui.moveTo(xx,y,duration=0.3)
pyautogui.mouseUp() # 松开鼠标