python之footTools庫操作ttf字體,實現(xiàn)字體混淆與網(wǎng)頁web反爬蟲功能

一、引入

1.1、在一些網(wǎng)頁中,往往會有這樣的需求:防止用戶通過爬蟲手段快速批量獲取需要顯示但是又極為敏感的數(shù)據(jù)。

  • 比如:電商網(wǎng)站的價格、文獻資料、具有版權性質的圖庫文庫等。
  • 這時候往往可以通過 字體混淆 技術來達到一定的防范效果。
  • 例如:(圖片來自網(wǎng)絡)


    0adb84d965924fa18d2684bd14266283.png

1.2、原理解釋

  • 首先,字體混淆僅僅是增加了爬蟲困難,通過恢復字體等手段依然能獲得原始文本。
  • 字體文件內部存在這一種字符字形的對應關系,或者說就是字符unicode字形編碼的對應關系。我們只要把這個對應關系偏移或打亂,使用打亂后的字符+打亂后的字體文件,即可在web端不影響顯示的情況下達到混淆效果。

二、實現(xiàn)代碼

2.1、本代碼實現(xiàn)了如下功能:

  • 根據(jù)需要截取字體文件

  • 修改字符字形的關系映射

  • 保存新字體文件和輸出混淆后的字符串

  • python實現(xiàn):

    #####
    # Created by 王圣滔[賢圣]
    # Email: w778899wst@live.cn
    #####
    
    from fontTools.ttLib import TTFont
    from fontTools import subset
    
    """
    根據(jù)字符需要裁剪
    字體文件內字符-字形映射關系的修改
    輸出編輯過的字體文件+偏移后的文本
    """
    
    # 需要混淆的字符串
    myStr = "今天你真好看"
    
    # 加載字體文件:
    font = TTFont('./ttf/Alibaba-PuHuiTi-Light.ttf')
    
    # 截取字符串內字符使用到的字體(為了減小體積)
    subsetter = subset.Subsetter()
    subsetter.populate(text=myStr)
    subsetter.subset(font)
    
    # 獲得字符、字形映射
    cmap = font.getBestCmap()
    print("--------------原始映射關系-----------------")
    print(cmap)
    
    # 修改映射關系,這里從文本的第一個字符開始,依次替換為A、B、C、D及往后字符的unicode
    # 實際項目中可以根據(jù)自己的喜好去編寫混淆算法,這里僅做基本演示
    baseCode = 0x0041  # 初始code
    newStr = ""  # 新的偏移后文本
    oldAndNewKeyMap = {} #存放修改前、修改后的key對應關系,以便在發(fā)生字符重復時找到原先的key再修改新key
    for st in myStr:
        code = ord(st)  # 原始字符的unicode
        try:
            cmap[baseCode] = cmap.pop(code)  # 刪除原有映射,并以新key存儲映射
            newStr += chr(baseCode)  # 連接新文本
            oldAndNewKeyMap[code] = baseCode  # 錄入新舊code
            baseCode = baseCode + 0x0001
        except Exception as err:
            print("發(fā)生異常:Unicode %s 字符已做過偏移映射" % err)
            newCode = oldAndNewKeyMap[code]
            newStr += chr(newCode)  # 連接新文本
            continue
    print("--------------修改后的映射關系-------------")
    print(cmap)
    print("--------------修改后偏移文本-------------")
    print(newStr)
    
    # 保存新ttf文件:
    font.save('./output/Alibaba-PuHuiTi-Light-cut-change-test.ttf')
    
    # 保存woff等其他文件
    # options = subset.Options()
    # options.flavor = 'woff'
    # subset.save_font(font, './output/Alibaba-PuHuiTi-Light-min.woff', options)
    
  • web端操作:

        <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            <!--這里要定義混淆后的字體文件樣式-->
            @font-face {
                font-family: "myFont";
                src: url("./output/Alibaba-PuHuiTi-Light-cut-change-test.ttf") format("truetype");
            }
        </style>
    </head>
    <body>
    <h3>原文本</h3>
    <p>今天你真好看</p>
    <h3>混淆文本</h3>
    <p>ABCDEF</p>
    <h3>混淆文本復原</h3>
    <!--這里設置了該字體的樣式才能生效-->
    <p style="font-family: myFont">ABCDE</p>
    </body>
    </html>
    

2.2、上效果

  • 控制臺輸出:


    575b0dcd6cf24b10b64b47743f0caf42.png
  • 網(wǎng)頁內容:


    8adca6189fe3494e85e42406bd73baf2.png

三、fontTools庫的使用

3.1、開始之前,建議先了解ttf字體內部結構

from fontTools.ttLib.ttFont import TTFont
from fontTools import subset

3.1、使用

  • 打開字體文件

    font = TTFont('TestFont.ttf')
    
  • 轉存xml文件(方便查看內部結構使用)

    font.saveXML('TestFont.xml')
    
  • 字體拆分截取

    # 截取包含“你好嘿!”幾個字符的字體內容
    subsetter = subset.Subsetter()
    subsetter.populate(text="你好嘿嘿!")
    subsetter.subset(font)
    
  • 保存與其他格式保存

    # 保存新ttf文件:
    font.save('TestFont-new.ttf')
    # 保存woff等其他文件
    options = subset.Options()
    options.flavor = 'woff'
    subset.save_font(font, 'TestFont.woff', options)
    
  • 獲取所有節(jié)點名

    print(font.keys())
    
    b3deab7d41364c3baa62fb013b3bb0af.png
  • 獲取cmap節(jié)點unicode與name值映射(字符和字形映射)

    print(font.getBestCmap())
    
    5e8f8f9a90584e768925b24f47875162.png
    4b2f3d8118ab48adb21f506b337d468a.png
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容