wapi是什么(详细来说就是用字体库加密数据)
如果有更好的建议或者想看更多关于综合百科技术大全及相关资讯,可以多多关注茶馆百科网。

作者:亚伦
转发链接:https://segmentfault.com/a/1190000022781346
前言
对于前端的同学来说,他们实际做的是把数据整合好,按照UI同学的设计,把后端同学给的数据显示在网页里,导致很多人觉得前端很简单,后端没有工作,也没有复杂的业务逻辑。其实前端有很多工作要做。比如今天,我想讲讲如何实现数据的反抓取。笔者最近也接到了同样的任务。该公司的数据经常被爬虫爬走。发生这种情况后,我开始研究如何实现前端业务数据的反抓取。刚接到这个需求的时候,不知道怎么处理,只好硬着头皮接了任务。
接到任务后,我就开始各种Google。我觉得要做反爬虫,首先要知道爬虫是什么,是怎么工作的。这就像我们必须足够了解我们的对手,才能知道如何防守。
爬虫就是发送http请求得到响应后获取内容,按照一定规则自动抓取网页信息,然后保存数据的过程。
一开始作者还写了一个小爬虫来练习,大概就是发送一个get请求,然后通过类似DOM操作的东西在网页中找到需要的数据,然后存储起来。
分析58个案例
在调查的过程中,我发现很多博客都是针对58同城的网页数据抓取的,于是我就点进去看了看。58是用于加密数据的字体。你看到的和你实际展示的不一致。看起来很高端。
这是什么情况?所以我们查看了当前元素的CSS样式,我们可以注意到这个元素使用了一种奇怪的字体系列: fangchan-secret(real estate-encryption)字体样式。如果我们关闭这种strongbox样式,停止使用这种字体,乱码就会如实显示在页面上。
其实可以看出,58同城是用字体家族的字体进行加密的。作者在网络上找了很久也找不到关于这一段的这个字体文件。啊?那么字体是从哪里来的呢?于是笔者去查了一下font-family和@font-face一个CSS的相关文献。
原来@font-face不仅可以接收一个文件的地址,还可以在src中使用base64作为参数。于是我在58同城的页面里查了一下源代码。正如我所想,58同城并没有拉字体库资源,而是在页面刚创建的时候通过JavaScript脚本动态添加到页面中。
大概知道了58的骚操作后,我开始研究下一步,如何去体会文字里看到的和实际看到的区别。实际上,每个汉字和字符都对应一个Unicode编码。从第一张图不难看出,查看源代码时这些都是Unicode编码,浏览器通过Unicode在字体库中找到对应的字符。这个类似于通常的字体图标库(个人认为。哈哈哈)。
打开百度字体编辑网站,在中打开一个字体文件。ttf格式。
可以清楚的看到字体包里的每一个字,以$开头的缩写是unicode,并且做了一些处理,否则浏览器会直接解析成相应的字符。
接下来我回过头来分析一下58同城网页如何运营。当我查看源代码时,我看到的是另外5个unicode代码。这个unicode对应另一个不常用的汉字。
我们先把这一段写下来。为了更好的理解,把矛头指向使用过阿里logo库的同学应该不会陌生。阿里logo库会将svg文件转换成字体,通过下载引入我们的项目,完成图标展示。将为不同的字体生成新的unicode编码,但这些新的Unicode编码不会与现有字体库中的Unicode编码冲突。
由此,我们可以认为。ttf文件是一个svg文件。我们只需要通过技术手段将字体包转换成svg,获得svg中每个字体的绘制参数,将原文的unicode替换为生僻字的编码。说了就做了。
编程;编排
因为字体文件太多,所以在程序运行前需要对这些字体文件进行处理。将它们转换成svg需要很长时间,所以不可能每次收到请求都这样做。因此,为了能够在请求期间快速处理它们,您必须在程序运行之前将字体包转换成svg。
但是有一个问题,不是所有的字符都需要加密,而是一些特定的字符需要加密。所以为了保证这个操作,把目前需要加密的字符写入数据库,转换成svg后读取svg文件中的标签,标签中的绘制路径的属性和一些必要的参数按照对应的字符存储在数据库中。
每次收到数据请求时直接读取数据库中的数据,然后生成一个svg文件,再将生成的svg文件处理成base64并发送到前端完成显示。
解析字体文件
我遇到的第一个问题是如何解析字体文件。因为不太懂其他语言,只能用node,通过搜索npm仓库找到了相关库ttf2svg。
首先安装此库:
此处使用了Npminstall-save-devttf2svg
基础字体库是微软雅黑这个文件在电脑中就可以找到。MicrosoftYaHei.ttf如果找不到的小伙伴可以自行百度一下。读取字体包转svg代码如下:
importpathfrom"path";importfsfrom"fs";importutilfrom"util";importttf2svgfrom"ttf2svg";//每次启动前需要删除原有svg文件,以防改变了所需要加密的字体包,参数没有及时发生变化import{removeDir}from"../util/fs";//读取文件constreadFile=util.promisify(fs.readFile);//写入文件constwriteFile=util.promisify(fs.writeFile);//创建文件夹constmkdir=util.promisify(fs.mkdir);constttfToSvg=async()=>{//运行根目录constrootPath=process.cwd();//.ttf文件所在目录constttfUrl=path.join(rootPath,"static/ttf/MicrosoftYaHei.ttf");//导出文件文件夹名称constsaveSvgMkdirName="ttfSvg";//svg存储路径constsaveSvgUrl=path.resolve(rootPath,`${saveSvgMkdirName}/MicrosoftYaHei.svg`);//svg文件夹路径constsvgDirUrl=path.resolve(rootPath,saveSvgMkdirName);//读取ttf文件生成bufferconstttfBuffer=awaitreadFile(ttfUrl);//通过ttf2svg将buffer转换成svgconstsvgContent=ttf2svg(ttfBuffer);//删除原有svg文件removeDir(svgDirUrl);//创建存放svg文件夹awaitmkdir(svgDirUrl);//写入svgawaitwriteFile(saveSvgUrl,svgContent);//返回存放svg的路径地址returnsaveSvgUrl;};util/fs.js
importfsfrom"fs";exportconstremoveDir=(path)=>{letfiles=[];if(fs.existsSync(path)){files=fs.readdirSync(path);files.forEach((file,index)=>{letcurPath=path+"/"+file;fs.unlinkSync(curPath);});fs.rmdirSync(path);}}生成好所需要的svg文件,看看生成好的svg是不是我们所需要的呢?
看样的一切都在朝着好的方向发展,这个东西正是我们所需要的。接下来就是开始读取svg文件(这里就不同步数据库了,小伙伴们可以根据自己的需求进行同步处理),想要读取svg开始的时候还是蛮头疼的,不知道该如何去读取里面的内容。想了想之后觉得svg和xml是差不多的,于是就尝试着使用读取xml文件的形式去读取svg文件,结果就真的成了。
这里使用xmldom来读取的svg文件:
npminstall--save-devxmldom有关xmldom的一些文档大家可以自行百度一下,也没有太复杂。具体应用代码如下:
importfsfrom"fs";importutilfrom"util";import{DOMParser}from"xmldom";constreadFile=util.promisify(fs.readFile);constreadSvg=async(svgPath)=>{//读取svg文件constsvgContent=awaitreadFile(svgPath);//读取内容转换成utf8形式constsvgHtml=Buffer.from(svgContent).toString("utf8");//生成伪xmlconstdoc=(newDOMParser()).parseFromString(svgHtml,'application/xml');//获取到第一个font标签constoFont=doc.getElementsByTagName("font")[0];//获取到font下面的所有glyph标签,并转换成数组//读取出来的是个伪数组需要转换constoGlyphs=Array.from(oFont.getElementsByTagName("glyph"));//测试临时使用数组constarr=[];//遍历oGlyphs所有标签oGlyphs.map((fontEle,index)=>{//svg对应的unicodeconstunicode=fontEle.getAttribute("unicode");//svg绘制参数constd=fontEle.getAttribute("d");//svg横向位置consthorizAdvX=fontEle.getAttribute("horiz-adv-x");//svg竖向位置constvertAdvY=fontEle.getAttribute("vert-adv-y");//这里只是个方便测试做的判断if(index===20||index===21||index===22){arr.push({unicode,d,horizAdvX,vertAdvY});}})console.log(...arr);};执行完上述代码就完成,完全可以读取到里面的所有属性。这个时候忽然感觉已经看到的胜利的曙光有没有,哈哈哈。接下来就是最关键的一步了,如何把读取到的内容转换成是转换成base64编码。经过一番搜索之后,找到了svg2ttf这个仓库,简直没有太香啊。
安装相关依赖:
npminstall--save-devsvg2ttf具体实现如下:
importfsfrom"fs";importutilfrom"util";import{DOMParser}from"xmldom";constreadFile=util.promisify(fs.readFile);constreadSvg=async(svgPath)=>{//读取svg文件constsvgContent=awaitreadFile(svgPath);//读取内容转换成utf8形式constsvgHtml=Buffer.from(svgContent).toString("utf8");//生成伪xmlconstdoc=(newDOMParser()).parseFromString(svgHtml,'application/xml');//获取到第一个font标签constoFont=doc.getElementsByTagName("font")[0];//获取到font下面的所有glyph标签,并转换成数组//读取出来的是个伪数组需要转换constoGlyphs=Array.from(oFont.getElementsByTagName("glyph"));//测试临时使用数组constarr=[];//遍历oGlyphs所有标签oGlyphs.map((fontEle,index)=>{//svg对应的unicodeconstunicode=fontEle.getAttribute("unicode");//svg绘制参数constd=fontEle.getAttribute("d");//svg横向位置consthorizAdvX=fontEle.getAttribute("horiz-adv-x");//svg竖向位置constvertAdvY=fontEle.getAttribute("vert-adv-y");//这里只是个方便测试做的判断if(index===20||index===21||index===22){arr.push({unicode,d,horizAdvX,vertAdvY});}})//获取svg内容letsvgStr=getSvgStr(arr);console.log(svgStr)//把svg转换成ttfconstttf=svg2ttf(svgStr,{});//把ttf转换成base64constbase64=Buffer.from(ttf.buffer).toString('base64');console.log(base64);};constgetSvgStr=(arr)=>{//用与拼接的svgletstr="";//临时替换文件,暂时性的,以后需要替换成所以unicodelet_a=["唹","唵","啜"];//生成svg内容arr.map((el,index)=>{str+=`<glyphglyph-name="${+newDate()}"unicode="${_a[index]};"d="${el.d}"horiz-adv-x="${el.horizAdvX}"vert-adv-y="${el.vertAdvY}"/>`;})//返回svg形式的字符串return`<?xmlversion="1.0"standalone="no"?><!DOCTYPEsvgPUBLIC"-//W3C//DTDSVG1.1//EN""http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svgxmlns="http://www.w3.org/2000/svg"><defs><fontid="svgtofont"horiz-adv-x="2688"vert-adv-y="2688"><font-facefont-family="MicrosoftYaHei"font-weight="400"font-stretch="normal"units-per-em="2048"ascent="2167"descent="-536"/><missing-glyph/>${str}</font></defs></svg>`;}这里出了一些小问题,注意我们要把我们所生成的字体svg文件的font标签部分复制过来,作为参数如果不这样做的话生成的字体会出现位置偏移的现象。
所有工作准备就绪了,执行程序就可以得到应该给前端的base64编码了,这我也进行了测试。
<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><metahttp-equiv="X-UA-Compatible"content="ie=edge"><title>Document</title></head><script>functionaddStyle(base64,fontName){letoStyle=document.createElement("style");oStyle.innerText=`@font-face{font-family:"${fontName}";src:url(data:application/x-font-woff;charset=utf-8;base64,${base64});}`;document.head.appendChild(oStyle);};constb="AAEAAAALAIAAAwAwR1NVQiCLJXoAAAE4AAAAVE9TLzLBusXmAAABjAAAAFZjbWFwAQcDhQAAAfQAAAGcZ2x5ZoQIB1wAAAOcAAABBGhlYWQfidbHAAAA4AAAADZoaGVhEvkIbQAAALwAAAAkaG10eBiTAAAAAAHkAAAAEGxvY2EArABmAAADkAAAAAptYXhwARAALwAAARgAAAAgbmFtZcrWmLMAAASgAAACNHBvc3RPEx32AAAG1AAAAFcAAQAACHf96AAACoAAAAAACoAAAQAAAAAAAAAAAAAAAAAAAAQAAQAAAAEAAMIjHBpfDzz1AAsIAAAAAADa9UXfAAAAANr1Rd8AAP/lCoAGJwAAAAgAAgAAAAAAAAABAAAABAAjAAIAAAAAAAIAAAAKAAoAAAD/AAAAAAAAAAEAAAAKADAAPgACREZMVAAObGF0bgAaAAQAAAAAAAAAAQAAAAQAAAAAAAAAAQAAAAFsaWdhAAgAAAABAAAAAQAEAAQAAAABAAgAAQAGAAAAAQAAAAEGJQGQAAUAAAaqB2QAAAF6BqoHZAAABREAhAK5AAACAAUDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBmRWQAwFU1VVwId/3oAPMIdwIYAAAAAQAAAAAAAAqAAAAEsQAABLEAAASxAAAAAAAFAAAAAwAAACwAAAAEAAABaAABAAAAAABiAAMAAQAAACwAAwAKAAABaAAEADYAAAAIAAgAAgAAVTVVOVVc//8AAFU1VTlVXP//AAAAAAAAAAEACAAIAAgAAAACAAEAAwAAAQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAANAAAAAAAAAADAABVNQAAVTUAAAACAABVOQAAVTkAAAABAABVXAAAVVwAAAADAAAAAAAqAGYAggAAAAEAAP/lBB4GDQAWAAABFAAjIic1FiA2ECYjIgcTIRUhAzcyBAQe/tP+2mudAUXHz72SdTkC1P3RII32ARkB3uP+6kHIZrMBKKUNAxKs/kkG9QAAAAIAAP/mBFsGJwAWACIAAAEmIyICAzM2MzISFRQAIyIAERAAITIXARQWMzI2NTQmIyIGA/p5hMn0AgVu8cnw/uvX7P7zAWEBIKVe/VCjh4Cgl4uEpAVGPv6i/tHV/vrZ4/7cAXEBUwGaAeMt/AGZ2ryUoLK0AAAAAAEAAAAABEcGDQAKAAABAgADIxIAEyE1IQRH9P7pIcwlARTn/QAD2AWU/lb9K/7rARECvAGTrQAAAAAQAMYAAQAAAAAAAQAPAAAAAQAAAAAAAgAHAA8AAQAAAAAAAwAJABYAAQAAAAAABAAJAB8AAQAAAAAABQALACgAAQAAAAAABgAJADMAAQAAAAAACgArADwAAQAAAAAACwATAGcAAwABBAkAAQAeAHoAAwABBAkAAgAOAJgAAwABBAkAAwASAKYAAwABBAkABAASALgAAwABBAkABQAWAMoAAwABBAkABgASAOAAAwABBAkACgBWAPIAAwABBAkACwAmAUhNaWNyb3NvZnQgWWFIZWlSZWd1bGFyc3ZndG9mb250c3ZndG9mb250VmVyc2lvbiAxLjBzdmd0b2ZvbnRHZW5lcmF0ZWQgYnkgc3ZnMnR0ZiBmcm9tIEZvbnRlbGxvIHByb2plY3QuaHR0cDovL2ZvbnRlbGxvLmNvbQBNAGkAYwByAG8AcwBvAGYAdAAgAFkAYQBIAGUAaQBSAGUAZwB1AGwAYQByAHMAdgBnAHQAbwBmAG8AbgB0AHMAdgBnAHQAbwBmAG8AbgB0AFYAZQByAHMAaQBvAG4AIAAxAC4AMABzAHYAZwB0AG8AZgBvAG4AdABHAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAHMAdgBnADIAdAB0AGYAIABmAHIAbwBtACAARgBvAG4AdABlAGwAbABvACAAcAByAG8AagBlAGMAdAAuAGgAdAB0AHAAOgAvAC8AZgBvAG4AdABlAGwAbABvAC4AYwBvAG0AAgAAAAAAAAAbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAQIBAwEEAQUADTE1OTA2NjI0OTU4NzQNMTU5MDY2MjQ5NTg3NA0xNTkwNjYyNDk1ODc0AAAA";constn="abc";addStyle(b,n);</script><body><divclass="box"><div></div><div></div><divstyle="font-family:abc;color:red;font-size:50px;">唹唵啜567</div><div></div><divclass="fiveBox">0123456789</div></div><script></script><style>*{margin:0px;padding:0px;}.box{width:100%;white-space:nowrap;}.boxdiv{width:500px;height:50px;border:1pxsolid#ededed;/*float:left;*/font-size:20px;color:pink;}.box::after{content:"";display:block;clear:both;}</style></body></html>以上就是我的测试代码,展示效果如下:
这样下来就和58同城的效果是一样的了,经过了几天的调研也算是有了初步的成果,也是有一些成就感的。
总结
总的来说在这个调研的过程中还是学到了很多的东西,比如阿里图标库是如何实现的,字体包里面都有什么等等等。。。虽然在这个过程中用了很多第三方的依赖,但是结果是好的。
文章比较潦草,感谢各位花费这么长时间阅读,文章中如果有什么错误,请在评论处指出,我会尽快做出改正。
推荐JavaScript经典实例学习资料文章
《Node.js要完了吗?》
《Pug3.0.0正式发布,不再支持Node.js6/8》
《纯JS手写轮播图(代码逻辑清晰,通俗易懂)》
《JavaScript20年中文版之创立标准》
《值得收藏的前端常用60余种工具方法「JS篇」》
《箭头函数和常规函数之间的5个区别》
《通过发布/订阅的设计模式搞懂Node.js核心模块Events》
《「前端篇」不再为正则烦恼》
《「速围」Node.jsV14.3.0发布支持顶级Await和REPL增强功能》
《深入细品浏览器原理「流程图」》
《JavaScript已进入第三个时代,未来将何去何从?》
《前端上传前预览文件image、text、json、video、audio「实践」》
《深入细品EventLoop和浏览器渲染、帧动画、空闲回调的关系》
《推荐13个有用的JavaScript数组技巧「值得收藏」》
《前端必备基础知识:window.location详解》
《不要再依赖CommonJS了》
《犀牛书作者:最该忘记的JavaScript特性》
《36个工作中常用的JavaScript函数片段「值得收藏」》
《Node+H5实现大文件分片上传、断点续传》
《一文了解文件上传全过程(1.8w字深度解析)「前端进阶必备」》
《【实践总结】关于小程序挣脱枷锁实现批量上传》
《手把手教你前端的各种文件上传攻略和大文件断点续传》
《字节跳动面试官:请你实现一个大文件上传和断点续传》
《谈谈前端关于文件上传下载那些事【实践】》
《手把手教你如何编写一个前端图片压缩、方向纠正、预览、上传插件》
《最全的JavaScript模块化方案和工具》
《「前端进阶」JS中的内存管理》
《JavaScript正则深入以及10个非常有意思的正则实战》
《前端面试者经常忽视的一道JavaScript面试题》
《一行JS代码实现一个简单的模板字符串替换「实践」》
《JS代码是如何被压缩的「前端高级进阶」》
《前端开发规范:命名规范、html规范、css规范、js规范》
《【规范篇】前端团队代码规范最佳实践》
《100个原生JavaScript代码片段知识点详细汇总【实践】》
《关于前端174道JavaScript知识点汇总(一)》
《关于前端174道JavaScript知识点汇总(二)》
《关于前端174道JavaScript知识点汇总(三)》
《几个非常有意思的javascript知识点总结【实践】》
《都2020年了,你还不会JavaScript装饰器?》
《JavaScript实现图片合成下载》
《70个JavaScript知识点详细总结(上)【实践】》
《70个JavaScript知识点详细总结(下)【实践】》
《开源了一个JavaScript版敏感词过滤库》
《送你43道JavaScript面试题》
《3个很棒的小众JavaScript库,你值得拥有》
《手把手教你深入巩固JavaScript知识体系【思维导图】》
《推荐7个很棒的JavaScript产品步骤引导库》
《Echa哥教你彻底弄懂JavaScript执行机制》
《一个合格的中级前端工程师需要掌握的28个JavaScript技巧》
《深入解析高频项目中运用到的知识点汇总【JS篇】》
《JavaScript工具函数大全【新】》
《从JavaScript中看设计模式(总结)》
《身份证号码的正则表达式及验证详解(JavaScript,Regex)》
《浏览器中实现JavaScript计时器的4种创新方式》
《Three.js动效方案》
《手把手教你常用的59个JS类方法》
《127个常用的JS代码片段,每段代码花30秒就能看懂-【上】》
《深入浅出讲解js深拷贝vs浅拷贝》
《手把手教你JS开发H5游戏【消灭星星】》
《深入浅出讲解JS中this/apply/call/bind巧妙用法【实践】》
《手把手教你全方位解读JS中this真正含义【实践】》
《书到用时方恨少,一大波JS开发工具函数来了》
《干货满满!如何优雅简洁地实现时钟翻牌器(支持JS/Vue/React)》
《手把手教你JS异步编程六种方案【实践】》
《让你减少加班的15条高效JS技巧知识点汇总【实践】》
《手把手教你JS开发H5游戏【黄金矿工】》
《手把手教你JS实现监控浏览器上下左右滚动》
《JS经典实例知识点整理汇总【实践】》
《2.6万字JS干货分享,带你领略前端魅力【基础篇】》
《2.6万字JS干货分享,带你领略前端魅力【实践篇】》
《简单几步让你的JS写得更漂亮》
《恭喜你获得治疗JSthis的详细药方》
《谈谈前端关于文件上传下载那些事【实践】》
《面试中教你绕过关于JavaScript作用域的5个坑》
《Jquery插件(常用的插件库)》
《【JS】如何防止重复发送ajax请求》
《JavaScript+Canvas实现自定义画板》
《Continuation在JS中的应用「前端篇」》
作者:Aaron
转发链接:https://segmentfault.com/a/1190000022781346
本文主要介绍了关于wapi是什么(详细来说就是用字体库加密数据)的相关养殖或种植技术,综合百科栏目还介绍了该行业生产经营方式及经营管理,关注综合百科发展动向,注重系统性、科学性、实用性和先进性,内容全面新颖、重点突出、通俗易懂,全面给您讲解综合百科技术怎么管理的要点,是您综合百科致富的点金石。
以上文章来自互联网,不代表本人立场,如需删除,请注明该网址:http://23.234.50.4:8411/article/98948.html