说明miraiYuQ的过验证码都需要通过App,对于小白来说还是太麻烦了。所以直接自动通过验证码,如果验证失败,再使用其自带的过验证码方式

好像出现盾牌行的验证码会有问题,懒得修了。又没人用

前提

引入我的工具类,只是用了HTTP请求的工具类而已,你也可以不需要引用,使用另外的方式来请求我的接口

// grade
implementation("me.kuku:utils:2.2.1.1")
// maven
<dependency>
  <groupId>me.kuku</groupId>
  <artifactId>utils</artifactId>
  <version>2.2.1.1</version>
</dependency>

总的来说,就是把获取到的验证码url传给我的api,将会收到ticket

https://api.kukuqaq.com/captcha POST
参数 url -> 验证码url

YuQ-Art

使用YuHook来实现

1、新建一个类,比如我的类是me.kuku.yuq.HookCaptchaUtils,继承于HookRunnable

class HookCaptchaUtils : HookRunnable {
    override fun init(info: HookInfo) {

    }

    private val log = LoggerFactory.getLogger(HookRunnable::class.java)

    override fun preRun(method: HookMethod): Boolean {
        log.info("验证码url: ${method.paras[1]}")


        val url = method.paras[1]!! as String
        val ticket = runBlocking {
            var ticket: String? = null
            for (i in 0..3) {
                log.info("正在尝试第${i + 1}次自动过验证码~~~")
                val jsonNode = OkHttpUtils.postJson("https://api.kukuqaq.com/captcha", mapOf("url" to url))
                if (jsonNode.contains("ticket")) {
                    ticket = jsonNode["ticket"].asText()
                    log.info("自动过验证码成功")
                    break
                }
            }
            ticket
        }
        if (ticket == null) {
            log.info("自动识别验证码失败,转为手动验证验证码")
            return com.icecreamqaq.yuq.artqq.HookCaptchaUtils().preRun(method)
        }
        //        RainUI.webListener(url)
        method.result = CommonResult(200, "Success!", mutableMapOf("ticket" to ticket))
        return true
    }

    override fun postRun(method: HookMethod) {
        println("result: ${method.result}")
    }

    override fun onError(method: HookMethod) = false

}

2、编写一个类替换掉YuQ-Art原有的过滑块方式

class HookYuQArtQQModule: HookRunnable {

    override fun preRun(method: HookMethod): Boolean {
        val yuQArtQQModule = method.paras[0] as YuQArtQQModule
        val context = yuQArtQQModule::class.java.declaredFields[0].also { it.isAccessible = true }
            .get(yuQArtQQModule) as YuContext
        context.putBean(YuQInternalFun::class.java, "", YuQInternalFunArtQQImpl())
        AppClassloader.registerBackList(
            arrayListOf(
                "javafx.",
                "org.w3c",
                "jdk.internal.",
            )
        )
        YuHook.put(
            HookItem(
                "org.artqq.util.TenCentCaptchaUtils",
                "identifyByUrl",
                "me.kuku.yuq.HookCaptchaUtils"
            )
        )
        YuHook.put(
            HookItem(
                "org.artqq.Wtlogin._Login",
                "onSuccessSendVC",
                "com.icecreamqaq.yuq.artqq.HookPhoneCap"
            )
        )
        YuHook.put(
            HookItem(
                "com.baidu.bjf.remoting.protobuf.utils.JDKCompilerHelper",
                "getJdkCompiler",
                "com.icecreamqaq.yuq.artqq.HookProto"
            )
        )
        return true
    }
}

3、在启动之前添加至Yu-Hook

fun main(args: Array<String>) {
    YuHook.put(
        HookItem(
            "com.icecreamqaq.yuq.artqq.YuQArtQQModule",
            "onLoad",
            "me.kuku.yuq.HookYuQArtQQModule"
        )
    )
    YuQArtQQStarter.start(args)
}

YuQ-Mirai

使用YuHook来实现

1、新建一个类,比如我的类是me.kuku.yuq.config.HookSliderCaptcha,继承于HookRunnable

public class HookSliderCaptcha implements HookRunnable {

    private final Logger logger = LoggerFactory.getLogger(HookRunnable.class);

    @Override
    public void init(HookInfo info) {

    }

    @Override
    public boolean preRun(HookMethod method) {
        String url = (String) method.paras[2];
        logger.info("验证码url:" + url);
        String ticket = null;
        try {
            for (int i = 0; i < 3; i++) {
                int num = i + 1;
                logger.info("正在第" + num + "次尝试识别验证码中");
                JsonNode jsonNode = OkHttpUtils.postJson("https://api.kukuqaq.com/captcha", Maps.of("url", url));
                if (jsonNode.contains("ticket")) {
                    logger.info("自动识别验证码成功");
                    ticket = jsonObject.get("ticket").asText();
                    logger.info("ticket:" + ticket);
                    break;
                }
            }
        } catch (Exception ignore) {
        }
        if (ticket == null) {
            logger.info("识别验证码失败,转为yuq-mirai自带的识别方式");
            return false;
        } else {
            method.result = ticket;
        }
        return true;
    }

    @Override
    public void postRun(HookMethod method) {

    }

    @Override
    public boolean onError(HookMethod method) {
        return false;
    }
}

2、在启动之前注入YuHook

fun main(args: Array<String>) {
    YuHook.put(
        HookItem(
            "net.mamoe.mirai.utils.StandardCharImageLoginSolver",
            "onSolveSliderCaptcha",
            "me.kuku.yuq.config.HookSliderCaptcha"
        )
    )
    YuQMiraiStart.start(args)
}

Mirai

自定义验证码实现

class KuKuLoginSolver: LoginSolver() {

    private val standardCharImageLoginSolver = StandardCharImageLoginSolver()

    override val isSliderCaptchaSupported: Boolean
        get() = true

    override suspend fun onSolvePicCaptcha(bot: Bot, data: ByteArray) =
        standardCharImageLoginSolver.onSolvePicCaptcha(bot, data)

    override suspend fun onSolveSliderCaptcha(bot: Bot, url: String): String? {
        val logger = bot.logger
        logger.info { "[SliderCaptcha] Captcha link: $url" }
        for (i in 0..3) {
            logger.info{ "[SliderCaptcha] Try to automatically recognize the verification code." }
            val jsonNode = client.post("https://api.kukuqaq.com/captcha") {
                setFormDataContent {
                    append("url", url)
                }
            }.body<JsonNode>()
            if (jsonNode.contains("ticket")) {
                val ticket = jsonNode["ticket"].asText()
                logger.info { "[SliderCaptcha] Ticket: $ticket" }
                return ticket
            }
        }
        logger.error { "[SliderCaptcha] Recognition failure" }
        return standardCharImageLoginSolver.onSolveSliderCaptcha(bot, url)
    }



}

mirai原生

替换掉验证码实现

suspend fun main(args: Array<String>) {
    // 让mirai强制走滑块验证码
    System.setProperty("mirai.slider.captcha.supported", "true");
    val newBot = BotFactory.newBot("qq号", "密码")
    val configuration = newBot.configuration
    // 把验证码实现更换为自己的
    configuration.loginSolver = KuKuLoginSolver()
    newBot.login()
}

simbot2

如果为simbot+SpringBoot,则实现MiraiBotConfigurationFactory接口,并重写getMiraiBotConfiguration方法

@Component
public class MiraiBot implements MiraiBotConfigurationFactory {
    @NotNull
    @Override
    public BotConfiguration getMiraiBotConfiguration(@NotNull BotVerifyInfo botInfo, @NotNull MiraiConfiguration simbotMiraiConfig) {
        BotConfiguration botConfiguration = simbotMiraiConfig.getBotConfiguration().invoke(botInfo.getCode());
        System.setProperty("mirai.slider.captcha.supported", "true");
        botConfiguration.setLoginSolver(new KuKuLoginSolver());
        botConfiguration.fileBasedDeviceInfo();
        return botConfiguration;
    }
}

simbot3

1、监听MiraiBotRegisteredEvent事件,替换掉验证码实现

@Service
class BotEvent {

    @Listener
    fun ss(e: MiraiBotRegisteredEvent) {
        e.bot.originalBot.configuration.loginSolver = KuKuLoginSolver()
    }

}
@Service
public class BotEvent {

    @Listener
    public void ss(MiraiBotRegisteredEvent e) {
        e.getBot().getOriginalBot().getConfiguration().setLoginSolver(new KuKuLoginSolver());
    }
    
}

2、启动之前设置环境变量

System.setProperty("mirai.slider.captcha.supported", "true")
最后修改:2022 年 12 月 12 日
如果觉得我的文章对你有用,请随意赞赏