前两天,有个朋友让我帮他搞个爬虫,是58同城的。本以为很简单的事情,没想到,他们竟然用自己的一套字体。抓取出来的都是乱码图片就不放了,去58同城看看就知道。搞了大半天,查资料,找规律,还真给弄出来了。然后得意地给朋友看,谁知他来了一句,不是抓租房,是抓简历的!好吧。我重新搞一搞。不过还是先把这个记下来,以后也可以做个参考。
加密的就不说了,去58一看就知道是什么回事。直接入正题:
用到的工具:(都是一些很常用的库)
fake_useragent
fontTools
requests
re
base64
io
lxml
网站的难点在于字体的解析, 这个费了好半天,最后终于还是找到了规律。
这是网页源码中的字体
閏鑶驋龤
这是加载好的字体: 閏鑶驋龤
这是经过渲染的字体
顺手看了一下网页源代码,然后找到了左上角提示,我。。。。这也太明显了吧。代码前半部分都有提示,base64, ttf…
base64加密, ttf格式字体
顺着线索找到了与网页中相似的一行代码
好吧,都这样明显了就开始动手吧,
生成字体文件, 两个文件xml和woff,方便做对比(中间有些信息没有必要。我也给抓下来了)
def get_font_info(self, html):
re_bds = self.re_bds
font_infos = re.findall(re_bds, html)[0]
# file_end = font_infos[0] # 字体文件的后缀
# charset = font_infos[1] # 文件编码 (貌似没什么用)
# jm_tool = font_infos[2] # 字体文件的加密方式 这里是base64
font_info = font_infos[3] # 可以生成字体文件的代码
data = base64.b64decode(font_info)
fonts = TTFont(io.BytesIO(data))
cmap=fonts.getBestCmap() # 字体的映射关系
fonts.saveXML('test/f.xml')
fonts.save('test/f.ttf')
return cmap
通过对比两个编号
多试几次,发现字体中的数字的规律 glyph000XX 对应数字为后两位减 1,比如 glyph00003对应的就是数字2,要是能生成自己的一套字典就OK了。可是要怎么生成呢,而且还不能固定生成,因为每次刷新, 编码都会变!
后来又一看0x9476
这不就是十六进制的数字嘛!不管其他的,先打印出来再说
for sec_str in cmap:
# 输入网页上显示字体与字体文件里对应关系
print(chr(sec_str), hex(sec_str), sec_str, cmap[sec_str])
果然不出所料:
这样一来,就好办了。自动生成字典
# 构建真实字体与网页源码字典
# 0x9476------> 鑶
def get_dict(cmap):
num_dic = {}
for sec_str in cmap:
s_key = '&#' + str(hex(sec_str))[1:] + ';'
# 规律: glyph00003 对应数字为后两位减 1
num_dic[s_key] = int(cmap[sec_str][-2:]) - 1
return num_dic
然后对获取到的网页进行替换
# 加密的字体进行替换
def change_num(str_html, num_dic):
for k, v in num_dic.items():
if k in str_html:
str_html = str_html.replace(k, str(v))
return str_html
大功告成!接下来就是普通的抓虫代码了!
写在最后:到目前为止简历信息的问题还没有解决。并且测试的时候,只测试了一页的内容。58应该还有其他的反爬虫措施。等以后有时间再继续!