您的位置:首页 >聚焦 >

爬虫高级内容,Python如何应对字体反爬

2022-03-04 20:10:06    来源:程序员客栈
前言

在编写网页爬虫的时候,我们经常会遇到各种反爬,比如js加密、css位置偏移、字体反爬等。最近在学习过程中,我碰到几个网站,都是使用的字体反爬,其大致上可以分为两类:一类是字体文件是静态的,另一类字体文件是动态的变化的。今天,我们探究一下,在爬虫中如何破解字体反爬。

一、如何寻找字体文件

字体文件大致上分两种,一种是以.ttf结尾的,一种是以.woff结尾的,两者相差不大,现在的网站运用的大多是woff文件。如何寻找网页使用的字体文件,可以分两类:

1.第一类 字体URL在网页源代码中

以aHR0cHM6Ly93d3cucmVucmVuY2hlLmNvbS9iai9lcnNob3VjaGUvP3Bsb2dfaWQ9NWI5NzA3MWI1YjVhNWZkYWRkOWZhZDEzMGE0MmJiMDM=网站为例:

打开网站后,明显能看到,8被替换成了6。这种情况,我们可以尝试在网页源代码中搜索“font-face”,查看字体URL。

2.第二类 字体URL不在网页源代码中,由服务器加载

以aHR0cHM6Ly93d3cuZ3VhemkuY29tL2J1eQ==网站为例:

这里可以看到车辆的行使里程数和首付均是字体反爬,按照第一种情况,我们直接在网页源代码中搜索“font-face”

可以看到,也是有woff文件和ttf文件,但这两个文件都是“element-icons”的链接,打开(软件:FontCreator)后也就是一堆图标。

遇到这种的,可以打开浏览器Network,刷新后抓包。

可以看到这个请求返回的结果中有一个woff文件,打开后观察:

这个正是我们要找的字体文件,当然这个网站要拿到字体URL需要js逆向verify-token这个参数,这里不展开说。

二、如何应对静态字体反爬

还是以aHR0cHM6Ly93d3cucmVucmVuY2hlLmNvbS9iai9lcnNob3VjaGUvP3Bsb2dfaWQ9NWI5NzA3MWI1YjVhNWZkYWRkOWZhZDEzMGE0MmJiMDM=网站为例,经过观察,他的字体是每天更换一次,暂且当作是静态。

1.在网页源代码中搜索字体文件的URL,复制到浏览器中打开,下载字体文件。2.用FontCreator打开文件,查看字体对应关系,手动建立对应关系字典。

#字体对应关系relation_table={"zero":"0","one":"2","two":"1","four":"3","three":"4","five":"8","seven":"7","nine":"9","six":"6","eight":"5"}

这是我学习过程中自己手动建立的对应关系。

3.请求字体链接,获取字体code和name的对应关系,然后遍历,获取网页中反爬文字的真实文字。

defwoff_font(font_url):"""获取字体真实对应关系"""newmap={}resp=session.get(font_url)#请求字体链接woff_data=BytesIO(resp.content)font=TTFont(woff_data)#读取woff数据cmap=font.getBestCmap()#获取字体对应关系font.close()fork,vincmap.items():value=vkey=str(k-48)#获取真实的keytry:get_real_data=relation_table[value]except:get_real_data=""ifget_real_data!="":newmap[key]=get_real_data#将字体真实结果对应returnnewmap

4.替换网页中的反爬文字

如果反爬字体是10进制或16进制的建议直接替换网页代码中的字体,如果是数字的,建议逐项替换。替换的方式有用正则表达式的(这里不说,因为我正则写的也不好),也有用列表推导式的,比如:

title="".join(html.xpath("//*[@id="zhimaicar-detail-header-right"]/div[1]/h1/text()")).strip()#获取原始标题trans_title="".join([iifnoti.isdigit()elsefont[i]foriintitle])#替换错误字体,获取真实标题

具体的用法,可以百度。

三、如何应对动态字体反爬

动态字体反爬,就是每请求一次(或一段时间后),字体的映射关系也会改变,因为第二个网站比较麻烦,这个还是以这个网站为例,将时间节点放大,把他看做是动态反爬的。

1.先下载字体文件2.安装fontTools

安装后用

fromfontTools.ttLibimportTTFontfont=TTFont(下载的字体文件)font.saveXML(文件名.xml)

将字体文件另存为xml文件,打开文件后会看到:

‘cmap’里存放的是字体code和name的关系

‘glyf’里存放的是字体形状和name的关系

3.手动建立字体形状和name的关系

只需手动建立一次。

f_font=TTFont("rrcttf3d6e374d48fb2cd14247257d4ae76674.woff")#读取分析的字体文件f_font_glyf=f_font["glyf"]#获取分析文件中的字体关系#建立基础的字体和字体形状的对应关系base_font_map={0:f_font_glyf["zero"],1:f_font_glyf["two"],2:f_font_glyf["one"],3:f_font_glyf["four"],4:f_font_glyf["three"],5:f_font_glyf["eight"],6:f_font_glyf["six"],7:f_font_glyf["seven"],8:f_font_glyf["five"],9:f_font_glyf["nine"],}

4.请求网页中的字体URL,获取code和name,形状和name的关系

resp=session.get(font_url)#请求字体链接woff_data=BytesIO(resp.content)#保存字体数据font=TTFont(woff_data)#读取woff数据glyf=font["glyf"]#获取请求到的字体形状code_name_map=font.getBestCmap()#获取请求到的字体code和name的对应关系font.close()

5.根据形状相同,肯定字体相同的原则,获取真实对应关系

forcode,nameincode_name_map.items():codestr=str(code-48)#根据分析结果需要减去48current_shape=glyf[name]#根据name获取字体形状fornumber,shapeinbase_font_map.items():#遍历基础字体形状对应关系ifshape==current_shape:#判断,如果两个字体形状相等newmap[codestr]=str(number)#将字体编码和字体添加到字典

6.完整代码

defwoff_font(font_url):newmap={}f_font=TTFont("rrcttf3d6e374d48fb2cd14247257d4ae76674.woff")#读取分析的字体文件f_font_glyf=f_font["glyf"]#获取分析文件中的字体关系#建立基础的字体和字体形状的对应关系base_font_map={0:f_font_glyf["zero"],1:f_font_glyf["two"],2:f_font_glyf["one"],3:f_font_glyf["four"],4:f_font_glyf["three"],5:f_font_glyf["eight"],6:f_font_glyf["six"],7:f_font_glyf["seven"],8:f_font_glyf["five"],9:f_font_glyf["nine"],}resp=session.get(font_url)#请求字体链接woff_data=BytesIO(resp.content)#保存字体数据font=TTFont(woff_data)#读取woff数据glyf=font["glyf"]#获取请求到的字体形状code_name_map=font.getBestCmap()#获取请求到的字体code和name的对应关系font.close()forcode,nameincode_name_map.items():codestr=str(code-48)#根据分析结果需要减去48current_shape=glyf[name]#根据name获取字体形状fornumber,shapeinbase_font_map.items():#遍历基础字体形状对应关系ifshape==current_shape:#判断,如果两个字体形状相等newmap[codestr]=str(number)#将字体编码和字体添加到字典returnnewmap

7.结果验证

当我在写这篇分享的时候,该网站的字体早已经换了,但是建立关系的时候我还用的是之前的文件,可见返回的结果也是没有问题的。

四、总结

静态字体反爬不用多说,面对动态反爬,一开始我也有点懵,后来在翻阅了一些资料和别人的启发后才弄明白,其实就是利用形状一样,字体肯定也一样的对应关系去破解。这是我学习过程中的一点经验总结,有不足之处还请各位指正,谢谢。

最后,推荐蚂蚁老师的视频套餐课程,包含爬虫部分,给我很大的帮助:

关键词: 对应关系 获取字体

相关阅读