猿人学 — 第1届第4题(解题思路附源码)
猿人学 — 第1届第4题
-
分析:由响应数据和页面的
html
可知style
属性中display
为none
的img
标签在页面上并不显示,为干扰项html
中img
标签的相对顺序不与页面上的数字相对顺序对应
-
问题1:如何排除干扰项;问题2:如何还原正确的顺序
-
解决问题1:返回的
info
中,所有img
标签并没有style
属性,并且class
属性中有一串奇怪的字符;并且请求返回的数据中有key,value,iv
貌似还没用到,因此进入js源码中查看
-
success:可以看到请求成功后,执行了一段代码。大概意思是,若一个标签的
class
属性中含有j_key
字符串内容,则为这个标签添加上display:none
,即不显示。对比返回结果和页面数据显示,发现确实如此,因此可扣下相关的代码
-
解决问题2:可以发现,若
left:0
,则相对初始位置没有移动;若left:11.5
,则代表其相对初始位置向左移动了一个单位;若left:-11.5
,则代表其相对初始位置上向右移动了一个单位;并且观察其它的,可发现11.5px
为一个基本单位。因此我们在后续的逻辑中,就可以提取img
标签style
属性中的left
值,从而定位它们的初始位置 -
源码如下:
import re import execjs import base64 import ddddocr import requests import multiprocessing# 读入并编译js代码用于生成特征信息 with open('v1.js', 'rt', encoding='utf-8') as f:JS_STRING = f.read() JS_CODE = execjs.compile(JS_STRING) # 实例化一个DddOcr对象用于识别图片 OCR = ddddocr.DdddOcr(show_ad=False)# 请求page页获取响应信息 def get_data(page):"""请求page页获取响应信息"""res = requests.get(url=f'https://match.yuanrenxue.cn/api/match/4?page={page}',headers={'Referer': 'https://match.yuanrenxue.cn/match/4',# 用你自己的Cookie'Cookie': 'Hm_lvt_c99546cf032aaa5a679230de9a95c7db=1728951512; HMACCOUNT=11F164A33FD6330D; qpfccr=true; no-alert3=true; tk=8258780053392544352; sessionid=9eqltqfxxrf7u6emsd3lajycdae9yg24; Hm_lvt_9bcbda9cbf86757998a2339a0437208e=1728951539; Hm_lpvt_9bcbda9cbf86757998a2339a0437208e=1728961624; Hm_lpvt_c99546cf032aaa5a679230de9a95c7db=1728961660'})if res.status_code != requests.codes.ok:print(f"{page}页数据获取失败")key = res.json()['key']value = res.json()['value']info = res.json()['info']return key, value, infodef display_no(key, value):"""根据请求中返回的key和value调用js代码生成特征信息若这个特征信息存在于img标签中,则该img标签的dispaly为none即不显示"""display_no_string = JS_CODE.call('display_no', key, value)return display_no_stringdef handle_info(info, display_no_string):"""根据info和不显示的img标签的特征信息,提取、筛选、排序和识别图片,返回info所在页的数字和:param info: 请求page页返回的响应中键info对应的值:param display_no_string: 如果在一个img标签中被包含,则说明这个img将不显示"""page_total_value = 0# 每页中有多少个数据即包含多少个td标签td_list = re.findall('<td>.*?</td>', info)for i in range(len(td_list)):# 提取一个td标签中的所有img标签img_list = re.findall('<img.*?>', td_list[i])# 根据特征信息删除不显示的img标签img_list = [x for x in img_list if display_no_string not in x]# 根据style属性中的left值对这几个img标签进行重新排序sort_img_list = [0] * len(img_list)for j in range(len(img_list)):img_string = img_list[j]# 提取img标签中style属性的left值,并计算出其初始位置的下标left = float(re.findall('left:(.*?)px', img_string)[0].strip())position = j + int(left // 11.5)# 只将img标签中的bas464编码信息存入最终的结果列表sort_img_list[position] = re.findall('base64,(.*?)"', img_string)[0]# 利用ddddocr识别图片single_value = ''for j in range(len(sort_img_list)):body = base64.b64decode(sort_img_list[j])code = str(OCR.classification(body))single_value += codepage_total_value += int(single_value)# print(single_value,end=' ')return page_total_valuedef worker(page):try:key, value, info = get_data(page)display_no_string = display_no(key, value)page_total_value = handle_info(info, display_no_string)return page_total_valueexcept Exception as e:return f'Error:{e}'# print(f"第{page}页计算结束")if __name__ == '__main__':# 多进程执行with multiprocessing.Pool(processes=5) as pool:results = pool.map(worker, range(1, 6))total_value = sum(results)print(f"求和:{total_value}")
-
运行结果:
-
结语:若上述分析和代码有错误、不合理或值得优化的地方,欢迎各位大佬批评指正,不吝赐教!