字体反爬-动态字库
程序员文章站
2022-03-02 08:13:23
这次是动态字体库的字体反爬 猫眼电影榜单国内票房榜,地址:https://maoyan.com/board/1 可以看出又是字体反爬,需要获得字体文件,定位字体文件的url,在页面或css里搜@font-face或font-famil 在network选font标签刷新页面几次发现每次用的字体都不一 ......
这次是动态字体库的字体反爬
猫眼电影榜单国内票房榜,地址:
可以看出又是字体反爬,需要获得字体文件,定位字体文件的url,在页面或css里搜@font-face或font-famil
在network选font标签刷新页面几次发现每次用的字体都不一,加密用的字体库是动态的,手动建立关系表然后全局替换的方法不管用了。
解决方案
建立字符和动态字体库unicode的联系
原理
首先要了解字体文件内部有很多表,上篇用到记录unicode索引和字形关系的cmap表就在里面,
这此要用到glyf表,这个表里记录了具体的字形数据,表里只记录了字形数据,没有表头索引。
有专门的表loca按顺序记录glyf里每个字形的位置,在使用字体时通过loca表来找到具体字形。
所以反爬不是改变字形的话可以利用字形数据来找到自定义字体unicode与真实字符的联系。
这部分详细资料见 中的glyf表。
找关联的思路如图:
1.下载一个网站字体做为基准,建立基准字体unicode和真实字符关系。
2.在页面刷新网页字体库变化,重新下载字体,记为网站字体2,通过比较网站字体1和网站字体2的字形找到unicode和新unicode联系。
3.再通过相同的unicode来建立真实字符和变化字体库unicode的联系,最后全局将新unicode替换成真实字符。
代码
headers={"user-agent":"mozilla/5.0 (windows nt 10.0; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/73.0.3683.86 safari/537.36"} r=requests.get("https://maoyan.com/board/1",headers=headers) font1_url="http:"+re.findall("url\(\'(\/\/.*?woff)\'\)",r.text,re.m)[0]
#创建font目录保存基准字体 if not os.path.exists("font"): font1=requests.get(font1_url,headers=headers) os.mkdir("font") with open("./font/base.woff","wb")as f: f.write(font1.content)
下载一次基准字体并保存到font目录
base_font = ttfont('./font/base.woff') base_dict=[] for i in range(len(basefont.getglyphorder()[2:])): print(f"对应的数字{i+1}:") w=input() base_dict.append({"code":basefont.getglyphorder()[2:][i],"num":w})
建立基准字体的unicode和真实字符的关系,看字体可以用fontcreator
上面的代码只需要执行一次,已经跳过前两项直接按顺序输入数字即可
new_font_url="http:"+re.findall("url\(\'(\/\/.*?woff)\'\)",r.text,re.m)[0] font=requests.get(new_font_url,headers=headers) with open("new_font.woff","wb")as f: f.write(font.content) new_font = ttfont('new_font.woff') new_font_code_list=new_font.getglyphorder()[2:]
页面改变后的字体下载,获取unicode列表
replace_dic=[] for i in range(10): news = new_font['glyf'][new_font_code_list[i]] for j in range(10): bases = base_font['glyf'][base_dict[j]["code"]] if news == bases: unicode=new_font_code_list[i].lower().replace("uni","&#x")+";" num= base_dict[j]["num"] replace_dic.append({"code":unicode,"num":num})
建立新unicode和字符的关系
org_data=r.text for i in range(len(replace_dic)): new_data=new_data.replace(replace_dic[i]["code"],replace_dic[i]["num"])
全局替换unicode成字符
tree=etree.html(org_data) dds=tree.xpath('//dl[@class="board-wrapper"]/dd') info=[] for dd in dds: title=dd.xpath('.//p[@class="name"]/a/@title')[0] star=dd.xpath('.//p[@class="star"]/text()')[0].replace("主演:","") time=dd.xpath('.//p[@class="releasetime"]/text()')[0].replace("上映时间:","") realticket=dd.xpath('.//p[@class="realtime"]//text()')[1]+dd.xpath('.//p[@class="realtime"]//text()')[2].strip() totalticket=dd.xpath('.//p[@class="total-boxoffice"]//text()')[1]+dd.xpath('.//p[@class="total-boxoffice"]//text()')[2].strip() info.append({"标题":title,"主演":star,"上映时间":time,"实时票房":realticket,"总票房":totalticket})
抓一些信息,下面是结果
json保存成csv
import csv csv_file = open("1325.csv", 'w', newline='') keys = [] writer = csv.writer(csv_file) keys = info[1].keys() writer.writerow(keys) for dic in info: for key in keys: if key not in dic: dic[key ] = '' writer.writerow(dic.values()) csv_file.close()
结果
引入的库
以上是全部代码
上一篇: Rails.cache
下一篇: Lua学习笔记之运算符和表达式