文章目录
-
- [1. 字体反爬机制概述](#1. 字体反爬机制概述)
- [2. 字体反爬原理分析](#2. 字体反爬原理分析)
-
- [2.1 字体反爬的基本原理](#2.1 字体反爬的基本原理)
- [2.2 常见字体反爬类型](#2.2 常见字体反爬类型)
- [3. 案例分析](#3. 案例分析)
- [4. 反反爬策略](#4. 反反爬策略)
- [5. 实战样例](#5. 实战样例)
-
- [5.1 案例1:使用Python和fontTools库破解字体反爬](#5.1 案例1:使用Python和fontTools库破解字体反爬)
- [5.2 案例2:新闻网站字体反爬处理](#5.2 案例2:新闻网站字体反爬处理)
- [6. 总结](#6. 总结)
1. 字体反爬机制概述
字体反爬是一种常见的反爬虫技术,通过自定义字体文件(如TTF、WOFF)对网页中的字符进行加密或替换,将页面上的文字使用特殊字体显示,而爬虫在解析时由于缺少相应的字体文件,导致无法正确识别文字内容。本文将深入分析字体反爬的机制,并提供实战样例,帮助读者理解和应对这一挑战。
2. 字体反爬原理分析
2.1 字体反爬的基本原理
字体反爬通常通过以下步骤实现:
自定义字体文件
:网站使用自定义的字体文件(如WOFF、TTF等),将页面上的文字映射到该字体文件中的特定字符。字符映射
:在CSS中,通过@font-face规则引入自定义字体,并将页面文字应用该字体。混淆显示
:实际页面上显示的文字可能是经过映射后的字符,而真实内容通过字体文件进行解码。
由于爬虫在抓取页面时,通常不会下载和应用自定义字体文件,导致解析出的文字内容为乱码或替代字符。
2.2 常见字体反爬类型
图标字体
:使用图标字体库(如Font Awesome)混淆文字。动态字体
:通过JavaScript动态加载字体文件,增加解析难度。字符替换
:将关键文字替换为相似的替代字符,需依赖字体文件解码。爬虫获取的是乱码或错误字符
3. 案例分析
假设有一个网页,其HTML结构如下:
html
复制
<div class="content">
<span class="char"></span>
<span class="char"></span>
<span class="char"></span>
<span class="char"></span>
</div>
在这个例子中,网页使用了自定义字体文件,字符、
等被映射到特定的字形。爬虫直接获取的文本内容是乱码,无法直接解析。
4. 反反爬策略
为了应对字体反爬,除了上述方法外,还可以采取以下策略:
自动下载与解析字体
:编写脚本自动检测并下载页面使用的字体文件,使用工具(如fontTools)解析字符映射关系。模拟浏览器行为
:使用无头浏览器(如Selenium、Playwright)模拟真实用户访问,确保获取渲染后的正确内容。定期更新解析规则
:网站可能会更换字体文件或映射规则,需定期检查和更新爬虫的解析逻辑。结合多种数据源
:通过多个渠道获取数据,交叉验证抓取结果的准确性。
5. 实战样例
以下是一个使用Python和fontTools库破解字体反爬的样例:
5.1 案例1:使用Python和fontTools库破解字体反爬
bash
pip install requests fonttools
代码实现
python
import requests
from fontTools.ttLib import TTFont
from bs4 import BeautifulSoup
# 目标网页URL
url = 'https://example.com'
# 获取网页内容
response = requests.get(url)
html_content = response.text
# 解析HTML
soup = BeautifulSoup(html_content, 'html.parser')
# 提取字体文件URL(假设字体文件URL在CSS中)
css_url = 'https://example.com/styles.css'
css_response = requests.get(css_url)
css_content = css_response.text
# 从CSS中提取字体文件URL(假设字体文件URL格式为'url(/path/to/font.woff)')
import re
font_url = re.search(r'url\((.*?\.woff)\)', css_content).group(1)
font_url = 'https://example.com' + font_url if font_url.startswith('/') else font_url
# 下载字体文件
font_response = requests.get(font_url)
with open('font.woff', 'wb') as f:
f.write(font_response.content)
# 解析字体文件
font = TTFont('font.woff')
cmap = font.getBestCmap()
# 创建字符映射表
char_map = {}
for code, name in cmap.items():
char_map[chr(code)] = name
# 示例:假设字形名称与真实字符的映射关系如下
glyph_to_char = {
'glyph00001': 'A',
'glyph00002': 'B',
'glyph00003': 'C',
'glyph00004': 'D',
}
# 替换网页中的乱码字符
content_div = soup.find('div', class_='content')
for char_span in content_div.find_all('span', class_='char'):
char_code = char_span.text.strip()
glyph_name = char_map.get(char_code, '')
real_char = glyph_to_char.get(glyph_name, '?')
char_span.string.replace_with(real_char)
# 输出解析后的文本内容
print(content_div.get_text())
5.2 案例2:新闻网站字体反爬处理
1、案例背景 :
假设有一个新闻网站,为了防止数据被爬取,采用了字体反爬技术。页面上的新闻标题和内容使用了自定义字体,直接抓取后显示为乱码。我们的目标是正确抓取并解析这些文字内容。
2、分析网页结构
使用浏览器的开发者工具分析页面,找到使用自定义字体的元素,并确定字体文件的URL。例如,假设字体文件通过@font-face规则引入,URL为https://example.com/fonts/custom.woff。
3、下载字体文件
使用requests库下载字体文件:
python
import requests
font_url = 'https://example.com/fonts/custom.woff'
font_response = requests.get(font_url)
with open('custom.woff', 'wb') as f:
f.write(font_response.content)
4、解析字体文件
使用fontTools解析字体文件,获取字符映射关系:
python
from fontTools.ttLib import TTFont
font = TTFont('custom.woff')
cmap = font.getBestCmap()
# 将映射关系保存为字典
char_map = {hex(k): chr(v) for k, v in cmap.items()}
print(char_map)
5、抓取并解析页面内容
使用requests抓取页面HTML,使用lxml解析,并根据字符映射关系替换文字:
python
from lxml import etree
# 抓取页面
page_url = 'https://example.com/news'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
}
response = requests.get(page_url, headers=headers)
html = response.text
# 解析HTML
tree = etree.HTML(html)
titles = tree.xpath('//h2[@class="news-title"]/text()')
# 替换文字
decoded_titles = []
for title in titles:
decoded = ''.join([char_map.get(hex(ord(c))[2:], c) for c in title])
decoded_titles.append(decoded)
for idx, title in enumerate(decoded_titles):
print(f'新闻标题 {idx+1}: {title}')
6、处理动态加载字体
有些网站通过JavaScript动态加载字体文件,可能需要使用Selenium等工具模拟浏览器行为,获取渲染后的页面内容和字体文件URL。
python
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
import time
# 配置Chrome选项
chrome_options = Options()
chrome_options.add_argument("--headless")
service = Service('/path/to/chromedriver')
driver = webdriver.Chrome(service=service, options=chrome_options)
# 抓取页面
driver.get(page_url)
time.sleep(3) # 等待字体加载
# 获取页面源代码
html = driver.page_source
driver.quit()
# 后续解析步骤同上
6. 总结
字体反爬技术通过自定义字体文件对字符进行加密或替换,增加了爬虫解析的难度。通过下载并解析字体文件,建立字符映射关系,可以有效破解这种反爬机制。在实际应用中,可能需要结合动态加载、CSS偏移等其他反爬技术进行综合处理。