Administrator
Published on 2026-05-07 / 0 Visits
0

知网滑块验证 解密 文献爬虫 数据抓取(转)

抓取知网的文献资料,但是在打开文章时,会重定向到一个验证网址,并弹出一个滑块,让你进行验证。(https://www.0en.cn/archives/343.html)

打开控制台,抓取两个接口

获取滑块信息

https://kns.cnki.net/verify-api/get

这个接口会返回滑块图片信息(jigsawImageBase64、originalImageBase64),以及token、secretKey

base64 就是两张图片,一张是大图,一张是小图。

token 需要提交给验证接口

secretKey 参与坐标加密

验证滑块信息

https://kns.cnki.net/verify-api/web/check

这个接口需要提交一些参数,最重要的是 pointJson

这个是由坐标信息:{"x":0,"y":5} 和 secretKey 进行加密之后的结果

下面是一些重要的部分


识别小图在大图中的位置

可以使用 opencv-python 包, 附带函数:

''' 识别滑块位置 '''
def find_template_position(self,big_img_base64, small_img_base64):
    # 将 Base64 字符串解码为图像数据
    def base64_to_image(base64_str):
        # 去掉可能的头部信息(如 "data:image/png;base64,")
        if "," in base64_str:
            base64_str = base64_str.split(",")[1]
        # 解码为字节数据
        img_bytes = base64.b64decode(base64_str)
        # 转换为 numpy 数组
        img_array = np.frombuffer(img_bytes, dtype=np.uint8)
        # 用 OpenCV 解码图像
        img = cv2.imdecode(img_array, cv2.IMREAD_GRAYSCALE)
        return img

    # 解码 Base64 并转为灰度图
    big_img = base64_to_image(big_img_base64)
    small_img = base64_to_image(small_img_base64)

    # Canny边缘检测
    edges_big = cv2.Canny(big_img, 50, 150)
    edges_small = cv2.Canny(small_img, 50, 150)

    # 轮廓匹配
    res = cv2.matchTemplate(edges_big, edges_small, cv2.TM_CCOEFF_NORMED)
    _, _, _, max_loc = cv2.minMaxLoc(res)
    return max_loc

生成客户端ID

在获取滑块信息时,要提交一个 clientUid 参数,但是好像使用固定的也没关系


''' 生成客户端ID '''
def generate_clientUid(self):
    hex_digits = '0123456789abcdef'
    uuid_chars = []

    # 生成 32 个随机十六进制字符(无分隔符)
    for _ in range(32):
        uuid_chars.append(random.choice(hex_digits))

    # 固定版本号和变体标识位(符合 UUID v4 规范)
    uuid_chars[12] = '4'  # UUID 版本位
    uuid_chars[16] = hex_digits[(int(uuid_chars[16], 16) & 0x3 | 0x8)]  # 变体位

    return ''.join(uuid_chars)

pointJson 加密方式

point = {"x": x + 3, "y": 5} # x轴+3 y轴固定为5
# 转为json格式并进行加密
json_str = json.dumps(point, separators=(',', ':'))
pointJson = self.encrypt_point_json(json_str, verify_data['secretKey'])
print(f"识别滑块坐标:{point}  坐标加密:{pointJson}")

pointJson 加密函数

    ''' 滑块位置加密 '''
def encrypt_point_json(self, plain_text: str, secret_key: str = "XwKsGlMcdPMEhR1B") -> str:
    key = secret_key.encode("utf-8")  # 16字节key
    data = plain_text.encode("utf-8")

    cipher = AES.new(key, AES.MODE_ECB)
    padded_data = pad(data, AES.block_size)  # PKCS7 padding
    encrypted = cipher.encrypt(padded_data)

    return base64.b64encode(encrypted).decode("utf-8")

验证成功

在滑块验证成功后,需要携带 captchaId访问文章,就可以免验证了。

returnUrl = check_reslut_data.get("returnUrl")
returnUrl = f"{returnUrl}&captchaId={check_reslut_data['captchaId']}"

行为异常

如果出现行为异常,也需要进行滑块验证,但是这个滑块是单机的,也就是说可以忽略。
抓取页面的v-value ,访问下面这个地址,就会返回一个可以访问的文章地址。

v_value = soup.find('input', {'id': 'v-value'})['value']
# 这个滑块不需要验证,直接抓
newLink_api = f"https://kns.cnki.net/kcms2/newLink?v={v_value}"

本文仅学习研究记录。