网址:第五题 js混淆 乱码增强 - 猿人学爬虫逆向练习平台
抓包分析,发现返回的一些字符串

通过分析可知道文中的数字是图片

看源码可以知道,当符合一些条件的时候,设置css的display属性为None,也就是说在td中有好几个,但是有一些不显示。

将其中一个td的内容复制到在线代码格式化,可以观察到共有8个img标签,但一个数字共有6个,说明其中有两个是没用的,结合$(j_key).css('display', 'none');,可以知道类是j_key的标签是不显示的。
<html>
<head></head>
<body>
<img class="img_number 1395e23f0906f7fc3e7247de13793bf4" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAeCAYAAADZ7LXbAAAB0klEQVR4nNWWu0tCURzHv75upfhAuVHh5mRDFFEIgS7lWIu0FAVuDUFN7v0TIoFTUzgU1WI01FASgU53yCIIA8Esn/kora289x6999xrQb/tfPn9zoff4/w4mnYp+4lfNn3noZnlUHwq9eFaFsZpF0wkSCMVRiEa7wNkC5r9jW+Itg83Str/hWgWfbB3nlVNVy6Oh+1NfDQ7NCYIaySEYdOPpCKTErK7O3wAAO1qkAdQBamloqikcnzRHIJtgRX5KoO0ODxHwuDXmYVhPQCHTuyuCFI+DaOeF4iOICxzFqI/PaSewMue8MGyMKytwE7IQhHk9TiKpqDZcARhmR3oGkMHqSZQPDgXyfrlQNcsqCGFsyjehVmYQ7B4yb2gh9STKB2Ks9Au+YkTpQhSvYqhURaqARi9TslYmZAMCicxsTzph9UmHS0Pko6j9igUWTDzHhhlhMuC5C+PINqiTADGie5jSwdpcXi74MT6jAfWQVkMaUg7nSA0HDBMjYORx5CGFG4IpYIfjLv326CAZFC7JpRqxIch8UZXCMklUc8SdLcLVvmM3pDmHYc2Qde7nFT7qKdv5T5BUFnoxihq1RuSQ+OW0A94YBilYqj8rci0P/ncfQFZgoA8RmcsKwAAAB10RVh0dgB1MjQ0MC1wMC0xLWJiNWE3NzY1NTRkM2U0ZDjZiTTCAAAAAElFTkSuQmCC" style="left:0.0px" />
<img class="img_number 1395e23f0906f7fc3e7247de13793bf4" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAfCAYAAAASsGZ+AAADS0lEQVR4nLWWX2hTVxzHPzeNuenyx9HulsRmEVa2lTyMBqF0FCY+2O3B+NSHCYLQh8H2oA7CChujENbBJDJhk0IZexj0YdIxxL0sL0VhLOpDxD9BlE5xNxq8aeeSxTRJk/hWe885N7EMf0+Xe37n9+H3O9/f7xytXS52eMnmetkAAHcvh0YxR2klQ/3PPK3qKp2KjhaKoA3H8Y5P4Z+MsdvTPYbmVK5NK8vD019Q/8vsHsEzgvvgPMbROP6+HUBq1xconDpDp9E9vs1G0xhzCV5VgOQzsTIUdwoAuJ2ktJijplgSIHWsn1NsKgDaeJrBs1eJ/nSV8HyaXYOyT2flG0p3e0FaeWpZS/YaWyScTDBgBNG9QfxvJojOpRVlyFG/nO8BWTdpSlkY6If24xM3hqYITCqyuWPyX1eI0uK4w6r/Ov1vT/XeLkECBrI4ynRUpwk0S7K8tbci+LtCvHF87xmCS5aNKyZtMVorT3VFrP9++g/EJLBQLp3B6VncQge3zyX5+w+LzS2AyaNvU2xUhCwOnyQ8LDF22IyBCTQfdNazYFsz0D74juGZOP0yo8tYKWQwv07RtBSStoET6J/Msmef4TgIndXlCdIXlesrWbNMp2BSazm7KDKps3YuyfpypjdguxkzBL6cJRTqCalT+uEY/2RyYgS0sY/xvz9CH9BazVD9bYn2huDmncZ/ep6wIFAbpHF9gQdfncGeWhzPp4u8/m7QVtt2JYf52YfU1wTQ2CJ7PrdPiG37yqydFwHA5EmGBACAKxAncmIWTfS/tsSTguC79bWRp35D3AG7xtWyBHCNTuCRbsWLNG7ZFfkcUrFQCcTl0x0QAAbuvfLf1mMniIO1n5SdF1smTcX9gTfoABmIKJupeTFL1YFRu5JBdYG6h5wgfTFekYYjcCPF4+VVngq13CxcoHj2RwViGv0dO8Qm4XbxAveOJ+WJCxBI4JmMoQGd+8s0bq+qvNAO/8obR2O2c5A6/t9LKazvl2Qpv4iNphmaS7BbuJSUA/LpzSUenUrJHe1oBtqBNKGPJpRvL8cpTMvC+mWB8u8Z2hWnSRzBtW+GwJEEr0Xlhu0N2WaNapnawzyNLTXruKMj+AaCeBxejTuG/F97BlGUQSwGRtVmAAAAHXRFWHR2AHUyNDQwLXAwLTItN2E0NDQ5NGJlM2JhNWZiYyQrnrMAAAAASUVORK5CYII=" style="left:0.0px" />
<img class="img_number 1395e23f0906f7fc3e7247de13793bf4" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAfCAYAAAASsGZ+AAACe0lEQVR4nL2WPWhTURTHf2nS92I/Ym18YGkIQtEhgyiIpBTMUro5CA6CQzBDJUi1Q7C0SMBFSOkQ6CC4dLG4BEWLIHWKInQotFQILq0ffQ2F2Jo2jfalfS8uDkneTfL6lTOe/733d++555x7bcb2epETtqaTBgA4aqq6xtZKkp1PCxQWU+i7KsWsCu1+bK0emnv9tPQGOHPeVXMhmyhcRk7l16s4Wx9moGBhq90h2iIjdHVbhWzM8u3hEPtWFi81yY/86DneS7JJMt+JoWEcFABQmEMbj7GeNUu17wRA6sF2MYDkUf47MuifZ9jPZQSgaXbe3MII+sp2Xx3iHEC+N4zb30OrvUILhslMDZKdXTBNK36cIxv00VniE6aw/dokytQk3j4BAMDuQrkbxdku0HIptI1yl/kknTfwRiwUkN1Dcw/sLlYKGkWj3GNey261QmWaWi0NPErFL6MtifweHBVhPDSksJREywmECz5OOY8Dkl9g/VkcUWd19AeozIeDQ3SVdGzIlEEAuEc4fd1lch8IYuRSrI7eJv9VUIgEaBkN0SlIecuQPysJfty/ye53EeAK8tgEXV7x3PptRd9m812MjRcJsS75kSOTeC67qu64znuikn4aJP9FFetKiLax6i2+PiSfYvXJYJXwKNh6o5x9MECHqO1Ygugq6VgVgORHCk/Q3adYiHUNyObLiDiD3HdoexytG576kLUEv9+aWzjuYTrGwyiizlvHKhJCI/M6jmEa5kMOhw4FgMqT6Cn+zokv2pif5ue8tUWl/hDnSmqmHLK2TEH4vifZe5+0RgC4GoISSHm4shlh0zuqNeQH2RCI8Ad53NaQk/wDUOnJokC7XfIAAAAddEVYdHYAdTI0NDAtcDAtMy00Mjg4MTg1NmFmOTYwYTZkP7Qh6AAAAABJRU5ErkJggg==" style="left:0.0px" />
<img class="img_number 079f299428bfb9e801eba3433743ff3e" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAeCAYAAADZ7LXbAAABz0lEQVR4nO2WMUvDUBSFT2qttaJCazBg0cmlTkE3R6F0cauz2MVJcCh0KCh2E9wEiw4VBH+AFBwCDoq4VlBLQXAItQYT0bamkKiJg9amSdW+EDt5tnvIzZeXk5d3Ka0i6Phjue21KShf5qAqza5rhEWA6XEIInKQUnFoJtsVO0UgQlsud5ETFEgHGQvgJxFDND6LMpcn6iGEiBC2k0SrIIbIJ2nI14QEIsjTMcSdfXJC+5AKhK0kXtR6TQMehyFVLoXqudgwRpfhm3YQoglZSHtZg8PCuxhFT7dTkLci7jbieFUbFhVZwfB4+4BfIAqk3ThqvMEKJOCfD5HE8TNEPlnHI5czOGH0rcbg7yIkfAfRhCzumz5XGu5YAgxDDmgNkXMorplyCG+CiQTt/OhaQN6KKK0vQXkweIEE/Assem0CTJCPoOWCYT94Zm3nYNTXefJ8lDIFDSBI4/UwA97cBUC7snr62T740sBnNQDfXBRD/QaI/lKxdt1koNy0/8R6IQ2lUK/CcM9GgX5bhxa5OgKh6tOKKuRRvm3xyr6RejiP2oXpZjObGJxqZOKZCGHQa8jEw4RAE2w2KQcrZIwFPenIIEGufwiRqE7Mwh1ZyTufuJUXq4+TkQAAAB10RVh0dgB1MjQ0MC1wMC00LTA2ZTc2Yzg1NDNmOWM5ODn3z6HDAAAAAElFTkSuQmCC" style="left:8.5px" />
<img class="img_number 1395e23f0906f7fc3e7247de13793bf4" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAfCAYAAAASsGZ+AAACe0lEQVR4nL2WPWhTURTHf2nS92I/Ym18YGkIQtEhgyiIpBTMUro5CA6CQzBDJUi1Q7C0SMBFSOkQ6CC4dLG4BEWLIHWKInQotFQILq0ffQ2F2Jo2jfalfS8uDkneTfL6lTOe/733d++555x7bcb2epETtqaTBgA4aqq6xtZKkp1PCxQWU+i7KsWsCu1+bK0emnv9tPQGOHPeVXMhmyhcRk7l16s4Wx9moGBhq90h2iIjdHVbhWzM8u3hEPtWFi81yY/86DneS7JJMt+JoWEcFABQmEMbj7GeNUu17wRA6sF2MYDkUf47MuifZ9jPZQSgaXbe3MII+sp2Xx3iHEC+N4zb30OrvUILhslMDZKdXTBNK36cIxv00VniE6aw/dokytQk3j4BAMDuQrkbxdku0HIptI1yl/kknTfwRiwUkN1Dcw/sLlYKGkWj3GNey261QmWaWi0NPErFL6MtifweHBVhPDSksJREywmECz5OOY8Dkl9g/VkcUWd19AeozIeDQ3SVdGzIlEEAuEc4fd1lch8IYuRSrI7eJv9VUIgEaBkN0SlIecuQPysJfty/ye53EeAK8tgEXV7x3PptRd9m812MjRcJsS75kSOTeC67qu64znuikn4aJP9FFetKiLax6i2+PiSfYvXJYJXwKNh6o5x9MECHqO1Ygugq6VgVgORHCk/Q3adYiHUNyObLiDiD3HdoexytG576kLUEv9+aWzjuYTrGwyiizlvHKhJCI/M6jmEa5kMOhw4FgMqT6Cn+zokv2pif5ue8tUWl/hDnSmqmHLK2TEH4vifZe5+0RgC4GoISSHm4shlh0zuqNeQH2RCI8Ad53NaQk/wDUOnJokC7XfIAAAAddEVYdHYAdTI0NDAtcDAtNS1lNmVjZGQyNDljZTI5NmM5JbuZkAAAAABJRU5ErkJggg==" style="left:8.5px" />
<img class="img_number 079f299428bfb9e801eba3433743ff3e" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAfCAYAAAASsGZ+AAAA0ElEQVR4nGP89+nFfwYaAyZaW8DAwMDAQo6mP093MTxpa2L4/fo1VMSNgXvqZAYpUWpY8vc1w+slTQwftu4iSRtRlvz79Zrh7YYJDB83rWH4/4sk8wlY8vcnw8eruxg+bt/M8PPsQdJNJsaSz7tLGF7NIy1YcAG6pC7SLOEIYeAKiSbZEuJSF68vA1tMEoOInRYD99XpDLepZQmzjD0DR1IIA7eBBYOABDtF4YrTEi6dEAYuHQpMRgKDMOJHLRm1ZNSSUUtGLRm1BDtgHDYNbgBRgjXoqop7sgAAAB10RVh0dgB1MjQ0MC1wMC02LTM4MzIzZDFjMmRiZWQzZDl4ojUPAAAAAElFTkSuQmCC" style="left:17.0px" />
<img class="img_number 1395e23f0906f7fc3e7247de13793bf4" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAfCAYAAAASsGZ+AAACrElEQVR4nLWWT0iTcRjHP0t9p1Onpm9YLomEkP4I4mXDaJcSL7vtEBgIu3koJkkegkEdAiNKT0EHwcNOdQi8SH8OO0gjiMmIDsYqbOrwxWHvttwft3Voie79vdtc83t8nuf9fd7f7/k93/c15NRInmPWieMGANTrJfaSYdQPfuLBAOlQGBIh8jEF2q0YGi002KyYbHY6zpn1FynIoD2uMJuP7hNf8Vf2mj0uWqamOd2jXyI4LoVMpQCA9XnikzdZC6aOAqlGAVKPZ4jsiLMljlOG3hGM1+00yca/oaTCru8VKdFO017i71zgtFQGMVz20D4xhiwLksMOfn+aZWPmOcV3Px/8QtxpoaUoLjiuQc56dAAFmYacNHULEtmUBqwDqUQWjAOVV1cJUdnbEoRPyRhrBclFfCRWiqMykm0QSVBfblg1SnxdRHk6Ra440T9N+5BoH6Ug2z5+PJhn70AoH/VDWlAru+mYdtBWJ15KH5JTyUb8wtuyr1YH0q0J5Gt9mHQA8D8TL9lpGLZitJQ3yCP3ZF9pH5klH5kliMkumu+6OXNe3BOBCxcUC7DxMnCgJyq5VT+ZbwExVLJivPeC3gEtSB+ip6xK9O0s0Xmvtl+dbjqeTdDVeDh89J7UmTk56kF2ObS57VniH1VNuOrGt90YEw5eZjVUOwh1YKiwtHpIMqWd+sogIZRl5dCU6+nXey8ZQby+V/vRKoKo7M5d5fvkQ34uh4gLLCSXVlAWbrO18EaAsCNd0n6IxMO47iU552UToNWKobkQT4bJ74SFjwAYRt3Igr+W8hMf85OPla2C/ifI4xdrY/VayRhsHrrujOi6sGbiY8FFoq+9pD/r2Mc/SX2cuDKGedxJZ7ex5DXVt5Vsit1omMSaUmQfZqQLFppMZqQS9l4ZpIb6A1fu5S14k/1FAAAAHXRFWHR2AHUyNDQwLXAwLTctNDc4MDZjOTlhODAwMDU2ORLQmh8AAAAASUVORK5CYII=" style="left:-8.5px" />
<img class="img_number 1395e23f0906f7fc3e7247de13793bf4" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAeCAYAAADZ7LXbAAABz0lEQVR4nO2WMUvDUBSFT2qttaJCazBg0cmlTkE3R6F0cauz2MVJcCh0KCh2E9wEiw4VBH+AFBwCDoq4VlBLQXAItQYT0bamkKiJg9amSdW+EDt5tnvIzZeXk5d3Ka0i6Phjue21KShf5qAqza5rhEWA6XEIInKQUnFoJtsVO0UgQlsud5ETFEgHGQvgJxFDND6LMpcn6iGEiBC2k0SrIIbIJ2nI14QEIsjTMcSdfXJC+5AKhK0kXtR6TQMehyFVLoXqudgwRpfhm3YQoglZSHtZg8PCuxhFT7dTkLci7jbieFUbFhVZwfB4+4BfIAqk3ThqvMEKJOCfD5HE8TNEPlnHI5czOGH0rcbg7yIkfAfRhCzumz5XGu5YAgxDDmgNkXMorplyCG+CiQTt/OhaQN6KKK0vQXkweIEE/Assem0CTJCPoOWCYT94Zm3nYNTXefJ8lDIFDSBI4/UwA97cBUC7snr62T740sBnNQDfXBRD/QaI/lKxdt1koNy0/8R6IQ2lUK/CcM9GgX5bhxa5OgKh6tOKKuRRvm3xyr6RejiP2oXpZjObGJxqZOKZCGHQa8jEw4RAE2w2KQcrZIwFPenIIEGufwiRqE7Mwh1ZyTufuJUXq4+TkQAAAB10RVh0dgB1MjQ0MC1wMC04LTRlMzA0ZDlmMGNmNjE4MDMOQb9zAAAAAElFTkSuQmCC" style="left:0.0px" />
</body>
</html>
用豆包生成一下j_key的生成方法,并且测试
import base64
import hashlib
def hex_md5(s: str) -> str:
"""等价JS hex_md5"""
return hashlib.md5(s.encode("utf-8")).hexdigest()
def btoa(s: str) -> str:
"""模拟浏览器btoa"""
return base64.b64encode(s.encode("utf-8")).decode("ascii")
def calc_j_key(key: str, value: str) -> str:
concat = key + value
b64_str = btoa(concat)
b64_no_pad = b64_str.replace("=", "")
md5_hex = hex_md5(b64_no_pad)
j_key = "." + md5_hex
return j_key
# --------测试示例,对应你抓包返回的数据---------
res_key = "2nptl30IxW"
res_value = "BI2rwzWaeN"
j_key_result = calc_j_key(res_key, res_value)
print("j_key =", j_key_result)

![]()
<td class="pgx‑num">
<img A … style="left:-17px; display:none;"> <!--A组 干扰 -->
<img B … style="left:-8.5px;"> ✅B组可见
<img B … style="left:8.5px;"> ✅B组可见
<img A … style="left:17px; display:none;"> <!--A组干扰 -->
<img B … style="left:-17.0px;"> ✅B组可见
<img A … style="left:‑8.5px; display:none;"> <!--A组干扰 -->
<img B … style="left:8.5px;"> ✅B组可见
<img A … style="left:25.5px; display:none;"> <!--A组干扰 -->
<img B … style="left:-8.5px;"> ✅B组可见
<img A … style="left:-17px; display:none;"> <!--A组干扰 -->
<img B … style="left:0.0px;"> ✅B组可见
<img A … style="left:17px; display:none;"> <!--A组干扰 -->
</td>
可以看到数字的值不仅跟left有关,还跟位置有关
最后结果
import requests
from bs4 import BeautifulSoup
import base64
import hashlib
from io import BytesIO
from PIL import Image
import ddddocr
import re
cookies = {
'Hm_lvt_f80b2b389f44bbfb3bfe1704817d44e0': '1785087424',
'HMACCOUNT': '8BC6A262685DEA75',
'sessionid': 'ho9vnm6xj4tu49sls5l2xhghod0ekog8',
'm': '1110c14b161386dfee2cba4c0a35f39e|1786780279109',
'Hm_lpvt_f80b2b389f44bbfb3bfe1704817d44e0': '1786800456',
}
headers = {
'accept': 'application/json, text/javascript, */*; q=0.01',
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'cache-control': 'no-cache',
'dnt': '1',
'pragma': 'no-cache',
'priority': 'u=1, i',
'referer': 'https://match.yuanrenxue.cn/match/4',
'sec-ch-ua': '"Not=A?Brand";v="99", "Microsoft Edge";v="151", "Chromium";v="151"',
'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; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36 Edg/151.0.0.0',
'x-requested-with': 'XMLHttpRequest',
# 'cookie': 'Hm_lvt_f80b2b389f44bbfb3bfe1704817d44e0=1785087424; HMACCOUNT=8BC6A262685DEA75; sessionid=ho9vnm6xj4tu49sls5l2xhghod0ekog8; m=1110c14b161386dfee2cba4c0a35f39e|1786780279109; Hm_lpvt_f80b2b389f44bbfb3bfe1704817d44e0=1786800456',
}
def hex_md5(s: str) -> str:
"""等价JS hex_md5"""
return hashlib.md5(s.encode("utf-8")).hexdigest()
def btoa(s: str) -> str:
"""模拟浏览器btoa"""
return base64.b64encode(s.encode("utf-8")).decode("ascii")
def calc_j_key(key: str, value: str) -> str:
concat = key + value
b64_str = btoa(concat)
b64_no_pad = b64_str.replace("=", "")
md5_hex = hex_md5(b64_no_pad)
j_key = md5_hex
return j_key
def parse_left_px(style_str: str):
"""
解析img标签style属性,取出left的像素数字
示例:style="left:8.5px;" → return 8.5
style="left:-17.0px;" → return -17.0
"""
# 正则匹配 left:数字px,支持正负小数
pat = re.compile(r'left\s*:\s*(-?\d+\.?\d*)px')
match = pat.search(style_str)
if not match:
return None
val = float(match.group(1))
return val
# 初始化ocr对象,只识别数字
ocr = ddddocr.DdddOcr(show_ad=False)
def base64_to_num(b64_src):
b64_body = b64_src.replace("data:image/png;base64,", "")
raw = base64.b64decode(b64_body)
img = Image.open(BytesIO(raw))
res = ocr.classification(img)
return res
def order_sum(arr):
sum = 0
tmp = []
for i, item in enumerate(arr):
new_pos = i + int(item[1])
tmp.append((new_pos, item))
# 按新位置排序
tmp.sort(key=lambda x: x[0])
new = [item for _, item in tmp]
for item in new:
sum = sum * 10 + item[0]
return sum
def get_num(response):
all_page_num=[] #一页所有数字
info_str=response.json()['info']
j_key = calc_j_key(response.json()['key'], response.json()['value'])
soup = BeautifulSoup(info_str, "html.parser")
all_td = soup.find_all("td")
for td in all_td:
all_img=td.find_all("img")
all_td_num=[] #一个单元格的数字
for img_tag in all_img:
# 获取class原始字符串
class_str = img_tag.get("class")[1]
# print("class列表:", class_str)
# # 返回列表:['img_number', '1395e23f0906f7fc3e7247de13793bf4']
# # 转字符串
# class_raw = " ".join(img_tag.get("class"))
# # print("class完整字符串:", class_raw)
if j_key == class_str:
# print("找到目标图片")
continue
else:
src=img_tag.get("src")
num=base64_to_num(src)
# 获取style属性
style = img_tag.get("style")
left_px = parse_left_px(style)
all_td_num.append([int(num),left_px])
tem=[]
for i, item in enumerate(all_td_num):
new_pos = i + int(item[1]//8.5)
tem.append([item[0],new_pos])
all_td_num=tem
# 按新位置排序
all_td_num.sort(key=lambda x: x[1])
all_td_num = [num for num, _ in all_td_num]
# 数组每一项转字符串,拼接,再转为数字
num_str = "".join(str(x) for x in all_td_num)
real_number = int(num_str)
all_page_num.append(real_number)
print(all_page_num)
return all_page_num
sums=0
for page in range(1,6):
params = {
'page': page,
'pageSize': '10',
'kw': '',
}
if page==5:
headers['user-agent']='yuanrenxue'
response = requests.get('https://match.yuanrenxue.cn/api/question/4', params=params, cookies=cookies, headers=headers)
# print(page,response.status_code,response.json()['info'][1:10])
sums+=sum(get_num(response))
print(sums)


840

被折叠的 条评论
为什么被折叠?



