爬虫「Python」:解决网络爬虫遇到的字体包.ttf识别问题

在写网络爬虫时,经常遇到页面显示正常的文字,在查看源码时出现空白或者乱码的情况,这就是运用字体包 .ttf 反爬机制,这里简单了解一下 .ttf 文件

目录

一、问题

二、TTF文件 

三、解决

(一)过程分析

(二)代码


一、问题

这里我已实际爬虫过程中遇到的情况为例,首先页面显示内容如下图1

图1:网页与控制台显示

这里即使我们尝试爬取网页内容,结果仍然是响应内容显示异常,如图2

图2:爬取得到的内容

这就是 .ttf 在这里起到的反爬作用

二、TTF文件 

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

那么 .ttf 是怎么在网页显示中起作用的呢?方法如下:

  • 首先在 <style> 标签中添加:
@font-face {
    font-family: "myfont";
    src: url('.ttf文件url');
}
  • 然后在需要显示的地方添加:
<span style="font-family:myfont"></span>

这里 是需要显示字的映射编码

这里推荐一个“百度字体编辑器”:http://fontstore.baidu.com/static/editor/index.html,可在线查看 .ttf 文件,效果如下图3

图3:百度字体编辑器

所以我们只需要将“字”与“编码”匹配即可替换文本中的符号

三、解决

(一)过程分析

给出需要解决的文档:

【最满意】驾驶非常舒服,做工饰非常棒,指导价22.86赶换代非常合适,7.4折,赠送全车龙膜,行车记录仪,前热,够用,双11看车,交定金,等20天超难熬,12月初车到,始贴装饰,等到1月才去牌子,切顺利,车能非常,换挡快,速快,饰简单又失去科技感,该功能全部都,20款,国、钥匙进入,钥匙,耳折叠,耳热,定速巡航,换挡拨片,太牛简直,这个车而舒服,够用【最不满意】前期速稳,慢点,其他都,钥匙点老气,轮胎韩泰米【为什么选择这款车】给媳妇买,优惠,奥迪做工,行驶稳定【空间】挺宽,够用,前舒服轿跑感觉,运座椅,布,但舒服,热,老快【动力】够用够用,脚就奔起,提速老快?还稳,几秒就100,感觉老给力【操控】舒服,稳定,尤其转弯,坑,老舒服,滤相细腻【油耗】200块钱95,半个月,班,够用,还跑两次新区,可以可以【舒适性】没毛病,前后都,舒服,劲,尤其座椅,各种方向调节,舒服,我喜欢半躺,冲劲,累【外观】帅,错,经典,18寸轮,黑顶,S3进气【内饰】看,连接方便,出风口红色漂亮,屏幕也【性价比】合适,同价位我知道,该哪款车可以这个配置,就也没奥迪驾驶感受,折扣肯定够用,配置绝对可以,

首先我们需要下载与该文档对应的 .ttf 文件,记住,大多数的网站每次页面的 .ttf不同的

1. .txt 文件. ttf 文件放到一个文件夹下:

 2. 通过如下代码解析字库文件:

# 解析字体库
font = TTFont('.ttf文件路径')

# 读取字体的映射关系
uni_list = font['cmap'].tables[0].ttFont.getGlyphOrder()

# 转换格式
utf_list = [eval(r"u'\u" + x[3:] + "'") for x in uni_list[1:]]

通过执行,我们可以获取字体的映射关系

['\uedec', '\ued38', '\uec85', '\uecd7', '\uec23', '\uec75', '\uedb6', '\ued02', '\ued54', '\ueca1', '\uede1', '\uec3f', '\ued80', '\uedd1', '\ued1e', '\uec6b', '\uecbc', '\uedfd', '\ued4a', '\ued9b', '\uece8', '\ued3a', '\uec86', '\uedc7', '\uec25', '\ued65', '\uecb2', '\ued04', '\uec50', '\ueca2', '\uede3', '\ued30', '\ued81', '\uecce', '\uec1b', '\uec6c', '\uedad', '\uedff', '\ued4b', '\uec98', '\uecea', '\uec36', '\ued77', '\uedc9', '\ued15', '\ued67', '\uecb4', '\uedf4', '\uec52', '\ued93', '\uecdf', '\ued31', '\uec7e', '\uecd0', '\uec1c', '\ued5d', '\uedaf', '\uecfb', '\uec48', '\uec9a', '\uedda', '\uec38', '\ued79', '\uecc5', '\ued17', '\uec64', '\ueda4', '\uedf6', '\ued43', '\ued94', '\uece1', '\uec2e', '\uec7f', '\uedc0', '\ued0d', '\ued5e', '\uecab', '\uecfd', '\uec49', '\ued8a', '\ueddc', '\ued28', '\uecc7', '\uee07', '\uec65', '\ueda6', '\uecf2', '\ued44', '\uec91', '\uec2f']

3. 借助百度字体编辑器,我们可以将上述字符匹配到我们熟悉的文字(需要手动匹配,对于较多的爬虫量,确实有些复杂,读者可以考虑将图片发送到百度图像识别接口来获取对应文字),结果如下:

# 被替换的字体的列表
word_list = [u'着', u'机', u'好', u'九', u'左', u'路', u'远', u'上', u'动', u'门',
                 u'副', u'档', u'真', u'了', u'小', u'短', u'实', u'盘', u'大', u'坏', u'空',
                 u'右', u'五', u'油', u'软', u'是', u'二', u'外', u'十', u'得', u'泥', u'地',
                 u'呢', u'音', u'控', u'保', u'手', u'光', u'启', u'四', u'养', u'七', u'不',
                 u'冷', u'味', u'的', u'矮', u'一', u'只', u'低', u'孩', u'有', u'来', u'和',
                 u'高', u'灯', u'自', u'耗', u'开', u'身', u'多', u'内', u'三', u'下', u'量',
                 u'硬', u'长', u'雨', u'八', u'排', u'皮', u'很', u'过', u'更', u'响', u'少',
                 u'坐', u'当', u'里', u'比', u'加', u'六', u'近', u'无', u'性', u'中', u'问',
                 u'级', u'公', u'电']

4. 然后执行替换,即可:

# 遍历需要被替换的字符
for i in range(len(utf_list)):
    text = text.replace(utf_list[i], word_list[i])

效果如下:

【最满意】驾驶非常舒服,做工内饰非常棒,指导价22.86赶上小换代非常合适,7.4折,赠送全车龙膜,行车记录仪,前排加热,够用了,双11看车,交了定金,等了20天超级难熬,12月初车到,开始贴装饰,等到了1月才去上牌子,一切顺利,车的性能非常好,换挡快,加速快,内饰简单又不失去科技感,该有的功能全部都有,20款,国六、无钥匙进入,无钥匙启动,电耳折叠,电耳加热,定速巡航,换挡拨片,太牛了简直,这个车小而舒服,够用【最不满意】前期加速很稳,慢一点,其他都好,钥匙有点老气,轮胎韩泰不是米【为什么选择这款车】给媳妇买的,优惠大,奥迪做工好,行驶稳定【空间】挺宽的,坐着够用,前排很舒服有轿跑的感觉,运动座椅,布的,但是很舒服,电加热,老快了【动力】够用够用,一脚就奔起,提速老快了?还稳当,几秒就上100,感觉老给力了【操控】舒服,稳定,尤其转弯,过坑,老舒服了,过滤的相当细腻【油耗】200块钱95油,开了半个月,上下班,够用不,还跑了两次新区,可以可以了【舒适性】没毛病,前排后排都坐了,舒服,得劲,尤其电动座椅,各种方向调节,真的舒服,我喜欢半躺开,小冲劲一上来,不累【外观】帅,真不错,经典,18寸大轮,黑顶,S3进气【内饰】好看,手机连接方便,出风口红色漂亮,小屏幕也好【性价比】合适,同价位我不知道,该有哪款车可以有这个多的配置,就是有也没有奥迪的驾驶感受,折扣肯定够用,配置绝对可以,

总体来说,整个过程相对而言不算太难,但是对于大批量的爬虫而言确有很多不足。 

(二)代码

这里直接给出全部代码:

from fontTools.ttLib import TTFont


def parse_ttf(download_path, mouth_id):
    # 解析字体库
    font = TTFont(download_path + mouth_id + '.ttf')

    # 读取字体的映射关系
    uni_list = font['cmap'].tables[0].ttFont.getGlyphOrder()

    # 转换格式
    utf_list = [eval(r"u'\u" + x[3:] + "'") for x in uni_list[1:]]

    return utf_list


def replace(utf_list, text):
    # 被替换的字体的列表
    word_list = [u'着', u'机', u'好', u'九', u'左', u'路', u'远', u'上', u'动', u'门',
                 u'副', u'档', u'真', u'了', u'小', u'短', u'实', u'盘', u'大', u'坏', u'空',
                 u'右', u'五', u'油', u'软', u'是', u'二', u'外', u'十', u'得', u'泥', u'地',
                 u'呢', u'音', u'控', u'保', u'手', u'光', u'启', u'四', u'养', u'七', u'不',
                 u'冷', u'味', u'的', u'矮', u'一', u'只', u'低', u'孩', u'有', u'来', u'和',
                 u'高', u'灯', u'自', u'耗', u'开', u'身', u'多', u'内', u'三', u'下', u'量',
                 u'硬', u'长', u'雨', u'八', u'排', u'皮', u'很', u'过', u'更', u'响', u'少',
                 u'坐', u'当', u'里', u'比', u'加', u'六', u'近', u'无', u'性', u'中', u'问',
                 u'级', u'公', u'电']

    # 遍历需要被替换的字符
    for i in range(len(utf_list)):
        text = text.replace(utf_list[i], word_list[i])

    return text


def read_txt(download_path, mouth_id):
    with open(download_path + mouth_id + '.txt', 'r') as f:
        text = f.read()

    return text


if __name__ == '__main__':
    # id
    my_mouth_id = '01dzk6s7st68wk6d9p6wv00000'

    # 保存路径
    my_download_path = r'../../../data/mouth_data/'

    # 解析ttf文件
    my_utf_list = parse_ttf(my_download_path, my_mouth_id)

    # 读取原文档
    old_text = read_txt(my_download_path, my_mouth_id)

    # 替换为新文档
    new_text = replace(my_utf_list, old_text)

    print(new_text)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章