题目看上去很简单,拿到5页的所有数字算总和就行,来分析一下

看到数字不是文本的形式,而是经过 base64编码的图片形式,有些图片的 style属性中有display: none,表示该图片不予展示,观察 ajax 接口返回的源数据,看到是直接返回 html源码,还有keyvalue 等字符串,暂时不明确这些的用途

对比渲染前后的html数据,有如下的不同点:

  • img_number 后疑似 md5编码(长度为32)的字符串不见了
  • style 属性多了 display

在这里猜测是根据不同的img_number值来判断该图片节点是否给予展示,因为返回的图片节点数量明显大于网页所展示的数量

直接全局搜 img_number,发现只有一个结果,加断点调试:

到这里逻辑就很清晰了,上面的操作就是:

  1. info即 原始html数据赋值给 $('.number')节点,也就是 <tr class="number">

  2. 根据 keyvalue 先进行 base64编码 再进行 MD5加密,计算出 j_key,只要是class值等于j_key的节点,都设置display属性

    hex_md5 即哈希md5算法

  3. 最后就是 removeClassaddClass两个操作,修改 img_number的值

最后一步,要怎么识别出图片中的数字呢?第一个想到的是ocr,但这里不必小题大做,这里只有十个数字,即代表只有十张不同的图片,而图片都是经过base64编码的,相同图片编码出来的结果是一致的,所以只需要设计一张映射表就行

代码整理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import requests
import hashlib

from base64 import b64encode
from parsel import Selector


yuanrenxue_headers = {
"User-Agent": "yuanrenxue.project",
"sessionid": "6nfyiexiutauob3e0s7jmrxtz8qfy68b",
}


def img_ocr(src):
"""
根据src后缀识别图像
"""
if src.endswith("eCAAAAAElFTkSuQmCC"):
return "0"
elif src.endswith("HMAAAAAElFTkSuQmCC"):
return "1"
elif src.endswith("Dor0g3AH8BJlTqZkAngxQAAAAASUVORK5CYII="):
return "2"
elif src.endswith("HzjKAAAAAElFTkSuQmCC"):
return "3"
elif src.endswith("QAAAABJRU5ErkJggg=="):
return "4"
elif src.endswith("cHAAAAAASUVORK5CYII="):
return "5"
elif src.endswith("0YzEyuMQpQAAAAASUVORK5CYII="):
return "6"
elif src.endswith("HrJiVs0AAAAAElFTkSuQmCC"):
return "7"
elif src.endswith("6cpuRANAAAAAElFTkSuQmCC"):
return "8"
elif src.endswith("dVIiAf4ApbEnkB6qHqsAAAAASUVORK5CYII="):
return "9"

def get_real_nums(html, none_key):
numbers = []
table = Selector(html)
fake_css = "img_number " + none_key
for num, td in enumerate(table.xpath(".//td")):
num_lst = []
position = 0
for img in td.xpath(".//img"):
img_src = img.xpath("./@src").get()
img_css = img.xpath("./@class").get()

if img_css != fake_css:
single_num = img_ocr(img_src)
offset = img.xpath("./@style").re_first("left:(.+)px")
num_lst.append(
{
"score": float(offset) / 11 + position,
"single_num": single_num,
}
)
position += 1

num_lst = sorted(num_lst, key=lambda x: x["score"])
number = "".join([d["single_num"] for d in num_lst])
numbers.append(number)

return numbers


def main():
for page in range(1, 6):
num_url = f"http://match.yuanrenxue.com/api/match/4?page={page}"
data = requests.get(num_url, headers=yuanrenxue_headers).json()
info, key, value = data["info"], data["key"], data["value"]
b64 = b64encode((key + value ).encode()).decode().replace("=", "")
none_key = hashlib.md5(b64.encode()).hexdigest()
print(get_real_nums(info, none_key))


if __name__ == "__main__":
main()

运行结果