
Ethan Collins
Pattern Recognition Specialist

AntiCloudflareTask并配合静态或粘性代理和一致的Chrome用户代理。cf_clearance、代理凭证和原始页面内容存储在短期运行时存储中,而不是分析或模型上下文中。只有每个观察结果都有明确的含义和来源时,房产价格监控才是可靠的。一个房源的报价不是记录的销售,自动估值不是交易,市场指数不能被视为房产级别的报价。最强的数据管道始于官方数据集和许可数据流,标准化房产身份和价格类型,并且仅在定义的空白处使用授权的公共页面。如果支持的Cloudflare挑战替代了预期的房源页面,CapSolver可以提供一个受控的恢复步骤,但工作流必须保留其代理、Chrome用户代理、cookie作用域和来源策略。本指南涵盖数据源层次结构、观察模式、可比性规则、挑战检测、AntiCloudflareTask、短期会话恢复、价格变化确认、质量控制和负责任的使用。
房产监控任务应明确其需要的信号。示例包括:
不要将这些问题合并为一个通用的price字段。
monitoring_job = {
"canonical_property_id": "prop_83f12",
"market": "US-CA-San-Francisco",
"source_priority": [
"official_transaction_dataset",
"licensed_listing_feed",
"partner_api",
"authorized_public_page",
],
"price_types": ["ASKING_SALE", "RECORDED_SALE"],
"alert_rules": {
"asking_change_percent": 3.0,
"status_changes": ["ACTIVE_TO_PENDING", "PENDING_TO_SOLD"],
},
}
CapSolver网页抓取博客涵盖了相关数据管道模式,CapSolver网页抓取常见问题提供了授权公共数据收集的操作指南。
官方和许可数据应作为主要层。美国联邦住房金融局的 房价指数 是一个覆盖多个地理层级的重复销售指数的公共集合。它对于市场基准有价值,但不是房产级别的房源数据流。
对于记录的交易数据,使用相关的土地登记处、记录处或许可提供商。英国政府的 价格支付数据 是一个官方交易数据集的示例。许可的多重房源或门户网站API可能在其合同下提供当前报价和状态观察。
| 源 | 价格含义 | 推荐角色 | 主要限制 |
|---|---|---|---|
| 官方价格指数 | 市场趋势 | 基准和异常上下文 | 不是房产级别 |
| 公共交易记录 | 记录的销售 | 验证和历史 | 发布延迟各不相同 |
| 许可的房源数据流 | 当前报价和状态 | 主要活跃房源来源 | 合同和覆盖限制 |
| 合作伙伴API | 定义的商业字段 | 结构化操作来源 | 提供商特定语义 |
| 授权公共页面 | 买家面向的验证 | 缺口覆盖和质量保证 | 布局和流量验证 |
浏览器采集应作为文档化数据缺口的后备,而不是可用许可数据流的替代。
房产身份难以确定,因为地址格式会变化,单位可能被省略,一个建筑可能包含多个地块。
from dataclasses import dataclass
@dataclass(frozen=True)
class PropertyIdentity:
canonical_property_id: str
country: str
administrative_area: str
locality: str
postal_code: str
street_number: str
street_name: str
unit: str | None
parcel_id: str | None
latitude: float | None
longitude: float | None
保守地匹配记录。地块或产权标识符比标准化地址更强;精确的单位标识符比建筑级坐标更强。将模糊匹配路由到审查。
CapSolver Python网页数据指南提供了结构化提取管道的实现上下文。
from dataclasses import dataclass, field
from datetime import datetime, timezone
@dataclass
class PriceObservation:
canonical_property_id: str
source: str
source_record_id: str | None
source_url: str | None
price_type: str
amount: float
currency: str
area_value: float | None
area_unit: str | None
status: str | None
market: str
evidence_hash: str
parser_version: str
observed_at: str = field(
default_factory=lambda: datetime.now(timezone.utc).isoformat()
)
使用受控的价格类型词汇表:
PRICE_TYPES = {
"ASKING_SALE",
"RECORDED_SALE",
"ASKING_RENT_MONTHLY",
"VALUATION_ESTIMATE",
"PRICE_PER_AREA",
"MARKET_INDEX",
}
永远不要直接比较ASKING_SALE与RECORDED_SALE或VALUATION_ESTIMATE。保留货币和面积单位。
挑战可能会返回一个中间页面而不是预期的房产页面。不要将缺失的价格选择器解释为下架或零值。
async def classify_property_page(page, expected_selector: str) -> str:
if await page.locator(expected_selector).count():
return "PROPERTY_PAGE"
title = (await page.title()).strip().lower()
html = (await page.content()).lower()
if "just a moment" in title:
return "CLOUDFLARE_CHALLENGE"
if "challenge-platform" in html or "cf-chl-" in html:
return "CLOUDFLARE_CHALLENGE"
if "listing no longer available" in html:
return "LISTING_UNAVAILABLE"
return "UNKNOWN_PAGE"
维护特定源的固定装置。通用标记是路由提示,而不是证明每个目标都可以或应该恢复。
CapSolver Cloudflare产品页面描述了支持的服务,CapSolver Cloudflare博客包含额外的实现指南。
CapSolver的 Cloudflare挑战文档 定义了AntiCloudflareTask。
| 字段 | 必需 | 房产监控用途 |
|---|---|---|
type |
是 | AntiCloudflareTask |
websiteURL |
是 | 精确批准的房源或公共记录页面 |
proxy |
是 | 用于请求会话的静态或粘性代理 |
userAgent |
可选 | 相同的受支持Chrome用户代理 |
html |
条件 | 同一粘性会话的最新挑战HTML |
解决方案可以包含cf_clearance、令牌和用户代理。这些是短期运行时值,不是房产数据。
Cloudflare的 挑战文档 解释了挑战机制的作用。恢复能力不会改变源权限或合同限制。
import os
from urllib.parse import urlparse
SOURCE_POLICY = {
"approved-listings.example": {
"purpose": "asking-price-validation",
"proxy_profile": "property_us_west",
"max_checks_per_hour": 2,
},
}
PROXY_VAULT = {
"property_us_west": os.environ["PROPERTY_PROXY_US_WEST"],
}
def approved_source(url: str) -> dict:
host = urlparse(url).hostname
policy = SOURCE_POLICY.get(host)
if not policy:
raise PermissionError("Property source is not approved")
return policy
目标URL应来自注册的源记录,而不是生产调度器中的模型或用户提供的自由文本。
AntiCloudflareTaskimport capsolver
capsolver.api_key = os.environ["CAPSOLVER_API_KEY"]
def solve_property_page_challenge(
url: str,
chrome_user_agent: str,
fresh_html: str = "",
) -> dict:
policy = approved_source(url)
proxy = PROXY_VAULT[policy["proxy_profile"]]
task = {
"type": "AntiCloudflareTask",
"websiteURL": url,
"proxy": proxy,
"userAgent": chrome_user_agent,
}
if fresh_html:
task["html"] = fresh_html
solution = capsolver.solve(task)
cookies = solution.get("cookies") or {}
clearance = cookies.get("cf_clearance") or solution.get("token")
if not clearance:
raise RuntimeError("Cloudflare Challenge solution is incomplete")
return {
"cookies": cookies,
"user_agent": solution.get("userAgent") or chrome_user_agent,
"proxy_profile": policy["proxy_profile"],
}
使用静态或粘性代理并为其保留初始请求、任务创建和页面恢复。不要将代理凭证放入日志中。
官方CapSolver文档要求使用支持TLS的请求客户端和一致的会话细节。将该实现保留在经过测试的源适配器中。
async def recover_property_document(
source_adapter,
url: str,
challenge_html: str,
user_agent: str,
) -> str:
solution = solve_property_page_challenge(
url=url,
chrome_user_agent=user_agent,
fresh_html=challenge_html,
)
response = await source_adapter.fetch_with_session(
url=url,
proxy_profile=solution["proxy_profile"],
user_agent=solution["user_agent"],
cookies=solution["cookies"],
)
if response.status_code != 200:
raise RuntimeError("Recovered request did not return HTTP 200")
if "challenge-platform" in response.text.lower():
raise RuntimeError("Challenge remained after one recovery attempt")
return response.text
fetch_with_session 是一个由应用拥有且使用批准的TLS配置文件的适配器。它不应向分析工具暴露cookies、代理值或headers。
公共页面各不相同。为每个批准的源使用一个适配器,并带有显式选择器和语义检查。
from decimal import Decimal, InvalidOperation
class SourceAdapter:
source_name = "approved-listings"
parser_version = "2026-08-28.1"
def parse_asking_price(self, document) -> dict:
raw = document.select_one('[data-testid="asking-price"]')
if raw is None:
raise ValueError("Asking-price field not found")
currency = raw.get("data-currency")
amount_text = raw.get("data-amount")
try:
amount = Decimal(amount_text)
except (InvalidOperation, TypeError):
raise ValueError("Invalid asking-price amount")
if amount <= 0 or not currency:
raise ValueError("Incomplete asking-price observation")
return {
"price_type": "ASKING_SALE",
"amount": float(amount),
"currency": currency,
}
不要将营销预估、月供说明或“从”价格视为报价。
from decimal import Decimal
def comparable(left: PriceObservation, right: PriceObservation) -> bool:
return all([
left.canonical_property_id == right.canonical_property_id,
left.price_type == right.price_type,
left.currency == right.currency,
left.market == right.market,
])
def percentage_change(previous: float, current: float) -> float:
if previous <= 0:
raise ValueError("Previous price must be positive")
return float(
(Decimal(str(current)) - Decimal(str(previous)))
/ Decimal(str(previous))
* 100
)
如果面积变化、添加了单位或房源以不同的房产身份重新发布,则需要审查而不是报告虚假的价格变动。
单个观察可能有噪声。使用重复确认或来源佐证。
def confirmed_price_change(
observations: list[PriceObservation],
threshold_percent: float,
) -> dict | None:
if len(observations) < 3:
return None
baseline, first_new, second_new = observations[-3:]
if not comparable(baseline, first_new):
return None
if not comparable(first_new, second_new):
return None
if first_new.amount != second_new.amount:
return None
change = percentage_change(baseline.amount, second_new.amount)
if abs(change) < threshold_percent:
return None
return {
"event": "CONFIRMED_PRICE_CHANGE",
"previous": baseline.amount,
"current": second_new.amount,
"currency": second_new.currency,
"change_percent": round(change, 2),
}
对于交易数据集,使用来源的发布时间和修订政策,而不是浏览器重复确认。
| 事件 | 含义 | 目标 |
|---|---|---|
PRICE_CHANGE_CONFIRMED |
可比较的价格观察发生变化 | 分析师或客户警报 |
STATUS_CHANGED |
活动、待售、已售或移除状态发生变化 | 房源工作流 |
CHALLENGE_ENCOUNTERED |
源呈现支持的挑战 | 自动化仪表板 |
RECOVERY_FAILED |
恢复未返回预期页面 | 操作员审查 |
PARSER_UNKNOWN |
页面返回但价格语义不明确 | 数据质量队列 |
SOURCE_STALE |
官方数据流或页面未刷新 | 源健康监控 |
永远不要将挑战、超时或解析器错误转换为零价格或下架状态。
The CapSolver错误常见问题解答提供了诊断分类,CapSolver自动化博客涵盖了相关的恢复模式。
优惠代码:在CapSolver仪表板使用代码WEBS,每次充值可额外获得5%的奖励。
| 控制项 | 推荐实现方式 |
|---|---|
| 源授权 | 与用途相关的合同或书面批准 |
| 源优先级 | 官方/合作伙伴数据优先于页面回退 |
| 目标范围 | 主机和路径白名单 |
| 代理 | 静态或粘性服务器端配置文件 |
| 用户代理 | 通过恢复使用相同的受支持Chrome身份 |
| 验证重试 | 一次尝试,然后审查 |
| 价格语义 | 明确的价格类型、货币、单位和状态 |
| 证据 | 源ID、时间戳、解析器版本和哈希值 |
| 警报 | 仅确认可比变化 |
| 保留 | 短生命周期Cookie;受监管的属性观察 |
使用CapSolver产品页面查看支持的分类和CapSolver CAPTCHA解决常见问题获取任务流程指导。
仅监控您有权访问的数据。遵守列表-馈送合同、注册许可证、来源条款、速率限制、隐私法和公平住房要求。在没有合法依据的情况下,不得收集私人账户数据、业主联系方式、租户信息、申请记录或受限估值报告。将验证恢复限制在经批准的公共或合作伙伴工作流中。技术能力不等于权限。
可靠的房产价格监控依赖于可比观察和明确的来源。官方指数和交易数据集提供基准;授权的馈送提供当前列表详情;授权页面填补定义的空白。当支持的Cloudflare验证中断该回退时,使用CapSolver并配合静态或粘性代理、一致的Chrome用户代理、短生命周期Cookie、一次恢复尝试和明确的页面验证。
通过CapSolver启动经批准的房产数据工作流,将其与受控源进行验证,并在扩展警报前添加价格类型、证据和确认规则。
不是。它是一个基于重复交易构建的市场指数,并在多个地理层级发布。请将其作为基准,而不是作为单个列表价格。
使用记录的AntiCloudflareTask,并提供精确的目标URL和静态或粘性代理。可能还需要一致的受支持Chrome用户代理和新的验证HTML。
它们应作为不同的价格类型存储。任何比较都必须说明一个为卖方报价,另一个为已完成的交易。
不。记录基础设施或解析器错误并验证页面状态。缺失的选择器不是该列表被移除的证据。
cf_clearance应保留多长时间?仅在短期批准的请求会话中保留。不要将其存储在房产分析、模型上下文、长期日志或客户警报中。