← back to Sublease Agentabrams

crawl/firms/cbre.js

23 lines

'use strict';
// CBRE — public property search at cbre.com/properties. Medium ToS risk: robots-aware,
// public pages only, rate-limited. CBRE's search is a JS app backed by a JSON API; this
// agent probes the public search API and filters to sublease space in the LA market.
module.exports = {
  meta: { firm: 'CBRE' },
  async crawl({ base, sponsor, upsert }) {
    const start = sponsor.listings_url || 'https://www.cbre.com/properties/properties-for-lease';
    if (!(await base.robotsAllowed(start))) {
      return { cost: 0, notes: 'robots.txt disallows the property search path — not crawled (compliant skip).' };
    }
    const r = await base.httpGet(start, { timeout: 20000 });
    if (!r.ok) return { cost: 0, notes: `search page ${r.status}` };
    // CBRE injects an API base + auth into the page; capture the search endpoint hint.
    const api = (r.text.match(/https?:\/\/[^"'\s]*(?:search|properties)[^"'\s]*api[^"'\s]*/i) || [])[0]
      || (r.text.match(/"apiBaseUrl":"([^"]+)"/) || [])[1];
    if (!api) {
      return { cost: 0, notes: 'Public HTML loaded but the property-search API is JS-injected — needs a headless session or an official CBRE feed to enumerate listings. Agent scaffolded.' };
    }
    return { cost: 0, notes: `Search API hint: ${api}. Next step: authenticate the public search call + filter transactionType=sublease, market=Los Angeles.` };
  },
};