题目链接:https://match.yuanrenxue.cn/match/7
常规操作F12打开开发者工具,点击翻页按钮,翻页,查看请求⬇️


观察响应,返回两个键,第一个data列表有10个字符串,每个字符串通过&#分割后有6个,6个一组拼接起来就是上面一个框里面的数字;第二个woff字体是base64(最后==基本是标志性特征)加密过的。
大概思路:
1.请求获取响应
2.解析响应用过woff字体,base64解码斜纹.woff字体文件中
3.使用字体工具库读取字体文件
4.将字体文件转为unicode字符串字典
5.循环读取这个字典
6.使用ImageDraw绘制出这个unicode字符图片
7.使用带带弟弟ocr识别出这个图片对应的文本
8.存储一个unicode字符串与文本的映射
9.读取响应中的data,根据映射获取数字文本,拼接一起就是目标中的一组数字了
代码如下:
import base64 import json import time import cv2 import ddddocr import fontTools import httpx import requests from fontTools.pens.basePen import BasePen from fontTools.pens.freetypePen import FreeTypePen from fontTools.ttLib import TTFont from PIL import Image, ImageDraw, ImageFont def ocr_font(r, page): data = r.json()['data'] woff = r.json()['woff'] woff_data = base64.b64decode(woff) with open('a.woff', 'wb') as f: f.write(woff_data) # 加载字体文件 pil_font = ImageFont.truetype('a.woff', 64) # 1.解析字体文件 font = TTFont('a.woff') cmap = font.getBestCmap() # 获取字符映射表 # 2.识别真实字符 # ocr识别 通过字形轮廓数据,识别每个字形对应的真实字符 # 初始化ocr工具 ocr = ddddocr.DdddOcr() # 创建字形到字符的映射 glyph_to_char = {} print(f'unicode码点 -> 字形名称:') for unicode_code, glyph_name in cmap.items(): if glyph_name == '.notdef': continue try: # 创建空白图片 img = Image.new('L', (80, 80), 255) draw = ImageDraw.Draw(img) # 绘制字符 draw.text((8, 8), chr(unicode_code), font=pil_font, fill=0) # 使用ocr识别字符 text = ocr.classification(img) # 建立映射 if text.strip(): # 转为16进制字符串 hex_code = f'0x{unicode_code:X}'.lower() glyph_to_char[hex_code] = text.strip().replace('o', '0') print(f'unicode:{hex_code} -> {text}') # unicode:0xA568 -> 5 data:'똲ꕨ뤡ꝅ랆뙵' except Exception as e: print(f'处理0x{unicode_code:X}时出错:{e}') num = [] for d in data: ds = d.split('&#') str_n = [] for x in ds: if x: s = glyph_to_char.get(('0' + x).lower()) str_n.append(s) num.append(int(''.join(str_n))) print(f'{str(page)}-------{num}') return num def get_question_7_result(): """动态字体""" url = "https://match.yuanrenxue.cn/api/question/7" headers = { "accept": "application/json, text/javascript, */*; q=0.01", # "accept-encoding": "gzip, deflate, br", "accept-language": "zh-CN,zh;q=0.9", "cookie": "Hm_lvt_f80b2b389f44bbfb3bfe1704817d44e0=1774858578; HMACCOUNT=1465BBAADDC804BC; sessionid=da5quxdc92n61utuwc552c5xe7fuq7ze; m=7450063a8a8538e9b1cc5896efcd7e2c; RM4hZBv0dDon443M=fqIMirz60z2tu8z7H6kPM4gLnRyRdcb4j2+e5E6cInWpPZqMCO/lVl2eYEUKYGV7AnqPagbG5P0VIk7imUdEyXI20tdeVmlpXgjvdDNJ6N6/0AYRUiOqqNp7J5kOeJwibXV7PKBfZ5o2NY0UF/wZCCjTzxEL8bvKK3Drg7adfISV1bBnyUKqIV82UwVH9CjQ3Twe0AxSjv5dAlzjWL9ZiHi1+9aZrUQA7Iqb+40GeaQ=; Hm_lpvt_f80b2b389f44bbfb3bfe1704817d44e0=1775533049", "referer": "https://match.yuanrenxue.cn/match/7", "sec-ch-ua": "\"Chromium\";v=\"94\", \"Google Chrome\";v=\"94\", \";Not A Brand\";v=\"99\"", "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "\"Windows\"", "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "same-origin", "user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36", "x-requested-with": "XMLHttpRequest" } sum_data = 0 s = requests.Session() s.headers.clear() s.headers.update(headers) for page in range(1, 6): timestamp = int(time.time()*1000) if page == 5: headers['user-agent'] = 'yuanrenxue' s.headers.update(headers) params = { "page": page, "pageSize": "10", "kw": "", } try: r = s.get(url=url, params=params, verify=False) if r.status_code == 200: data = ocr_font(r, page) sum_data += sum(data) print(f"翻第{str(page)}页,累计求和:{sum_data}") time.sleep(5) else: print(f'error:{r.status_code}-----{r.text}') except Exception as e: raise ValueError(e) if __name__ == '__main__': get_question_7_result()
实践出真知~
浙公网安备 33010602011771号