zoukankan      html  css  js  c++  java
  • 58 字体反爬攻略 python3

    1、下载安装包

    pip install fontTools

    2、下载查看工具FontCreator 

    百度后一路傻瓜式安装即可

    3、反爬虫机制

    网页上看见的

    后台源代码里面的

    从上面可以看出,生这个字变成了乱码,请大家特别注意箭头所指的数字。

    3、解决

    1、确定反爬方法

    在看了别人的解析文章之后,确定采取的是字体反爬机制,即网站定义了字体文件,然后进行相应的查找替换,在前端看起来,是没有任何差异的。其实从审查元素的也是可以看到的:

    和大众点评的反爬差不多,都是通过css搞得。

    2、寻找字体文件

    以上面方框里的”customfont“为关键词搜了一下,发现就在源代码里面:

    而且还有base64,直接进行解密,但是解密出来的其实是乱码,这个时候其实要做的很简单,把解密后的内容保存为.ttf格式即可。

    ttf文件: *.ttf是字体文件格式。TTF(TrueTypeFont)是Apple公司和Microsoft公司共同推出的字体文件格式,随着windows的流行,已经变成最常用的一种字体文件表示方式。

    @font-face 是CSS3中的一个模块,主要是实现将自定义的Web字体嵌入到指定网页中去。

    因为我们要对字体进行研究,所以必须将它打开,这里我是用的是FontCreator,打开以后是这个样子(其实很多字,在这里为了看的清楚,所以只截了下面的图):

    很明显,每个字可以看到字形和字形编码。

    观察现在箭头指的地方和前面箭头指的地方的数字是不是一样啊,没错,就是通过这种方法进行映射的。

    所以我们现在的思路似乎就是在源代码里找到箭头指的数字,然后再来字体里找到后替换就行了。

    恭喜你,如果你也是这么想的,那你就掉坑里了。

    因为每次访问,字体字形是不变的,但字符的编码确是变化的。因此,我们需要根据每次访问,动态解析字体文件。

    字体1:

    字体2:

    所以想通过写死的方式也是行不通的。

    这个时候我们就要对字体文件进行更深一步的研究了。

    3、研究字体文件

    刚刚的.ttf文件我们是看不到内部的东西的,所以这个时候我们要对字体文件进行转换格式,将其转换为xml格式,然后来查看:

    具体操作如下:

    xml的格式如下:

    今天,我终于弄懂了字体反爬是个啥玩意!

    文件很长,我只截取了一部分。

    仔细的观察一下,你会发现~这俩下面的x,y,on值都是一毛一样的。所以我们的思路就是以一个已知的字体文件为基本,然后将获取到的新的字体文件的每个文字对应的x,y,on值进行比较,如果相同,那么说明新的文字对就 可以在基础字体那里找到对应的文字,有点绕,下面举个小例子。

    假设: “我” 在基本字体中的名为uni1,对应的x=1,y=1,n=1新的字体文件中,一个名为uni2对应的x,y, n分别于上面的相等,那么这个时候就可以确定uni2 对应的文字为”我”。

    查资料的时候,发现在特殊情况下,有时候两个字体中的文字对应的x,y不相等,但是差距都是在某一个阈值之内,处理方法差不多,只不过上面是相等,这种情况下就是要比较一下。

    其实,如果你用画图工具按照上面的x与y值把点给连起来,你会发现,就是汉字的字形~

    所以,到此总结一下:

    一、将某次请求获取到的字体文件保存到本地[基本字体];
    二、用软件打开后,人工的找出每一个数字对应的编码[
    一定要保证顺序的正确,要不然会出事];
    三、我们以后访问网页时,需要保存新字体文件;
    四、用Fonttools库对基本字体与新字体进行处理,找
    到新的字体与基本字体之间的映射;
    五、替换;

    4、代码

    # coding=utf-8
    import requests
    import re
    import time
    import  lxml.html as H
    import base64
    from fontTools.ttLib import TTFont
    import requests
    from lxml import etree
    def get_data(url):
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
        }
        response = requests.get(url, headers=headers)
        font_data_origin = re.search(r'base64,(.*?))', response.text, re.S).group(1)
        font_data_after_decode = base64.b64decode(font_data_origin)
        new_font_name = "font_new.ttf"
        with open(new_font_name, 'wb') as f:
            f.write(font_data_after_decode)
        # font_base = TTFont('font_base.ttf').saveXML('font_base.xml')
        # font_base = TTFont('font_new.ttf').saveXML('font_new.xml')
        map_data = tff_parse(new_font_name)
        names = etree.HTML(response.text).xpath('//span[@class="infocardName fl stonefont resumeName"]/text()')
        # 有的时候会找不到,可以多执行几次;
        if names:
            for name in names:
                print('name in page source', name)
                for j in map_data.keys():
                        name = name.replace(j, map_data[j])
                print('name actual', name)
    
    def tff_parse(font_parse_name):
        # 我这里的字体的顺序,如果你的不同,一定要修改
        font_dict = [u'', u'', u'', u'', u'', u'', u'8', u'1', u'', u'E', u'2', u'6', u'',
                     u'M', u'', u'5', u'', u'', u'', u'', u'', u'', u'4', u'', u'', u'', u'',
                     u'', u'', u'', u'A', u'', u'', u'3', u'', u'7', u'0', u'9', u'', u'', u'',
                     u'', u'', u'', u'B']
        font_base = TTFont('font_base.ttf')
        font_base_order = font_base.getGlyphOrder()[1:]
        # font_base.saveXML('font_base.xml')  #调试用
    
        font_parse = TTFont(font_parse_name)
        # font_parse.saveXML('font_parse_2.xml')调试用
        font_parse_order = font_parse.getGlyphOrder()[1:]
        f_base_flag = []
        for i in font_base_order:
            flags = font_base['glyf'][i].flags
            f_base_flag.append(list(flags))
        f_flag = []
        for i in font_parse_order:
            flags = font_parse['glyf'][i].flags
            f_flag.append(list(flags))
        result_dict = {}
        for a, i in enumerate(f_base_flag):
            for b, j in enumerate(f_flag):
                if comp(i, j):
                    key = font_parse_order[b].replace('uni', '')
                    key = eval(r'u"u' + str(key) + '"').lower()
                    result_dict[key] = font_dict[a]
        return result_dict
    
    def comp(L1, L2):
        if len(L1) != len(L2):
            return 0
        for i in range(len(L2)):
            if L1[i] == L2[i]:
                pass
            else:
                return 0
        return 1
    
    if __name__ == '__main__':
        url = "https://su.58.com/qztech/"
        get_data(url)

    看一下成果

    参考链接:

    https://cuiqingcai.com/6431.html

  • 相关阅读:
    2019-2020-1 20199327《Linux内核原理与分析》第九周作业
    交替重复 批处理
    2019-2020-1 20199327《Linux内核原理与分析》第八周作业
    内核模块编译
    2019-2020-1 20199327《Linux内核原理与分析》第七周作业
    2019-2020-1 20199327《Linux内核原理与分析》第六周作业
    MenuOS扩展
    2019-2020-1 20199327《Linux内核原理与分析》第五周作业
    2019-2020-1 20199327《Linux内核原理与分析》第四周作业
    2019-2020-1 20199327《Linux内核原理与分析》第三周作业
  • 原文地址:https://www.cnblogs.com/qieyu/p/10456963.html
Copyright © 2011-2022 走看看