首先需要打开浏览器两个target,tagget[0]用来正常加载目标网页,target[1]用来准备加载验证码图片
await browser.newPage() # 新增一个tab用作验证码截图,一起截的话两个图片会重叠在一起
pages = await browser.pages() # 获取所有page,page[0]正常浏览page[1]用作加载图片
await pages[0].setViewport({'width': 1024, 'height': 768})
await pages[0].goto('http://dun.163.com/trial/jigsaw',{'waitUntil':'domcontentloaded'})
下载验证码图片,主要逻辑是下面这个函数,先获得图片的url,然后用target1打开,再通过元素级截图把验证码截下来。
async def get_img(pages,img_str,img_path):
img_url = await pages[0].evaluate(img_str)
await pages[1].goto(img_url)
img = await pages[1].waitForSelector('body > img')
await img.screenshot({'path':img_path})
获取图片后是计算距离,计算距离的核心是教程(六)的算法
async def calc_distance(bg_img,flag_img):
gray = cv2.imread(bg_img,0)
flag = cv2.imread(flag_img,0)
w,h = flag.shape[::-1]
res = cv2.matchTemplate(gray,flag,cv2.TM_CCOEFF_NORMED)
L = 0
R = 1
while 1:
threshold = (L+R)/2
loc = np.where(res >= threshold)
if len(loc[0]) > 1:
L += (R-L) /2
elif len(loc[0]) == 1:
pt = loc[::-1]
break
elif len(loc[0]) < 1:
R -= (R-L) / 2
return pt[0][0]
计算后的距离需要等比例放大,真实距离=计算距离*页面元素框长度/图片宽度
t_distance = round(distance*318/320)
通过
await pages[0].bringToFront()
告诉浏览器页面标签0前置
然后是开始拖动滑块操作
async def slide(pages,distance):
el = await pages[0].querySelector('div.yidun_slider')
box = await el.boundingBox() # 一定要先用选择器再取box函数,串联起来不行
await pages[0].waitFor(2 * 1000)
await pages[0].hover('div.yidun_slider')
await pages[0].waitFor(2 * 1000)
await pages[0].mouse.down()
await pages[0].mouse.move(box['x']+distance+20+9,box['y'],{'steps':3})
await pages[0].mouse.up()
获取滑块坐标,然后滑动距离,这里await pages[0].mouse.move(box['x']+distance+20+9,box['y'],{'steps':3})
的20+9是滑块的宽度一半在加一个测试后比较稳定的偏差值。
剩下的部分是验证是否滑动成功,如果不成功则重新滑动。
async def check(pages,BG_IMG_STR, FLAG_IMG_STR, BG_IMG_PATH, FLAG_IMG_PATH):
while 1:
await pages[0].waitFor(1 * 1000)
success_msg = await pages[0].querySelector('div.yidun.yidun--light.yidun--float.yidun--jigsaw.yidun--success')
# error_msg = await pages[0].querySelector('div.m-form-group.login-error > p > span')
if not success_msg:
await drag(pages, BG_IMG_STR, FLAG_IMG_STR, BG_IMG_PATH, FLAG_IMG_PATH)
else:
print("success")
break