我电脑缩放比例为150%,所以图片坐标都乘以1.5,然后把图片缩小一半,提交超级鹰,返回坐标,坐标再乘以2(因为之前缩小一半),再乘以2/3(电脑缩放比例为150%,还原为100%),整个代码跑得通,就是到点击验证码坐标时不对,不知道是我代码错了还是超级鹰返回的坐标有问题。
思路:截图➡图片处理➡提交超级鹰➡返回坐标
import time,random
from posixpath import split
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from lib2to3.pgen2 import driver
from selenium import webdriver
from PIL import Image
from chaojiying import Chaojiying_Client
#隐藏 WebDriver 提示条和自动化扩展信息
option = webdriver.ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])
#进入开发者模式,去除滑块验证
option.add_experimental_option('useAutomationExtension', False)
driver = webdriver.Chrome(options=option)
driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {'source': 'Object.defineProperty(navigator, "webdriver", {get: () => undefined})' })
#登录
def login():
#访问某宝,窗口最大化
driver.get('https://www.bilibili.com')
driver.maximize_window()
if driver.find_element(by=By.CLASS_NAME,value='header-login-entry'):
driver.find_element(by=By.CLASS_NAME,value='header-login-entry').click()
time.sleep(3)
driver.find_element(by=By.XPATH,value='//*[@class="bili-mini-account"]/input').send_keys('账号')
driver.find_element(by=By.XPATH,value='//*[@class="left"]/input').send_keys('密码')
driver.find_element(by=By.XPATH,value='//*[@class="universal-btn login-btn"]').click()
time.sleep(3)
#验证码截图
def save_img():
#对当前页面截图保存
driver.save_screenshot(r'selenium案例\B站\page.png')
#定位验证码图片的位置
code_img_ele = driver.find_element(by=By.XPATH,value='//*[@class="geetest_panel_box geetest_no_logo geetest_panelshowclick"]')
#获取验证码左上角的坐标x,y
location = code_img_ele.location
#获取验证码图片的长宽
size = code_img_ele.size
print(location)
print(size)
#左上角和右下角的坐标
rangle = (
int(location['x']*1.5), #乘以1.5为电脑系统缩放比例,否则定位不准
int(location['y']*1.5),
int((location['x']+size['width'])*1.5),
int((location['y']+size['height'])*1.5)
)
print(rangle)
i = Image.open(r'selenium案例\B站\page.png')
#crop根据rangle元组内的坐标进行裁剪
frame = i.crop(rangle)
frame.save(r'selenium案例\B站\code.png')
return code_img_ele
#图片缩小一半
def narrow_img():
#缩小图片
code = Image.open(r'selenium案例\B站\code.png')
#图片尺寸缩小一半提交超级鹰
small_width = int(code.size[0]/2)
small_height = int(code.size[1]/2)
print(small_width,small_height)
small_img = code.resize((small_width,small_height))
small_img.save(r'selenium案例\B站\small_img.png')
print(code.size,'\n',small_img.size)
#缩小后的图片提交超级鹰
def submit_img():
#将验证码提交给超级鹰识别
chaojiying = Chaojiying_Client('账号','密码','938224')# 用户中心>>软件ID 生成一个替换 96001
im = open(r'selenium案例\B站\small_img.png','rb').read()# 本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
print(chaojiying.PostPic(im,9004)['pic_str'])# 9004是验证码类型
result = chaojiying.PostPic(im,9004)['pic_str']
print(type(result))
return result
#对返回坐标进行处理
def parse_data(result):
all_list = []# 要存储即将被点击的点的坐标 [[x1,y1],[x2,y2]]
if '|' in result:
list_1 = result.split('|')
count_1 = len(list_1)
for i in range(count_1):
xy_list = []
x = int(list_1[i].split(',')[0])
y = int(list_1[i].split(',')[1])
xy_list.append(x)
xy_list.append(y)
all_list.append(xy_list)
else:
x = int(result.split(',')[0])
y = int(result.split(',')[1])
xy_list = []
xy_list.append(x)
xy_list.append(y)
all_list.append(xy_list)
return all_list
#网页自动点击
def click_codeimg(all_list,code_img_ele):
# 遍历列表,使用动作链对每一个列表元素对应的x,y指定的位置进行点击操作
# x,y坐标乘2和2/3,是由于之前图片缩放过,所以*2,2/3是因为本人电脑桌面缩放比例为150%,需要还原成1
for l in all_list:
x = l[0]*2*0.666
y = l[1]*2*0.666
# 将点击操作的参照物移动到指定的模块,
# 若用方法二获取的验证码图片,要添加下面代码对code_img_ele赋值
# code_img_ele = bro.find_element_by_xpath('/html/body/div[2]/div[2]/div[6]/div/div/div[2]/div[1]/div/div[2]/img')
ActionChains(driver).move_to_element_with_offset(code_img_ele,x,y).click().perform()
print('点击已完成')
time.sleep(random.random())
time.sleep(random.random())
#完成动作链点击操作后,定位确认按钮并点击
driver.find_element(by=By.XPATH,value='//*[@class="geetest_commit_tip"]').click()
print('登录成功')
def main():
#进入登录界面,输入账号密码
login()
#保存页面截图,并根据坐标裁剪获取验证码图片
code_img_ele = save_img()
#缩小图片
narrow_img()
#将图片提交给超级鹰,获取返回值
result = submit_img()
#解析返回值,将数据格式化
all_list = parse_data(result)
#在页面验证码上完成点击操作
click_codeimg(all_list,code_img_ele)
if __name__=='__main__':
main()