• JAVA爬虫对font-face字体反爬虫解密


             1.参考博客

             https://www.jianshu.com/p/9975de57b0ce

             https://blog.csdn.net/litang199612/article/details/83413002

             https://blog.csdn.net/m0_37156322/article/details/84658872

             https://blog.csdn.net/paul0926/article/details/96336947

             本博客重点讲解java实现反爬虫字体解密,了解具体原因请参考以上博客,Python也请参考以上博客。

             2.背景

              在针对安居客等房地产项目进行数据爬虫工作中,发现页面的显示为标准的数字,但数据抓取到确实乱码

              页面:

              页面审查:

           

              页面显示的“2500”,但数据显示的却是“龒麣龤龤”的乱码,很疑惑,最后审查发现数据显示是使用的一个特殊字体“fangchan-secret”。

     fangchan-secret

     经查询相关文档和博客,发现fang-secret是一个动态生成字体库的工具,而且每次根据不同key生成,字体库动态生成,后端又不存在相关字体库,所以获取的是乱码。key为base64,重新加载页面key为变化,具体的key可以审查页面,检索"AAAAA",比较长的一串的base64编码的就是了,浏览器每次返回页面根据动态字体库渲染相关数据。

             3.解决方案

             在博客和相关文档中,了解了相关原因,但其具体的实现却是基于python实现,最关键的是python的ttffont的库,一直想找java的解决方案没有,只好自己动手。

             拿到动态生成的字体库的key

            

             因为字体库基于key生成,这里实现可以通过java的爬虫工具,然后使用正则表达式实现,然后拿到以下的字符串:

             

             生成字体库,解码

             这里使用java的awt的相关jar包,关键的类Font实现

             

     1     /**
     2      * font-secret字符串专用解密工具
     3      *
     4      * @param key          密匙
     5      * @param encodeString 加密后的字符串
     6      * @return             解密后的字符串
     7      */
     8     public static String decodeString(String key, String encodeString) {
     9         try {
    10             //base64解码,初始化字体
    11             byte[] ss = Base64.decodeBase64(key);
    12             InputStream inputStream = new ByteArrayInputStream(ss);
    13             Font dynamicFont = Font.createFont(Font.TRUETYPE_FONT, inputStream);
    14             FontRenderContext fontRenderContext = new FontRenderContext(new AffineTransform(), false, false);
    15             GlyphVector glyphVector = dynamicFont.createGlyphVector(fontRenderContext, "");
    16 
    17             //获取font中字形的映射关系,字段为private,使用反射
    18             Class<?> clazz = Font.class;
    19             Field[] fs = clazz.getDeclaredFields();
    20             Font2DHandle font2DHandle = null;
    21             for (int i = 0; i < fs.length; i++) {
    22                 fs[i].setAccessible(true);// 将目标属性设置为可以访问
    23                 if (fs[i].getName().equals("font2DHandle")) {
    24                     font2DHandle = (Font2DHandle) fs[i].get(dynamicFont);
    25                 }
    26 
    27             }
    28 
    29             //得到映射关系
    30             Font2D font2D = font2DHandle.font2D;
    31             TrueTypeFont trueTypeFont = (TrueTypeFont) font2D;
    32             TrueTypeGlyphMapper charToGlyphMapper = (TrueTypeGlyphMapper) trueTypeFont.getMapper();
    33 
    34             //开始解密,encodeString为加密后的字符串
    35             StringBuffer buffer = new StringBuffer();
    36             char[] chars = encodeString.toCharArray();
    37             for (int i = 0; i < chars.length; i++) {
    38                 buffer.append(charToGlyphMapper.charToGlyph(chars[i]) - 1);
    39             }
    40             return buffer.toString();
    41         } catch (Exception e) {
    42             e.printStackTrace();
    43         }
    44         return "";
    45     }

          4.demo

     demo:https://gitee.com/scnucxy/spiderFontDemo

          

              

  • 相关阅读:
    saltstack远程执行
    centos7防火墙的关闭和禁用
    saltstack 安装使用
    flask基础-第一个flask-jinja2-response三剑客-request-session
    linux服务器排查病毒纪实
    读完这篇文章,就基本搞定了Redis主从复制
    Django学习【第26篇】:中介模型以及优化查询以及CBV模式
    Django学习【第26篇】:后端CORS解决跨域问题
    Django学习【第25篇】:前端Jsonp解决跨域问题
    Django学习【第24篇】:JS实现的ajax和同源策略
  • 原文地址:https://www.cnblogs.com/cxyc/p/11290207.html
Copyright © 2020-2023  润新知