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实现
- /**
- * font-secret字符串专用解密工具
- *
- * @param key 密匙
- * @param encodeString 加密后的字符串
- * @return 解密后的字符串
- */
- public static String decodeString(String key, String encodeString) {
- try {
- //base64解码,初始化字体
- byte[] ss = Base64.decodeBase64(key);
- InputStream inputStream = new ByteArrayInputStream(ss);
- Font dynamicFont = Font.createFont(Font.TRUETYPE_FONT, inputStream);
- FontRenderContext fontRenderContext = new FontRenderContext(new AffineTransform(), false, false);
- GlyphVector glyphVector = dynamicFont.createGlyphVector(fontRenderContext, "");
- //获取font中字形的映射关系,字段为private,使用反射
- Class<?> clazz = Font.class;
- Field[] fs = clazz.getDeclaredFields();
- Font2DHandle font2DHandle = null;
- for (int i = 0; i < fs.length; i++) {
- fs[i].setAccessible(true);// 将目标属性设置为可以访问
- if (fs[i].getName().equals("font2DHandle")) {
- font2DHandle = (Font2DHandle) fs[i].get(dynamicFont);
- }
- }
- //得到映射关系
- Font2D font2D = font2DHandle.font2D;
- TrueTypeFont trueTypeFont = (TrueTypeFont) font2D;
- TrueTypeGlyphMapper charToGlyphMapper = (TrueTypeGlyphMapper) trueTypeFont.getMapper();
- //开始解密,encodeString为加密后的字符串
- StringBuffer buffer = new StringBuffer();
- char[] chars = encodeString.toCharArray();
- for (int i = 0; i < chars.length; i++) {
- buffer.append(charToGlyphMapper.charToGlyph(chars[i]) - 1);
- }
- return buffer.toString();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return "";
- }
4.demo
JAVA爬虫对font-face字体反爬虫解密的更多相关文章
- 深入细枝末节,Python的字体反爬虫到底怎么一回事
内容选自 即将出版 的<Python3 反爬虫原理与绕过实战>,本次公开书稿范围为第 6 章——文本混淆反爬虫.本篇为第 6 章中的第 4 小节,其余小节将 逐步放送 . 字体反爬虫开篇概 ...
- Python 爬虫工程师必看,深入解读字体反爬虫
字体反爬虫开篇概述 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经做案例的人,却不知道如何去学习更加高深的知识.那么针对这三类人 ...
- 基于C#.NET的高端智能化网络爬虫(一)(反爬虫哥必看)
前两天朋友发给我了一篇文章,是携程网反爬虫组的技术经理写的,大概讲的是如何用他的超高智商通过(挑衅.怜悯.嘲讽.猥琐)的方式来完美碾压爬虫开发者.今天我就先带大家开发一个最简单低端的爬虫,突破携程网超 ...
- python网络爬虫 - 如何伪装逃过反爬虫程序
有的时候,我们本来写得好好的爬虫代码,之前还运行得Ok, 一下子突然报错了. 报错信息如下: Http 800 Internal internet error 这是因为你的对象网站设置了反爬虫程序,如 ...
- Python爬虫学习笔记——防豆瓣反爬虫
开始慢慢测试爬虫以后会发现IP老被封,原因应该就是单位时间里面访问次数过多,虽然最简单的方法就是降低访问频率,但是又不想降低访问频率怎么办呢?查了一下最简单的方法就是使用转轮代理IP,网上找了一些方法 ...
- 自动更改IP地址反爬虫封锁,支持多线程(转)
8年多爬虫经验的人告诉你,国内ADSL是王道,多申请些线路,分布在多个不同的电信机房,能跨省跨市更好,我这里写好的断线重拨组件,你可以直接使用. ADSL拨号上网使用动态IP地址,每一次拨号得到的IP ...
- WebSocket 反爬虫
目录 WebSocket握手验证反爬虫 WebSocket 消息校验反爬虫 WebSocket Ping 反爬虫 总结 WebSocket握手验证反爬虫 ! HTTP协议 请求头 服务器端创建 soc ...
- 温故知新,.Net Core利用UserAgent+rDNS双解析方案,正确识别并反爬虫/反垃圾邮件
背景 一般有价值的并保有数据的网站或接口很容易被爬虫,爬虫会占用大量的流量资源,接下来我们参考历史经验,探索如何在.Net Core中利用UserAgent+rDNS双解析方案来正确识别并且反爬虫. ...
- k 近邻算法解决字体反爬手段|效果非常好
字体反爬,是一种利用 CSS 特性和浏览器渲染规则实现的反爬虫手段.其高明之处在于,就算借助(Selenium 套件.Puppeteer 和 Splash)等渲染工具也无法拿到真实的文字内容. 这种反 ...
随机推荐
- 【js】字符串反转(倒序)的多种处理方式
今天发布一篇关于字符串反转的几种方式(一种问题的解决方案不是只有一种). 方式1: 这种方式比较简单,推荐使用 字符串转数组,反转数组,数组转字符串. split(""):根据空字 ...
- Linux下安装php开发环境
先记录下以恶搞教程,回头自己更 https://my.oschina.net/hhly/blog/1547227
- Vue路由嵌套和命名视图
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Python_算术运算符
1.算术运算符 示例: >>> num1=7 >>> num2=3 >>> num1+num2 #+ 10 >>> num1-n ...
- 小程序数据绑定和setData
我们wxml没有直接调用数据的能力,我们的逻辑是通过js调用数据,再由js传递给wxml才能够显示出来.那么怎么由js传递给wxml? 首先我的js里面有这样一段代码 process: funct ...
- 使用C#应用程序与Arduino开发板进行通信
在本文中,我们将一个Arduino Pro Mini开发板连接到PC,并且使用C# Windows应用程序与其进行通信. 将硬件连接到PC是非常有利的,不仅是因为你可以发送命令以及监控状态,还可以实时 ...
- linux网络编程之posix共享内存
今天继续研究posix IPC对象,这次主要是学习一下posix共享内存的使用方法,下面开始: 下面编写程序来创建一个共享内存: 编译运行: 那posix的共享内存存放在哪里呢?上节中学的posix的 ...
- psql主主复制
主主是mysql的概念,通常在mysql中为保证事务一致也是一台主写,一台做读.pg主从可以互为切换 之前没做数据库部署这部分,一个同事离职暂时没人,接受过来的!mysql做的是主主复制,我理解是可以 ...
- Nginx入门(四)——反向代理
server { listen 8020; server_name localhost; location / { root html; index index.html index.htm; pro ...
- VUE this.$http.post 与后端flask 数据交互
背景: 小鱼第一次前端用的VUE,然后前后端的交互调了几次,记录下来留给自己下次使用 前端 通过 form.XXX 获取数据,代码: <template> <el-form ref ...