自学内容网 自学内容网

猿人学 — 第1届第4题(解题思路附源码)

猿人学 — 第1届第4题

  • 分析:由响应数据和页面的html可知

    • style属性中displaynoneimg标签在页面上并不显示,为干扰项
    • htmlimg标签的相对顺序不与页面上的数字相对顺序对应
  • 问题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, info
    
    
    def display_no(key, value):
        """
        根据请求中返回的key和value调用js代码生成特征信息
        若这个特征信息存在于img标签中,则该img标签的dispaly为none即不显示
        """
        display_no_string = JS_CODE.call('display_no', key, value)
        return display_no_string
    
    
    def 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 += code
            page_total_value += int(single_value)
            # print(single_value,end=' ')
        return page_total_value
    
    
      def 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_value
          except 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}")
    
    
  • 运行结果

    在这里插入图片描述

  • 结语:若上述分析和代码有错误、不合理或值得优化的地方,欢迎各位大佬批评指正,不吝赐教!


原文地址:https://blog.csdn.net/Learner_HJ/article/details/142965055

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!