1. 为什么需要爬取浏览器兼容性文档?
浏览器兼容性数据是前端开发者每天都要面对的核心参考资料。无论是MDN的Web API文档还是Can I Use的CSS特性支持表,这些数据直接影响着我们能否放心使用某个新特性。但手动查阅这些文档效率极低,特别是当我们需要批量检查多个API或CSS属性在不同浏览器版本中的支持情况时。
我在去年开发一个企业级前端框架时,就遇到了这样的痛点:需要为50多个Web API和30多个CSS属性生成兼容性报告。如果全靠人工操作,至少需要3天时间反复切换标签页、复制粘贴数据。而用Python爬虫自动化这个流程,最终只用了20分钟就完成了全部数据的采集和格式化。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与工具选型
2.1 基础环境配置
推荐使用Python 3.8+版本,这个版本在异步IO和类型提示方面已经非常成熟。关键库的安装命令如下:
bash复制pip install requests beautifulsoup4 pandas aiohttp
requests:用于同步HTTP请求(适合初学者)aiohttp:异步HTTP客户端(高性能场景)beautifulsoup4:HTML解析神器pandas:数据清洗和存储
注意:如果目标网站有反爬机制,建议额外安装
fake-useragent库来随机切换User-Agent:bash复制pip install fake-useragent
2.2 目标网站分析
以MDN和Can I Use为例,它们的页面结构各有特点:
-
MDN Web API文档:
- 典型URL:
https://developer.mozilla.org/en-US/docs/Web/API/WebSocket - 兼容性数据位于"Browser compatibility"章节
- 数据以表格形式呈现,包含浏览器图标和版本号
- 典型URL:
-
Can I Use CSS特性:
- 典型URL:
https://caniuse.com/css-grid - 支持率数据通过彩色条形图展示
- 提供详细的版本支持明细
- 典型URL:
3. 爬取MDN Web API兼容性数据
3.1 页面结构解析
先来看MDN的典型兼容性表格结构:
html复制<table class="bc-table">
<thead>
<tr>
<th>Feature</th>
<th>Chrome</th>
<th>Edge</th>
<!-- 其他浏览器... -->
</tr>
</thead>
<tbody>
<tr>
<td>WebSocket</td>
<td class="bc-supports-yes">4</td>
<td class="bc-supports-yes">12</td>
<!-- 其他浏览器数据... -->
</tr>
</tbody>
</table>
3.2 完整爬取代码实现
python复制import requests
from bs4 import BeautifulSoup
import pandas as pd
def scrape_mdn_compatibility(api_name):
url = f"https://developer.mozilla.org/en-US/docs/Web/API/{api_name}"
headers = {'User-Agent': 'Mozilla/5.0'}
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
table = soup.find('table', {'class': 'bc-table'})
if not table:
return None
data = []
browsers = [th.text.strip() for th in table.thead.find_all('th')[1:]]
for row in table.tbody.find_all('tr'):
feature = row.find('th').text.strip()
versions = [td.text.strip() for td in row.find_all('td')]
for browser, version in zip(browsers, versions):
data.append({
'API': api_name,
'Feature': feature,
'Browser': browser,
'Version': version
})
return pd.DataFrame(data)
except Exception as e:
print(f"Error scraping {api_name}: {str(e)}")
return None
# 示例:爬取WebSocket API兼容性
df = scrape_mdn_compatibility('WebSocket')
print(df.head())
3.3 数据清洗技巧
原始数据通常需要以下处理:
- 提取最低支持版本(例如"4-116" → 取第一个数字)
- 处理特殊标记(如"≤79"表示最高不支持版本)
- 统一浏览器名称(如"Firefox Android" → "Firefox")
python复制def clean_version(version):
if not version or version.lower() == 'no':
return None
return version.split('-')[0].replace('≤', '').strip()
df['MinVersion'] = df['Version'].apply(clean_version)
4. 爬取Can I Use CSS特性数据
4.1 解析动态渲染的数据
Can I Use使用了大量JavaScript动态渲染内容,简单的HTML解析可能无法获取完整数据。这时我们可以:
- 直接请求他们的API端点
- 或者使用Selenium模拟浏览器
这里展示API方式:
python复制import requests
def get_caniuse_data(feature):
api_url = f"https://caniuse.com/feat/{feature}"
detail_url = f"https://caniuse.com/data/feat/{feature}.json"
try:
response = requests.get(detail_url)
data = response.json()
stats = data['stats']
result = []
for browser, versions in stats.items():
for version, support in versions.items():
result.append({
'Feature': feature,
'Browser': browser,
'Version': version,
'Support': support
})
return pd.DataFrame(result)
except Exception as e:
print(f"Error fetching {feature}: {str(e)}")
return None
# 示例:获取CSS Grid支持情况
css_grid_df = get_caniuse_data('css-grid')
print(css_grid_df.head())
4.2 支持率数据解码
Can I Use的支持状态有多种编码:
y:完全支持a:部分支持n:不支持p:厂商前缀支持
建议添加解释列:
python复制support_map = {
'y': 'Full support',
'a': 'Partial support',
'n': 'No support',
'p': 'Prefixed support'
}
css_grid_df['SupportLevel'] = css_grid_df['Support'].map(support_map)
5. 高级技巧与反爬对策
5.1 请求速率控制
避免被封IP的关键策略:
python复制import time
import random
def delayed_request(url):
time.sleep(random.uniform(1, 3)) # 随机延迟1-3秒
return requests.get(url)
5.2 使用代理池
对于大规模爬取,建议配置代理:
python复制proxies = {
'http': 'http://your_proxy:port',
'https': 'http://your_proxy:port'
}
response = requests.get(url, proxies=proxies)
5.3 处理JavaScript渲染
当目标网站使用前端框架时,可以考虑:
python复制from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.headless = True
driver = webdriver.Chrome(options=options)
driver.get(url)
html = driver.page_source
# 然后用BeautifulSoup解析html
6. 数据存储与应用
6.1 结构化存储方案
建议使用SQLite或CSV:
python复制# CSV存储
df.to_csv('web_api_compatibility.csv', index=False)
# SQLite存储
import sqlite3
conn = sqlite3.connect('compatibility.db')
df.to_sql('mdn_data', conn, if_exists='append', index=False)
6.2 自动生成兼容性报告
用Pandas的样式功能创建可视化报告:
python复制report = df.pivot_table(index=['API', 'Feature'],
columns='Browser',
values='MinVersion',
aggfunc='first')
def highlight_supported(val):
if val and float(val) <= 5: # 假设5是老版本阈值
return 'background-color: yellow'
return ''
report.style.applymap(highlight_supported).to_excel('report.xlsx')
7. 实战中的经验教训
- 缓存策略:对相同API的多次请求,应该本地缓存结果。我通常用
@lru_cache装饰器实现:
python复制from functools import lru_cache
@lru_cache(maxsize=100)
def cached_scrape(api_name):
return scrape_mdn_compatibility(api_name)
- 错误重试机制:网络请求难免失败,建议实现自动重试:
python复制from tenacity import retry, stop_after_attempt
@retry(stop=stop_after_attempt(3))
def reliable_request(url):
return requests.get(url)
- 增量爬取:定期检查更新时,只爬取变更部分。可以通过记录ETag或Last-Modified头实现:
python复制headers = {'If-None-Match': previous_etag}
response = requests.get(url, headers=headers)
if response.status_code == 304:
print('数据未更新')
- 法律合规:始终遵守robots.txt规则,MDN的规则在:
https://developer.mozilla.org/robots.txt。对于商业用途,建议直接使用MDN的官方API。
