
本文详解为何传统 HTML 解析无法获取 Cloudflare 邮箱保护页面中的 email,以及如何通过解析嵌入的 __NEXT_DATA__ JSON 数据精准提取真实邮箱、姓名、位置等结构化信息。
本文详解为何传统 html 解析无法获取 cloudflare 邮箱保护页面中的 email,以及如何通过解析嵌入的 `__next_data__` json 数据精准提取真实邮箱、姓名、位置等结构化信息。
在使用 requests + BeautifulSoup 抓取类似 Keller Williams(KW)这类现代化房产平台的代理页面时,你可能会发现:明明网页上显示了邮箱,但用 .find() 却只拿到一段形如 /cdn-cgi/l/email-protection#... 的混淆字符串——这正是 Cloudflare Email Protection(CEP)机制在起作用。它通过 JavaScript 动态解密并渲染邮箱,而 BeautifulSoup 仅解析静态 HTML,无法执行 JS,因此原始 HTML 中根本不存在明文邮箱。
幸运的是,该网站基于 Next.js 构建,其服务端渲染(SSR)会在页面 <script id="__NEXT_DATA__"></script> 标签中内嵌完整的初始状态 JSON 数据。其中就包含未混淆的真实邮箱字段,可直接解析获取。
✅ 正确做法是:定位并解析 __NEXT_DATA__ 脚本内容,提取结构化数据:
import requests
from bs4 import BeautifulSoup
import json
url = 'https://www.kw.com/agent/UPA-6587385179144187908-1'
response = requests.get(url)
response.raise_for_status() # 确保请求成功
soup = BeautifulSoup(response.text, 'lxml')
script_tag = soup.find('script', {'id': '__NEXT_DATA__'})
if not script_tag:
raise ValueError("无法找到 __NEXT_DATA__ 脚本标签,请检查页面结构是否变更")
json_data = json.loads(script_tag.string)
# 安全提取嵌套字段(推荐使用 .get() 避免 KeyError)
agent_data = json_data.get('props', {}).get('pageProps', {}).get('agentData', {})
name = agent_data.get('name', {}).get('full', 'N/A')
city = agent_data.get('location', {}).get('city', 'N/A')
state = agent_data.get('location', {}).get('state', 'N/A')
email = agent_data.get('email', 'N/A') # ✅ 这里是真实邮箱字符串,非混淆链接
website = agent_data.get('website', 'N/A')
print(f"姓名: {name}")
print(f"城市: {city}, 州: {state}")
print(f"邮箱: {email}")
print(f"官网: {website}")
⚠️ 注意事项:
- 不要依赖
res.content后再用'html.parser'—— 改用response.text并指定'lxml'或'html.parser'均可,但确保解析的是完整 HTML 字符串; -
__NEXT_DATA__是 Next.js 应用的关键数据入口,但其结构可能随版本更新微调,建议用.get()链式安全访问,或添加异常处理; - 该方法绕过了前端 JS 渲染和反爬混淆,稳定、高效,且无需 Selenium 等重量级工具;
- 若目标网站启用了严格 CSP 或动态加载
__NEXT_DATA__(极少见),才需考虑 Puppeteer 等方案——但对 KW 此类 SSR 页面,JSON 提取是首选。
总结:当面对邮箱被 Cloudflare 加密、内容由 React/Next.js 渲染的现代网站时,放弃“找 标签”的思路,转而挖掘服务端注入的 JSON 数据源,是更专业、更鲁棒的爬虫实践。











