
Sora Fujimoto
AI Solutions Architect

AntiCloudflareTaskを使用し、スタティックまたはスタックプロキシと一貫したChromeユーザー・エージェントを使用してください。cf_clearance、プロキシの資格情報、およびロウページコンテンツを一時的なランタイムストレージに保持し、分析やモデルコンテキストに保存しないでください。不動産価格モニタリングは、すべての観測が明確な意味と出所を持つ場合にのみ信頼できます。リストの提示価格は記録された販売価格ではなく、自動評価は取引ではなく、マーケット指数は不動産レベルの価格として扱うことはできません。最も強力なパイプラインは、公式データセットとライセンス付きフィードから始まり、不動産のIDと価格タイプを正規化し、定義されたギャップに対してのみ認可された公開ページを使用します。サポートされているCloudflareチャレンジが期待されるリストページを置き換えた場合、CapSolverは制御された復元ステップを提供できますが、ワークフローはプロキシ、Chromeユーザー・エージェント、クッキースコープ、およびソースポリシーを保持する必要があります。このガイドでは、データソースの階層、観測のスキーマ、比較ルール、チャレンジ検出、AntiCloudflareTask、一時的なセッション復元、価格変更の確認、品質管理、および責任ある使用についてカバーします。
不動産モニタリングジョブは、必要な正確なシグナルを指定する必要があります。例として以下があります:
これらの質問を1つの汎用的な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のウェブスクレイピングFAQでは、認可された公開データ収集の運用ガイドが提供されています。
公式およびライセンス付きデータは主なレイヤーとして使用してください。米国連邦住宅金融管理庁の住宅価格指数は、複数の地理的レベルをカバーする繰り返し販売指数の公開コレクションです。これはマーケットのベンチマークとして価値がありますが、不動産レベルのリストフィードではありません。
記録された取引データには、関連する土地登記所、記録者、またはライセンス付きプロバイダーを使用してください。英国政府の価格支払データは、公式取引データセットの例です。ライセンス付き複数リストまたはポータルAPIは、独自の契約に基づいて現在の提示価格とステータスの観測を提供する可能性があります。
| ソース | 価格の意味 | 推奨役割 | 主な制限 |
|---|---|---|---|
| 公式価格指数 | マーケットトレンド | ベンチマークおよび異常の文脈 | 不動産レベルではない |
| 公開取引記録 | 記録された販売 | 検証および履歴 | 公開遅延が異なる |
| ライセンス付きリストフィード | 現在の提示価格およびステータス | 主なアクティブリストソース | 契約およびカバレッジの制限 |
| パートナーAPI | 定義された商業フィールド | 構造化された運用ソース | プロバイダー固有の意味 |
| 認可された公開ページ | 買い手向けの検証 | ギャップカバレッジおよびQA | レイアウトおよびトラフィックの検証 |
ブラウザ収集は、文書化されたデータギャップのフォールバックとして使用すべきであり、利用可能なライセンスフィードの代替として使用すべきではありません。
不動産IDは、住所の形式が変化し、ユニットが省略される可能性があり、1つの建物に多くのパーセルが含まれるため、難しいです。
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"
ソース固有のfixtureを維持してください。一般的なマーカーは、すべてのターゲットが復元可能であることを証明するものではなく、ルーティングのヒントです。
CapSolverのCloudflare製品ページでは、サポートされているサービスについて説明し、CapSolverのCloudflareブログには追加の実装ガイドが含まれます。
CapSolverのCloudflareチャレンジドキュメンテーションはAntiCloudflareTaskを定義しています。
| フィールド | 必須 | 不動産モニタリングでの使用 |
|---|---|---|
type |
はい | AntiCloudflareTask |
websiteURL |
はい | 精査されたリストまたは公開記録ページの正確なURL |
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は、生産用スケジューラーでモデルまたはユーザーが提供する自由テキストではなく、登録されたソースレコードから取得する必要があります。
AntiCloudflareTaskを作成するimport 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プロファイルを使用するアプリケーション所有のアダプターです。これは、クッキー、プロキシ値、またはヘッダーを分析に公開してはなりません。
公開ページは異なります。承認されたソースごとに1つのアダプターを使用し、明示的なセレクターとセマンティックチェックを使用してください。
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」価格を提示価格として扱わないでください。
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
)
面積が変化し、単位が追加され、またはリストが異なる不動産IDで再リストされた場合、誤った価格移動を報告するのではなく、レビューを要求してください。
単一の観測はノイズが含まれる可能性があります。繰り返し確認またはソースの裏付けを使用してください。
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を使用 |
| キャプチャリトライ | 1回の試行後、レビューを行う |
| 価格の意味 | 明示的な価格タイプ、通貨、単位、およびステータス |
| 証拠 | ソースID、タイムスタンプ、パーサーのバージョン、およびハッシュ |
| アラート | 確認された類似変更のみ |
| 保持 | 短命なクッキー; 指定されたプロパティの観測を管理 |
CapSolver製品ページでサポートされているカテゴリを確認し、CapSolver CAPTCHA解決FAQでタスクフローのガイドを参照してください。
アクセス権があるデータのみを監視してください。リストフィード契約、登録ライセンス、ソースの利用規約、レートリミット、プライバシー法、公平な住宅要件に従ってください。有効な法的根拠がない限り、プライベートアカウントデータ、オーナーの連絡先、テナント情報、申請記録、または制限付き評価レポートを収集しないでください。チャレンジの復元は、承認された公開またはパートナーワークフローに限定してください。技術的な能力は許可を意味しません。
信頼できる不動産価格モニタリングは、比較可能な観測と明確な出所に依存します。公式インデックスと取引データセットがベースラインを提供し、ライセンス付きフィードが現在のリスト詳細を提供し、承認されたページが定義されたギャップを埋めます。サポートされているCloudflareチャレンジがフォールバックを妨げた場合、静的またはスタックプロキシ、一貫したサポートされているChromeユーザーエージェント、短命なクッキー、1回の復元試行、および明確なページ検証を使用してCapSolverを使用してください。
CapSolverで承認された不動産データワークフローを開始し、制御されたソースに対して検証し、価格タイプ、証拠、確認ルールを追加してからアラートをスケーリングしてください。
いいえ。これは繰り返し取引に基づいて構築された市場指数であり、いくつかの地理的レベルで公開されています。個々のリスト価格としてではなく、ベンチマークとして使用してください。
正確なターゲットURLと静的またはスタックプロキシを使用して、文書化された AntiCloudflareTask を使用してください。一貫したサポートされているChromeユーザーエージェントと新しいチャレンジHTMLも必要な場合があります。
それらは異なる価格タイプとして保存する必要があります。比較を行う場合は、一方が販売者のオファーであり、もう一方が完了した取引であることを説明する必要があります。
いいえ。インフラストラクチャまたはパーサーのエラーを記録し、ページの状態を確認してください。セレクターが見つからないことは、リストが削除された証拠ではありません。
cf_clearance はどのくらい保持すべきですか?承認された短命なリクエストセッションのみ保持してください。不動産アナリティクス、モデルコンテキスト、長期ログ、またはカスタマーアラートに保存しないでください。
アンチクラウドフレアタスク、安定したプロキシおよびユーザー エージェントのアイデンティティ、新規のHTML、クリアランス処理、検証、およびセーフエラーを用いて、Cloudflareチャレンジフローを診断します。

信頼性の高いECサイト在庫モニタリングを構築するには、APIファーストのソーシング、Cloudflareチャレンジ復旧、セッション一貫性、在庫証拠、および安全なアラートを活用してください。
