字体反爬案例解析:大众点评

字体反爬简介

       什么是字体反爬?
       就是我们在网页上看到的内容和我们直接解析出来的内容不一样,以大众点评网站为例:
       我们在网页上看到的是这样:
在这里插入图片描述
       这些数字是正常显示的,但是我们点击F12,查看HTML时,却是这样的:
在这里插入图片描述
       用requests发送请求,获取到网页信息,发现是这样的:
在这里插入图片描述
       也就是说,这个网页中,有些数字和字是经过了加密处理,像原来那样直接解析的话,得到的是每个字的‘密码’,而不是我们想要的汉字或者数字。
       字体反爬大致可以分为两种,一种是不同字体文件中,每个字的Unicode编码不一样,但字形完全一样(即每个字的contour的坐标完全一样),比如大众点评;一种是Unicode编码不一样,并且在不同字体文件中,字形也不完全一样,只是非常相似,比如美团。
       对于第一种,我们的处理方式如下:
       设置基准字典,以contour为key,以该contour描绘出来的字作为value;当遇到需要解析的字时,我们通过这个字的‘密码’先找到这个字的Unicode,然后用Unicode来找到这个字的contour,最后用这个contour去基准字典中找到对应的汉字或数字。
       对于第二种,我们的处理方式如下:
       设置基准字典,以contour为key,以该contour描绘出来的字作为value;当遇到需要解析的字时,我们通过这个字的Unicode来找到这个字的contour;然后对比基准字典中的所有contour,看哪个与待解析字的contour最接近(比如可以使用K近邻的方法),然后把最接近的那个contour的value赋给待解析的字。
       本文主要介绍第一种。

import requests
import re
from lxml import etree
import fontTools
from  fontTools.ttLib import TTFont 
import hashlib
import pandas as pd

发送请求,获取网页源码

url ='http://www.dianping.com/dayi/ch10'
headers = {
   'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Mobile Safari/537.36'}
html = requests.get(url,headers=headers)

提取字体信息,并将字体文件下载到本地

一个网页中,可能使用了多种字体文件来对页面中的某些文字进行加密,这些字体文件信息保存在一个css文件中,因此我们首先要拿到该css文件的链接,然后在该链接的网页中查找字体信息

#拿到含有字体的css url
css_url = re.findall('href="(.*s3plus.*)"',html.text)

#拿到字体的url
woff_html = requests.get('http:'+css_url[0],headers=headers)
woff_url = ['http:'+url for url in re.findall(",url\(\"(.*?)\"\);}",woff_html.text)]

#拿到字体的名字
woff_name = re.findall('font-family: "PingFangSC-Regular-(.*?)";',woff_html.text)

#将字体名字和url一一对应起来
woff_name_url = {
   }
for i in range(len(woff_name)):
    if woff_name[i] !=  'reviewTag': #这样处理的原因是本例中用不到reviewTag这个字体文件,并且它是重复的,所以去掉它。
        woff_name_url[woff_name[i]] = woff_url[i]
woff_name_url
{'shopNum': 'http://s3plus.meituan.net/v1/mss_73a511b8f91f43d0bdae92584ea6330b/font/3afae22b.woff',
 'tagName': 'http://s3plus.meituan.net/v1/mss_73a511b8f91f43d0bdae92584ea6330b/font/276defdb.woff',
 'address': 'http://s3plus.meituan.net/v1/mss_73a511b8f91f43d0bdae92584ea6330b/font/33f1a1f2.woff'}

可以看到,一共有3个字体文件,名字分别是shopNum、tagName、address,目前我们都拿到了它们对应的链接。

#下载字体文件到本地
for key in woff_name_url:
    name = key
    url = woff_name_url[key]
    response = requests.get(url,headers=headers)
    with open('%s.woff'%name,'wb') as f:
        f.write(response.content)
        f.close()

fonts = {
   }
for key in woff_name_url:
    file_name = '{}.woff'.format(key)
    fonts[key] = TTFont(file_name)
fonts
{'shopNum': <fontTools.ttLib.ttFont.TTFont at 0x2609b2bdf48>,
 'tagName': <fontTools.ttLib.ttFont.TTFont at 0x2609b2bd4c8>,
 'address': <fontTools.ttLib.ttFont.TTFont at 0x2609b2c1bc8>}

我们使用在线的字体解析工具看看这些字体文件:
在这里插入图片描述
可以看到,每个字都有对应的Unicode编码(红色圈起来的那个)

建立基准字典

# basefont_char是基准字典中所含有的全部字符,是有一定顺序的(按照font.getGlyphOrder()的顺序排的)
# 一共有601个字符,不知道是哪位大神按顺序整理的,十分感谢!
# 这个顺序和上图的顺序是一样的
basefont_char = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '店', '中', '美', '家', '馆', '小', '车', '大', '市', '公', '酒',
                     '行', '国', '品', '发', '电', '金', '心', '业', '商', '司', '超', '生', '装', '园', '场', '食', '有', '新', '限', '天', '面',
                     '工', '服', '海', '华', '水', '房', '饰', '城', '乐', '汽', '香', '部', '利', '子', '老', '艺', '花', '专', '东', '肉', '菜',
                     '学', '福', '饭', '人', '百', '餐', '茶', '务', '通', '味', '所', '山', '区', '门', '药', '银', '农', '龙', '停', '尚', '安',
                     '广', '鑫', '一', '容', '动', '南', '具', '源', '兴', '鲜', '记', '时', '机', '烤', '文', '康', '信', 
  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值