时隔这么多天,终于能有时间写抽空写篇博文了,正值今天1024程序员节,所以写了篇字体反扒博文给大家,希望大家看后能有所搜获!
本次反扒对象是 GlidedSky 网站的题目,说实话有点难度,但逻辑搞通的话其实还好,话不多说,开搞!!!
温馨提示:如果想练习需要先注册账号,而且题目不是一次性全部出来的,类似于闯关类型,如果是新用户需要先完成前面的题,才能解锁后面的题目,对于前面题目的讲解,我已经发表过博文了,想看的可以去看看。
在我爬取之前已经有110个人完成了这次题目。
总共有1000页,多页爬取参考如下,只需更改page参数即可
打开控制台查看网页,可见网页显示的是各种表示数字的文字或罗马数字或数字,二网页源码中则为汉字,这其实就是经过加密后的结果,咱们接着看。
往上看父标签,可见引入了style
搜索style中的font-family
这就是网页内嵌的Base64存储字体加密的文件,我们在python代码中使用TTFont获取并解析这段文件如下
进过博主实测后,我们需获取网页源码汉字并转为ACSII码获取对应cmap中map的code值,再将code值转为unicode编码(python获取时默认做了),去GlyphID获取对应的id值,id值-1即为真实数字
import requests
from fontTools.ttLib import TTFont
import base64
import json
import re
from bs4 import BeautifulSoup
#头信息
headers = {
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36",
#记得填上cookie,参考图1
"Cookie": ""
}
#最后保存总和的变量
sum = 0
#爬取
def download(response):
#引入全局变量sum
global sum
html_data = response.text
with open("字体文件2.html", mode="w") as f:
f.write(html_data)
#使用re模块正则匹配到当前网页中的base64字体文件,参考图2
font_base = re.findall("base64,(.*?)\) format", response.text)[0]
#使用base64库进行解码
result = base64.b64decode(font_base)
with open("字体文件2.ttf", mode="wb") as f:
f.write(result)
#使用TTFont打开字体文件并保存为xml文件以供阅读
font = TTFont('字体文件2.ttf')
font.saveXML("font2.xml")
# 获取字体映射关系,参考图2
font_map = font.getGlyphOrder()
font_cmap = font['cmap'].getBestCmap()
#将font-cmap中的key、value值对换位置
#zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
font_cmap = dict(zip(font_cmap.values(), font_cmap.keys()))
lists = []
font_map_new = []
for name in font_map:
if name == '.notdef':
continue
#根据name值获取对应的id值并添加到lists中,参考图2
#将获取到的数减一,再添加到lists列表中去,id值-1即为最终真实的数字
lists.append(font.getGlyphID(name) - 1)
for name in font_map:
#.notdef是我们不需要的,如果为.notdef直接使用continue进入下次循环
if name == '.notdef':
continue
font_map_new.append(name)
#GlyphOrder映射
dicts = dict(zip(font_map_new, lists))
# 更改映射
t1 = []
t2 = []
for key in dicts.keys():
#chr()主要用来表示ascii码对应的字符他的输入时数值
#t1保存font_cmap中对应key值即acsii码对应的数值
t1.append(chr(font_cmap[key]))
#t2保存dicts中key对应的value值
t2.append(dicts[key])
#最终映射结果,参考图3
t3 = dict(zip(t1,t2))
#数据爬取处理流程,参考图4
data = BeautifulSoup(html_data, "lxml")
numbers = data.find(class_="row").find_all(class_="col-md-1")
for num in numbers:
num = BeautifulSoup(str(num), "lxml")
num_temp = num.text.strip()
l = list(str(num_temp))
#遍历l,然后获取对应t3中的值并保存
for i in range(len(l)):
l[i] = str(t3.get(l[i]))
#拼接l中的值然后进行累加
sum = sum + int("".join(l))
#开始
if __name__ == '__main__':
#多页爬取
for i in range(1000):
print("正在爬取第"+str(i+1)+"页")
#拼接page值
url = "http://glidedsky.com/level/web/crawler-font-puzzle-2?page=" + str(i)
#发起请求
response = requests.get(url=url, headers=headers)
#设置编码
response.encoding = 'utf-8'
download(response)
#执行完后打印总和
print(sum)
博主会持续更新,有兴趣的小伙伴可以点赞、关注和收藏下哦,你们的支持就是我创作最大的动力!
几十个宝藏爬虫项目教程,你值得拥有!