chromep模拟抖音人机滑块校验


前言

使用chromedp启动浏览器,打开抖音网页版的时候,一直出现滑块人机校验,就用chromedp模拟拖动滑块

一、监听网页版获取滑块的接口,将图片下载到本地

opts := append(chromedp.DefaultExecAllocatorOptions[:],
    chromedp.Flag("headless", false),
    chromedp.Flag("ignore-certificate-errors", true),
)
var allocCtx context.Context
allocCtx,_ = chromedp.NewExecAllocator(context.Background(), opts...)
ctx,_ := chromedp.NewContext(allocCtx,)

// 过滑块校验
// 监听是否人机校验接口,如果有将两个图片存储到本地 ‪C:\Users\jack\Desktop\pic,供python使用
var requestId network.RequestID
var gapImg string
var bgImg string
chromedp.ListenTarget(ctx, func(ev interface{}) {
    switch ev := ev.(type) {
    case *network.EventRequestWillBeSent:
        if strings.HasPrefix(ev.Request.URL, "https://verify.snssdk.com/captcha/get") {
            requestId = ev.RequestID
        }
    }

    if event, ok := ev.(*network.EventLoadingFinished); ok {
        if requestId != "" && event.RequestID == requestId {
            go func() {
                var data []byte
                if err := chromedp.Run(ctx, chromedp.ActionFunc(func(ctx context.Context) error {
                    var err error
                    data, err = network.GetResponseBody(requestId).Do(ctx)
                    if err != nil {
                        return err
                    }
                    return nil
                })); err != nil {
                    fmt.Println("err ", err)
                }
                bgImgUrl := gjson.Get(string(data), "data").Get("question").Get("url1").String()
                gapImgUrl := gjson.Get(string(data), "data").Get("question").Get("url2").String()
                // 将图片下载到本地
                bgImg = downloadImg(bgImgUrl)
                gapImg = downloadImg(gapImgUrl)
            }()
        }
    }
})

chromedp.Run(
    ctx,
    chromedp.Navigate("https://www.douyin.com/video/7067020209298705668"),
    chromedp.WaitReady("//body"),
)

将图片下载到本地后,把路径存储起来,供计算滑块需要滑动的距离

二、计算滑块需要滑动的距离

此处使用的是python的开源项目: https://github.com/crazyxw/SlideCrack
注意原图的大小和网页中该图片大小是不同的,需要对原图resize

#  抖音人机校验获取的原图,需要缩小大概1.624倍,才能使用
def img_resize(image):
    height, width = image.shape[0], image.shape[1]
    width_new = int(height / 1.624)
    height_new = int(width / 1.624)
    m = 1.624
    img_new = cv2.resize(image, (height_new, width_new))
    return img_new

class SlideCrack(object):
    def __init__(self, gap, bg):
        """
        init code
        :param gap: 缺口图片
        :param bg: 背景图片
        :param out: 输出图片
        """
        self.gap = gap
        self.bg = bg

    @staticmethod
    def clear_white(img):
        # 清除图片的空白区域,这里主要清除滑块的空白
        _img = cv2.imread(img)
        img = img_resize(_img)
        rows, cols, channel = img.shape
        min_x = 255
        min_y = 255
        max_x = 0
        max_y = 0
        for x in range(1, rows):
            for y in range(1, cols):
                t = set(img[x, y])
                if len(t) >= 2:
                    if x <= min_x:
                        min_x = x
                    elif x >= max_x:
                        max_x = x

                    if y <= min_y:
                        min_y = y
                    elif y >= max_y:
                        max_y = y
        img1 = img[min_x:max_x, min_y: max_y]
        return img1

    def template_match(self, tpl, target):
        th, tw = tpl.shape[:2]
        result = cv2.matchTemplate(target, tpl, cv2.TM_CCOEFF_NORMED)
        # 寻找矩阵(一维数组当作向量,用Mat定义) 中最小值和最大值的位置
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
        tl = max_loc
        br = (tl[0] + tw, tl[1] + th)
        # 绘制矩形边框,将匹配区域标注出来
        # target:目标图像
        # tl:矩形定点
        # br:矩形的宽高
        # (0,0,255):矩形边框颜色
        # 1:矩形边框大小
        cv2.rectangle(target, tl, br, (0, 0, 255), 2)
        # cv2.imwrite(self.out, target)
        return tl[0]

    @staticmethod
    def image_edge_detection(img):
        edges = cv2.Canny(img, 100, 200)
        return edges

    def discern(self):
        img1 = self.clear_white(self.gap)
        img1 = cv2.cvtColor(img1, cv2.COLOR_RGB2GRAY)
        slide = self.image_edge_detection(img1)
        _back = cv2.imread(self.bg, 0)
        back = img_resize(_back)
        back = self.image_edge_detection(back)
        slide_pic = cv2.cvtColor(slide, cv2.COLOR_GRAY2RGB)
        back_pic = cv2.cvtColor(back, cv2.COLOR_GRAY2RGB)
        x = self.template_match(slide_pic, back_pic)
        # 输出横坐标, 即 滑块在图片上的位置
        return x

然后开启一个http服务,将两个路径传输过来,最终传回去的就是滑块需要滑动的距离,注意该距离还需要减去一个边缘的距离,大概是6

三、chromedp获取到需要移动的距离后,模拟拖拽

var lap int // 本次人机校验需要滑动的距离
var sel = `#captcha_container > div > div.captcha_verify_img--wrapper.sc-gZMcBi.jzVByM > img.captcha_verify_img_slide.react-draggable.sc-VigVT.ggNWOG`
func DragElement(sel interface{}, xlap int) chromedp.QueryAction {
	fmt.Println("dragElement")
	return chromedp.QueryAfter(sel, func(ctx context.Context, id runtime.ExecutionContextID, node ...*cdp.Node) error {
		if len(node) == 0 {
			fmt.Println("找不到相应node")
			return fmt.Errorf("找不到相关 Node")
		}
		return MouseDragNode(node[0], xlap).Do(ctx)
	})
}

func MouseDragNode(n *cdp.Node, xlap int) chromedp.ActionFunc {
	return func(ctx context.Context) error {
		boxes, err := dom.GetContentQuads().WithNodeID(n.NodeID).Do(ctx)
		if err != nil {
			return err
		}

		box := boxes[0]
		c := len(box)
		if c%2 != 0 || c < 1 {
			return chromedp.ErrInvalidDimensions
		}

		var x, y float64
		for i := 0; i < c; i += 2 {
			x += box[i]
			y += box[i+1]
		}
		x /= float64(c / 2)
		y /= float64(c / 2)

		p := &input.DispatchMouseEventParams{
			Type:       input.MousePressed,
			X:          x,
			Y:          y,
			Button:     input.Left,
			ClickCount: 1,
		}

		// 鼠标左键按下
		if err := p.Do(ctx); err != nil {
			return err
		}

		// 拖动
		p.Type = input.MouseMoved

		t := rand.Intn(20) + 40
		totalX := 0
		// 生成随机的路径,模拟拖动
		for i:=0 ; i < t ; i++ {
			rt := rand.Intn(20) + 20
			chromedp.Run(ctx, chromedp.Sleep(time.Millisecond * time.Duration(rt)))
				x := rand.Intn(2) + 4
				if totalX >= xlap {
					break
				}
				if totalX + x >= xlap {
					x = xlap - totalX
				}

				totalX += x
				y := rand.Intn(2)
				p.Y = p.Y + float64(y)
				p.X = p.X + float64(x)
				if err := p.Do(ctx); err != nil {
					return err
				}
		}
		// 鼠标松开
		p.Type = input.MouseReleased
		return p.Do(ctx)
	}
}		

总结

如果滑块校验多了,会出现汉字校验,目前还没做
其实用chromedp启动浏览器是可以绕过抖音人机校验

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Python抖音滑块是指使用Python编程语言实现对抖音滑块验证码的自动化处理。 抖音滑块验证码通常出现在用户登录、注册等场景中,用于验证用户的真实性。由于滑块验证码需要用户手动滑动滑块,以模拟人类的行为,所以对于大规模的操作或需要频繁验证的场景来说,手动处理滑块验证码非常麻烦且效率低下。 Python抖音滑块解决方案可以通过某些开源的Python库和工具来实现自动滑动滑块,其中常用的是selenium和PIL(Python Imaging Library)库。使用selenium库可以模拟浏览器的操作,包括打开网页、填写表单和点击元素等,而PIL库则提供了图像处理的功能。 实现抖音滑块验证码的自动处理步骤大致如下: 1. 使用selenium库打开包含滑块验证码的抖音登录或注册页面; 2. 使用selenium库获取滑块验证码的背景图和滑块图,并下载保存; 3. 使用PIL库读取保存的背景图和滑块图,并对其进行图像处理,如灰度化、二值化等; 4. 使用图像处理技术找到滑块图在背景图上的位置,得到滑块需要滑动的距离; 5. 使用selenium库模拟鼠标拖动滑块,滑动距离即为上一步得到的距离; 6. 使用selenium库模拟点击登录或注册按钮,完成操作。 通过以上步骤,可以实现对抖音滑块验证码的自动化处理,提高效率和便捷性。同时需要注意的是,为了避免被抖音识别为机器行为,可以加入一些随机因素,如模拟人的操作速度和滑动轨迹等,以增加自动化处理的真实性。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值