zoukankan      html  css  js  c++  java
  • 爬虫之字体解密

    一、背景

    待破解网站

    问题:xpath 提取章节发现字体加密

    待破解的 HTML

    <dd class="col-sm-3">
        <a href="/books/34/34652/18381474.html">
            <i></i><i></i>章 醒
        </a>
    </dd>
    

    二、破解

    破解方案

    • 正则提取章节部分,获取加密部分内容(xpath 提取后是加密后的而不是原始数据,所以这里采用正则)
    • 下载字体文件,使用 百度字体编辑器 解析字体文件,获取对应关系
    • 将字体文件转换为 xml,解析 xml 获取字体对应关系

    正则提取

    chapter_list = re.findall("<dd class=\"col-sm-3\"><a href=.*?>(.*?)</a>", html)
    

    提取后的结果:

    # &#xe848; 就是需要破解的、&#xe801;
    [
        '<i>&#xe848;</i><i>&#xe801;</i>章&#8192;醒',
        '<i>&#xe848;</i>二章&#8192;谁'
    ]
    

    百度字体编辑器解密

    f12 打开刷新浏览器获取 font.ttf 字体文件,上传到 百度字体编辑器 就会得到一个字体对应关系:

    {'uniE800': '的', 'uniE801': '一', 'uniE802': '是', 'uniE803': '了',
     'uniE804': '我', 'uniE805': '不', 'uniE806': '人', 'uniE807': '在',
     'uniE808': '他', 'uniE809': '有', 'uniE80A': '这', 'uniE80B': '个',
     'uniE80C': '上', 'uniE80D': '们', 'uniE80E': '来', 'uniE80F': '到',
     'uniE810': '时', 'uniE811': '大', 'uniE812': '地', 'uniE813': '为',
     'uniE814': '子', 'uniE815': '中', 'uniE816': '你', 'uniE817': '说',
     'uniE818': '生', 'uniE819': '国', 'uniE81A': '年', 'uniE81B': '着',
     'uniE81C': '就', 'uniE81D': '那', 'uniE81E': '和', 'uniE81F': '要',
     'uniE820': '她', 'uniE821': '出', 'uniE822': '也', 'uniE823': '得',
     'uniE824': '里', 'uniE825': '后', 'uniE826': '自', 'uniE827': '以',
     'uniE828': '会', 'uniE829': '家', 'uniE82A': '可', 'uniE82B': '下',
     'uniE82C': '而', 'uniE82D': '过', 'uniE82E': '天', 'uniE82F': '去',
     'uniE830': '能', 'uniE831': '对', 'uniE832': '小', 'uniE833': '多',
     'uniE834': '然', 'uniE835': '于', 'uniE836': '心', 'uniE837': '学',
     'uniE838': '么', 'uniE839': '之', 'uniE83A': '都', 'uniE83B': '好',
     'uniE83C': '看', 'uniE83D': '起', 'uniE83E': '发', 'uniE83F': '当',
     'uniE840': '没', 'uniE841': '成', 'uniE842': '只', 'uniE843': '如',
     'uniE844': '事', 'uniE845': '把', 'uniE846': '还', 'uniE847': '用',
     'uniE848': '第', 'uniE849': '样', 'uniE84A': '道', 'uniE84B': '想',
     'uniE84C': '作', 'uniE84D': '种', 'uniE84E': '开', 'uniE84F': '美',
     'uniE850': '总', 'uniE851': '从', 'uniE852': '无', 'uniE853': '情',
     'uniE854': '己', 'uniE855': '面', 'uniE856': '最', 'uniE857': '女',
     'uniE858': '但', 'uniE859': '现', 'uniE85A': '前', 'uniE85B': '些',
     'uniE85C': '所', 'uniE85D': '同', 'uniE85E': '日', 'uniE85F': '手',
     'uniE860': '又', 'uniE861': '行', 'uniE862': '意', 'uniE863': '动'}
    

    提取 xml

    font.ttf 转换为 xml 文件,提取其中的字体对应关系:

    # pip install fontTools
    from fontTools.ttLib import TTFont
    
    def process_font():
        font = TTFont("fonteditor.ttf")
        font.saveXML("fonteditor.xml")
    

    font.xml

    <!-- 提取其中关键部分 -->
    <cmap>
        <tableVersion version="0"/>
        <cmap_format_4 platformID="0" platEncID="3" language="0">
          <map code="0xe800" name="uniE800"/><!-- ???? -->
          <map code="0xe801" name="uniE801"/><!-- ???? -->
          <map code="0xe802" name="uniE802"/><!-- ???? -->
          <map code="0xe803" name="uniE803"/><!-- ???? -->
          <map code="0xe804" name="uniE804"/><!-- ???? -->
          <map code="0xe805" name="uniE805"/><!-- ???? -->
          <map code="0xe806" name="uniE806"/><!-- ???? -->
            ....
        </cmap_format_4>
    </cmap>
    

    解析:

    def parse_xml():
        from xml.dom.minidom import parse
        import xml.dom.minidom
    
        # 使用minidom解析器打开 XML 文档
        DOMTree = xml.dom.minidom.parse("fonteditor.xml")
        collection = DOMTree.documentElement
    
        font_info_dict = {}
    
        # 在集合中获取所有 cmap
        cmap = collection.getElementsByTagName("cmap")
        for item in cmap:
            cmap_format_4 = item.getElementsByTagName("cmap_format_4")
            for cmp_ in cmap_format_4:
                if cmp_.getAttribute("platformID") == "0":
                    map_list = cmp_.getElementsByTagName("map")
                    for map in map_list:
                        code = map.getAttribute("code")
                        name = map.getAttribute("name")
                        
                        # 0xe806 转换为 &#xe806;
                        code = f'{re.sub("0xe", "&#xe", code)};'
                        # print(code, name)
                        font_info_dict[code] = name
    
        print(font_info_dict)
    

    对应关系:

    {'&#xe800;': 'uniE800', '&#xe801;': 'uniE801'...}
    

    以上三步走完之后差不多就可以完整解析了,完整代码

  • 相关阅读:
    自我介绍
    秋季学期总结
    第七周编程总结
    第六周作业
    第五周编程总结
    第四周编程总结
    第三周作业
    第二周作业
    抓老鼠啊~亏了还是赚了
    币值转换
  • 原文地址:https://www.cnblogs.com/midworld/p/15679095.html
Copyright © 2011-2022 走看看