1.背景
在爬虫领域中,可能你有很多中破解手段,但是随着产品的迭代和技术新进,反爬措施也就趋于智能化,我们也就要模拟人的想法来破解了
2.目标
本节将介绍基于pyppeteer技术来模拟浏览器方式的滑块验证码图片
主要步骤:
a.获取没有缺口的图片/含缺口图片(目的将两种类型图片进行比较,一半情况下前端是隐藏了背景图,需要你通过css调控来发现原图在那个标签内)
b.计算缺口离左边界的距离
3.步骤展示
比较通过改css,display:none与block,查找你的目标图片
然后使用模拟浏览器方式,向浏览器中注入js
fulljs = """
() => { return document.getElementsByClassName("geetest_canvas_fullbg")[0].toDataURL("image/png") }
"""
fadejs = """
() => {
return document.getElementsByClassName("geetest_canvas_bg geetest_absolute")[0].toDataURL("image/png")}
"""
上面代码表示将对应图片转为base64(这样的好处避免了截图的不准确而带来比较差异带来的影响)
接下来就可以根据图片差异(两种图片相减就可以得到差异部分)
4.详细代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Author:Lijiacai
Email:[email protected]
===========================================
[email protected]
===========================================
"""
import base64
import os
import sys
import json
import asyncio
import time
import numpy as np
import cv2
from pyppeteer import launch
from PIL import Image, ImageChops
import matplotlib.pyplot as plt
launch_args = {
"headless": False,
"args": [
"--start-maximized",
"--disable-infobars",
"--ignore-certificate-errors",
"--log-level=3",
"--enable-extensions",
"--window-size=1920,1080",
"--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36",
],
}
async def get_decode_image(filename, data):
_, img = data.split(",")
img = base64.b64decode(img)
with open(filename, "wb") as f:
f.write(img)
async def main():
browser = await launch(**launch_args)
page = await browser.newPage()
await page.setViewport({"width": 1920, "height": 1080})
await page.goto(url="http://sd.gsxt.gov.cn/index.html")
await page.waitForXPath("//input[@id='keyword']")
await asyncio.sleep(2)
elem = await page.xpath("//input[@id='keyword']")
await elem[0].type("百度")
await asyncio.sleep(2)
await page.waitForXPath("//img[@id='btn_query']")
elem = await page.xpath("//img[@id='btn_query']")
await elem[0].click()
await asyncio.sleep(3)
fulljs = """
() => { return document.getElementsByClassName("geetest_canvas_fullbg")[0].toDataURL("image/png") }
"""
fadejs = """
() => {
return document.getElementsByClassName("geetest_canvas_bg geetest_absolute")[0].toDataURL("image/png")}
"""
full_img = await page.evaluate(fulljs)
await get_decode_image(filename="fullbg.png", data=full_img)
await asyncio.sleep(0.1)
fade_img = await page.evaluate(fadejs)
await get_decode_image(filename="fadebg.png", data=fade_img)
await asyncio.sleep(0.1)
a = await compute_gap(img1="fullbg.png", img2="fadebg.png")
elem = await page.xpath("//div[@class='geetest_slider_button']")
await elem[0].hover()
await page.mouse.down()
await page.mouse.move(int(840 + a), 450)
await page.mouse.up()
await asyncio.sleep(1000)
await browser.close()
async def compute_gap(img1, img2):
"""计算缺口偏移 这种方式成功率很高"""
img1 = Image.open(img1)
img2 = Image.open(img2)
# 将图片修改为RGB模式
img1 = img1.convert("RGB")
img2 = img2.convert("RGB")
# 计算差值
diff = ImageChops.difference(img1, img2)
plt.figure('pokemon')
plt.imshow(diff, cmap='gray')
plt.show()
table = []
for i in range(256):
if i < 50:
table.append(0)
else:
table.append(1)
# 灰度图
diff = diff.convert("L")
#
# # 二值化
diff = diff.point(table, '1')
# print(diff.getbbox()) # 这里可以直接获取差异坐标点坐标顺序为左上右下
#
left = 43
# # 这里做了优化为减少误差 纵坐标的像素点大于5时才认为是找到
# # 防止缺口有凸起时有误差
for w in range(left, diff.size[0]):
lis = []
for h in range(diff.size[1]):
if diff.load()[w, h] == 1:
lis.append(w)
if len(lis) > 5:
return w
if __name__ == '__main__':
asyncio.get_event_loop().run_until_complete(main())
5.上面教程只是一个思路,代码中没有模拟人点鼠标的运动轨迹,但是测试是可以发现,按钮是移动到了缺口位置
如果阅读者需要模拟轨迹,只需要把偏移的方式变下,目前我的代码直接到move到了目标点