获取某宝价格 字体反爬

背景

环境

  • Windows
  • python
  • selenium

目标

  • 打开店铺连接获取商品信息

问题

解决过程

什么是字体反爬

字体反爬简介

​ 在 CSS3 之前,Web 开发者必须使用用户计算机上已有的字体。目前的技术开发者可以使用@font-face为网页指定字体,开发者可将心仪的字体文件放在 Web 服务器上,并在CSS 样式中使用它。用户使用浏览器访问 Web应用时,对应的字体会被浏览器下载到用户的计算机上。

注:使用自动化selenium也无法获取正常的数据

  • 在页面源代码中搜索font-face关键字,可以发现字体文件在网页源代码中
  • 可以在网络抓包里面进行筛选,可以发现这里面有对应的字体文件加载地址,由后端返回

如何解决

确定反爬方式

字体反爬

寻找字体文件

即网站定义了字体文件,然后进行相应的查找替换,在前端看起来,是没有任何差异的。其实从审查元素的也是可以看到的:

在源代码中搜索 AlibabaSans102CustomFont

 @font-face {
            font-family: 'AlibabaSans102CustomFont';
            src: url('https://webfontcdn.taobao.com/webfont/1f489de8-e9bc-4d96-93de-f475686639ab7375358770356543788.woff') format("woff");
        }
下载字体文件
​
字体文件地址:https://webfontcdn.taobao.com/webfont/1f489de8-e9bc-4d96-93de-f475686639ab7375358770356543788.woff

在浏览器中可以直接下载字体文件.woff
​
研究字体文件

因为我们要对字体进行研究,所以必须将它打开

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

字形:1 

字形编码:one

字体解析工具

 工具安装

pip install fontTools  # 使用这个包处理字体文件
 字体读取
from fontTools.ttLib import TTFont

# 加载字体文件:
font = TTFont('1f489de8-e9bc-4d96-93de-f475686639ab7375358770356543788 (2).woff')
# 转为xml文件:
font.saveXML('file.xml')

file.xml 预览

  <tableVersion version="0"/>
    <cmap_format_4 platformID="3" platEncID="1" language="0">
      <map code="0x0" name="NULL"/><!-- ???? -->
      <map code="0xd" name="nonmarkingreturn"/><!-- ???? -->
      <map code="0x20" name="space"/><!-- SPACE -->
      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
      <map code="0x25" name="percent"/><!-- PERCENT SIGN -->
      <map code="0x2b" name="plus"/><!-- PLUS SIGN -->
      <map code="0x2c" name="comma"/><!-- COMMA -->
      <map code="0x2d" name="hyphen"/><!-- HYPHEN-MINUS -->
      <map code="0x2e" name="period"/><!-- FULL STOP -->
      <map code="0x30" name="zero"/><!-- DIGIT ZERO -->
      <map code="0x31" name="one"/><!-- DIGIT ONE -->
      <map code="0x32" name="two"/><!-- DIGIT TWO -->
      <map code="0x33" name="three"/><!-- DIGIT THREE -->
      <map code="0x34" name="four"/><!-- DIGIT FOUR -->
      <map code="0x35" name="five"/><!-- DIGIT FIVE -->
      <map code="0x36" name="six"/><!-- DIGIT SIX -->
      <map code="0x37" name="seven"/><!-- DIGIT SEVEN -->
      <map code="0x38" name="eight"/><!-- DIGIT EIGHT -->
      <map code="0x39" name="nine"/><!-- DIGIT NINE -->
      <map code="0x3a" name="colon"/><!-- COLON -->
      <map code="0x3d" name="equal"/>

在xml文件中可以看到       <map code="0x31" name="one"/><!-- DIGIT ONE -->

分析

自此已知的条件:

  1. 页面展示的价格:价格 42.14
  2. HTML文件中展示的价格 : 嶪䭛䮰昵片
  3. 字体文件中:字形‘1’对应的字形编码是‘one’
  4. 字体文件转换的xml文件中:name="one" code="0x31"

依据条件可以做出的分析:

  1. 数字:1 对应 汉字:昵 ;字形‘1’对应code="0x31"
  2. 一个数字对应一个汉族
  3. 字形 字形编码 和 code 存在某种对应关系

尝试的可能的方法:

  1. 既然是汉族数字一一对应,例如数字1,对应的汉族找出来,形成字典即可。十个数字加一个小数点
    结果:多个汉族对应 同一个 数字。无法获取到全部数字对应的汉字,就无法整理全
  2. selenium截图,对价格就行截图,再进行OCR
  3. 找出对应关系
解决方案

在xml文件中直接查询《name="one"》有2004个,说明有2004个编码对应数字1

一直没有头绪,就直接百度《0x31是什么字符》,发现:0x31是字符'1'的ASCII编码

百度《汉族 昵 对应的编码》发现:“昵”的Unicode编码(通常是UTF-16编码格式):U+662D

在xml文件中搜索《662D》发现:<map code="0x662d" name="one"/>

终于发现了:汉族“昵”的编码是“U+662D”,编码“U+662D”对应name="one"name="one"就对字形“1”

只需获取汉字对应的Unicode编码,就可以在xml文件中找到对应的数字了。

代码

import unicodedata
from fontTools.ttLib import TTFont

'''
实际价格:42.14
显示汉字:嶪䭛䮰昵片
'''


def get_unicode_code_point(characters):
    '''
    返回十六进制Unicode编码
    '''
    return ''.join(f'U+{ord(c):04X}' for c in characters)


# print(get_unicode_code_point('洛'))


def get_unicode_code(characters):
    '''
    返回十进制Unicode编码
    '''
    return [ord(c) for c in characters]


# print(get_unicode_code('嶪䭛䮰昵片'))


# 加载字体文件:
font = TTFont('1f489de8-e9bc-4d96-93de-f475686639ab7375358770356543788 (2).woff')
# 转为xml文件:
# font.saveXML('file.xml')
# 获取字体映射关系
font_cmap = font['cmap'].getBestCmap()

base_dict = {
    'period': '.',
    'zero': '0',
    'one': '1',
    'two': '2',
    'three': '3',
    'four': '4',
    'five': '5',
    'six': '6',
    'seven': '7',
    'eight': '8',
    'nine': '9',

}

if __name__ == '__main__':
    price_str = ''
    price_str_s = '嶪䭛䮰昵片'
    unicode_codes = get_unicode_code(price_str_s)
    for unicode_code in unicode_codes:
        name = font_cmap[unicode_code]
        price_str += base_dict[name]

    print(price_str)

输出:42.14

总结

参考了众多网友写的文章,表示感谢

如果本文对您有帮助,请给我点赞吧

  • 31
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值