Python脚本爬取字体文件可以分为以下几个步骤:
- 获取字体文件的URL或者本地字体文件的路径
- 下载字体文件
- 解析字体文件中的映射表(map)信息
- 解析需要反爬的文本,并将对应的加密text和已知的明文text进行映射
- 替换被加密的文本为明文
- 可选:将替换后的文本保存为一个新的HTML页面或者PDF文件
下面是两个示例:
示例1:爬取腾讯视频网站的字体文件并解密被加密的文本
Step 1:打开网页并获取字体文件的URL
以腾讯视频网站为例,在Chrome浏览器中打开任意一个视频页面,右键单击页面中的非链接文本区域,选择“检查”,进入浏览器的开发者工具界面,切换到“Network”选项卡,在浏览器中选择任意一个视频,可以发现浏览器中发出了一个类似的请求:
https://puui.qpic.cn/vfont/yyxbDOwrrG1QcJLAdJ9gpw/241
这个请求中,包含了一个字体文件的URL路径,将该路径复制下来备用。
Step 2:下载字体文件并解析映射表
编写Python脚本,使用requests模块下载该字体文件,然后使用fontTools工具包解析出其中的映射表信息,如下所示:
from fontTools.ttLib import TTFont
import requests
font_url = "https://puui.qpic.cn/vfont/yyxbDOwrrG1QcJLAdJ9gpw/241"
# 首先下载字体文件到本地
response = requests.get(font_url)
with open("font.ttf", "wb") as f:
f.write(response.content)
# 使用fontTools解析字体文件并获取映射表信息
font = TTFont("font.ttf")
glyf_order = font.getGlyphOrder()[2:]
map_table = font.getBestCmap()
uni_list = []
for i in range(2, len(glyf_order)):
code_hex = glyf_order[i].replace("uni", "&#x") + ";"
uni_list.append(chr(map_table[code_hex]))
Step 3:解密加密文本并替换
在腾讯视频网站上,文本中被加密的文本通常以类似“”的形式出现,将该字符替换为对应的明文即可解密被加密文本。
# 需要处理的加密文本
enc_text = "Ste osn"
# 映射加密字符与明文
enc_list = ["", "", "", "", ""]
dec_list = ["S", "t", "e", "a", "n"]
text_map = str.maketrans("".join(enc_list), "".join(dec_list))
# 替换加密文本为明文
dec_text = enc_text.translate(text_map)
示例2:爬取安居客二手房信息,并将结果保存为PDF文件
Step 1:获取网页中的字体文件和加密文本占位符
以安居客网站的二手房页面为例,使用Chrome浏览器打开该页面,在开发者工具中可以发现页面中所有的字体文件都是以Data URI形式内嵌在网页的CSS代码中的。
同时,页面中有很多被加密的数字文本,这些文本都使用了相同的字体文件。在开发者工具的“Elements”选项卡中选中其中的一段加密文本占位符,可以看到类似以下的CSS代码:
.wl-2{
font-family: normal !important;
font-weight: 400;
font-style: normal;
color: #64b4ff;
position: relative;
font-size: 18px;
letter-spacing: 1px;
line-height: 30px;
display: inline-block;
}
.wl-2::after{
content: '5';
font-family:"Arial",serif !important;
font-weight: 400;
font-style: normal;
font-size: 42px;
position: absolute;
top: -16px;
left: 0px
}
.wl-2::before{
content:'秒';
font-family:"&sjb-22276cf7a8ad5beecc1d03f7f6c8a6c5",serif !important;
font-weight: 400;
font-style: normal;
font-size: 16px;
position: absolute;
right: -22px;
top: 0;
}
其中,加密的数字文本是通过伪元素::before和::after进行绝对布局,并调用不同的字体文件进行显示。
可以观察到,字体文件的路径在伪元素::before的内容内容中,而加密的数字则在伪元素::after的content属性中。
Step 2:解析伪元素中的字体文件,并将加密数字替换为明文
利用BeautifulSoup库解析网页,并使用CSS选择器找到加密数字所在的伪元素。
然后,通过正则表达式从伪元素的content属性中截取出加密数字,并从字体文件中解析出对应的明文。
最后,将原文本中的加密数字替换为解密后的明文即可完成解密。
import re
import requests
from bs4 import BeautifulSoup
from fontTools.ttLib import TTFont
from io import BytesIO
import pdfkit
def get_html(url):
# 获取HTML代码
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110"
}
response = requests.get(url, headers=headers)
html = response.text
return html
def decrypt_text(html):
# 解析字体文件
font_urls = []
bs = BeautifulSoup(html, "html.parser")
css_urls = bs.select("link[rel='stylesheet']")
for css in css_urls:
css_url = css["href"]
if "aosfont" in css_url:
font_urls.append(css_url)
font_map = {}
for font_url in font_urls:
response = requests.get(font_url)
font_data = BytesIO(response.content)
font = TTFont(font_data)
cmap = font.getBestCmap()
for k, v in cmap.items():
if v.startswith("uni"):
font_map[v] = chr(int(k))
# 解密数字
enc_nums = bs.select(".wl-2::after")
for enc_num in enc_nums:
enc_str = enc_num.text
for k, v in font_map.items():
enc_str = enc_str.replace(k, v)
enc_num.string = enc_str
return str(bs)
url = "https://sz.fang.anjuke.com/loupan/all/p1/"
html = get_html(url)
html = decrypt_text(html)
pdfkit.from_string(html, 'out.pdf')
运行上述脚本,会自动爬取安居客网站的第一页二手房信息并保存为PDF文件out.pdf。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:python脚本爬取字体文件的实现方法 - Python技术站