From 24a505e9bfff42a281ef1a93517529c6ab7470b0 Mon Sep 17 00:00:00 2001 From: niku Date: Tue, 17 Feb 2026 23:11:16 +0100 Subject: [PATCH] some more changes --- .env.example | 5 ++ .gitignore | 1 + Justfile | 21 +++++---- dbt/.gitignore | 5 ++ dbt/README.md | 15 ++++++ dbt/analyses/.gitkeep | 0 dbt/dbt_project.yml | 33 ++++++++++++++ dbt/macros/extract_numeric.sql | 3 ++ dbt/models/marts/listings.sql | 5 ++ dbt/models/staging/__sources.yml | 6 +++ dbt/models/staging/stg_listings.sql | 53 ++++++++++++++++++++++ dbt/package-lock.yml | 5 ++ dbt/packages.yml | 3 ++ dbt/seeds/.gitkeep | 0 dbt/snapshots/.gitkeep | 0 dbt/tests/.gitkeep | 0 docker-compose.yaml | 2 +- replication.yaml => sling/replication.yaml | 6 +-- src/main.ts | 46 ++++++++++++++----- src/resolve.ts | 35 -------------- 20 files changed, 184 insertions(+), 60 deletions(-) create mode 100644 .env.example create mode 100644 dbt/.gitignore create mode 100644 dbt/README.md create mode 100644 dbt/analyses/.gitkeep create mode 100644 dbt/dbt_project.yml create mode 100644 dbt/macros/extract_numeric.sql create mode 100644 dbt/models/marts/listings.sql create mode 100644 dbt/models/staging/__sources.yml create mode 100644 dbt/models/staging/stg_listings.sql create mode 100644 dbt/package-lock.yml create mode 100644 dbt/packages.yml create mode 100644 dbt/seeds/.gitkeep create mode 100644 dbt/snapshots/.gitkeep create mode 100644 dbt/tests/.gitkeep rename replication.yaml => sling/replication.yaml (50%) delete mode 100644 src/resolve.ts diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..2798437 --- /dev/null +++ b/.env.example @@ -0,0 +1,5 @@ +POSTGRES_HOST=172.17.0.1 +POSTGRES_PORT=5432 +POSTGRES_DB=fundamnit +POSTGRES_USER=fundamnit +POSTGRES_PASSWORD=fundamnit diff --git a/.gitignore b/.gitignore index e0996e6..f7cfca5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ dist node_modules storage +.env diff --git a/Justfile b/Justfile index 3ffbe3a..04849c0 100644 --- a/Justfile +++ b/Justfile @@ -1,17 +1,20 @@ set dotenv-load -run_sling: +run-scraper: + bun run start + +run-sling: docker run -it --rm \ - -v ${PWD}/replication.yaml:/replication.yaml \ + -v ${PWD}/sling/replication.yaml:/replication.yaml \ -v ${PWD}/storage:/storage \ -e POSTGRES="postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST:$POSTGRES_PORT/$POSTGRES_DB?sslmode=disable" \ -e SLING_DISABLE_TELEMETRY=true \ docker.io/slingdata/sling run -r /replication.yaml -run: - docker run -it --rm \ - -v ${PWD}/replication.yaml:/replication.yaml \ - -v ${PWD}/storage:/storage \ - -e POSTGRES="postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST:$POSTGRES_PORT/$POSTGRES_DB?sslmode=disable" \ - --entrypoint bash \ - docker.io/slingdata/sling:v1.4.24 +run-dbt: + cd dbt && dbt run --static-analysis off + +run-all: + just run-scraper + just run-sling + just run-dbt diff --git a/dbt/.gitignore b/dbt/.gitignore new file mode 100644 index 0000000..1c22a22 --- /dev/null +++ b/dbt/.gitignore @@ -0,0 +1,5 @@ + +target/ +dbt_packages/ +logs/ +dbt_internal_packages/ diff --git a/dbt/README.md b/dbt/README.md new file mode 100644 index 0000000..7874ac8 --- /dev/null +++ b/dbt/README.md @@ -0,0 +1,15 @@ +Welcome to your new dbt project! + +### Using the starter project + +Try running the following commands: +- dbt run +- dbt test + + +### Resources: +- Learn more about dbt [in the docs](https://docs.getdbt.com/docs/introduction) +- Check out [Discourse](https://discourse.getdbt.com/) for commonly asked questions and answers +- Join the [chat](https://community.getdbt.com/) on Slack for live discussions and support +- Find [dbt events](https://events.getdbt.com) near you +- Check out [the blog](https://blog.getdbt.com/) for the latest news on dbt's development and best practices diff --git a/dbt/analyses/.gitkeep b/dbt/analyses/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/dbt/dbt_project.yml b/dbt/dbt_project.yml new file mode 100644 index 0000000..a2e3dc6 --- /dev/null +++ b/dbt/dbt_project.yml @@ -0,0 +1,33 @@ +# Name your project! Project names should contain only lowercase characters +# and underscores. A good package name should reflect your organization's +# name or the intended use of these models +name: "fundamnit" +version: "1.0.0" + +# This setting configures which "profile" dbt uses for this project. +profile: "fundamnit" + +# These configurations specify where dbt should look for different types of files. +# The `model-paths` config, for example, states that models in this project can be +# found in the "models/" directory. You probably won't need to change these! +model-paths: ["models"] +analysis-paths: ["analyses"] +test-paths: ["tests"] +seed-paths: ["seeds"] +macro-paths: ["macros"] +snapshot-paths: ["snapshots"] + +clean-targets: # directories to be removed by `dbt clean` + - "target" + - "dbt_packages" + +# Configuring models +# Full documentation: https://docs.getdbt.com/docs/configuring-models + +# In this example config, we tell dbt to build all models in the example/ +# directory as views. These settings can be overridden in the individual model +# files using the `{{ config(...) }}` macro. +models: + fundamnit: + staging: + +materialized: view diff --git a/dbt/macros/extract_numeric.sql b/dbt/macros/extract_numeric.sql new file mode 100644 index 0000000..a40c157 --- /dev/null +++ b/dbt/macros/extract_numeric.sql @@ -0,0 +1,3 @@ +{% macro extract_numeric(column_name) %} + NULLIF(regexp_replace({{ column_name }}, '[^0-9]','','g'), '')::numeric +{% endmacro %} diff --git a/dbt/models/marts/listings.sql b/dbt/models/marts/listings.sql new file mode 100644 index 0000000..da7ab94 --- /dev/null +++ b/dbt/models/marts/listings.sql @@ -0,0 +1,5 @@ +{{ config(materialized='table') }} +select + * +from + {{ ref('stg_listings') }} diff --git a/dbt/models/staging/__sources.yml b/dbt/models/staging/__sources.yml new file mode 100644 index 0000000..fa87f19 --- /dev/null +++ b/dbt/models/staging/__sources.yml @@ -0,0 +1,6 @@ +version: 2 + +sources: + - name: funda + tables: + - name: raw_listings diff --git a/dbt/models/staging/stg_listings.sql b/dbt/models/staging/stg_listings.sql new file mode 100644 index 0000000..39ab727 --- /dev/null +++ b/dbt/models/staging/stg_listings.sql @@ -0,0 +1,53 @@ +with source as ( + select + * + from + {{ source('funda', 'raw_listings') }} +), +flattened_json as ( + select + (data#>>'{globalId}')::int as listing_id, + (data#>>'{parentProject,globalId}')::int as parent_id, + + (data#>>'{address,addressTitle}')::varchar as title, + + (data#>>'{tracking,listing_offering_type}')::varchar as offering_type, + (data#>>'{tracking,listing_type}')::varchar as listing_type, + (data#>>'{tracking,listing_status}')::varchar as listing_status, + + (data#>>'{advertising,targetingOptions,aantalkamers}')::int as rooms, + (data#>>'{featuresFastView,energyLabel}')::varchar as energy_label, + + {{ extract_numeric("data#>>'{featuresFastView,livingArea}'") }} as living_area, + {{ extract_numeric("data#>>'{featuresFastView,plotArea}'") }} as plot_area, + + (data#>>'{price,numericPrice}')::int as price, + (data#>>'{isSoldOrRented}')::boolean as is_sold, + + (data#>>'{advertising,targetingOptions,balkon}')::boolean as has_balcony, + (data#>>'{advertising,targetingOptions,tuin}')::boolean as has_garden, + (data#>>'{advertising,targetingOptions,parkeergelegenheidopafgeslotenterrein}')::boolean as has_closed_parking, + (data#>>'{advertising,targetingOptions,parkeergelegenheidopeigenterrein}')::boolean as has_private_parking, + + (data#>>'{address,country}')::varchar as country, + (data#>>'{address,province}')::varchar as province, + initcap((data#>>'{advertising,targetingOptions,gemeente}')) as municipality, + (data#>>'{address,city}')::varchar as city, + (data#>>'{address,neighborhood,name}')::varchar as neighborhood, + (data#>>'{address,postcode}')::varchar as postcode, + (data#>>'{tracking,listing_house_no}')::varchar as house_number, + (data#>>'{tracking,listing_house_no_addition}')::varchar as house_number_addition, + + (data#>>'{coordinates,lng}')::float as longitude, + (data#>>'{coordinates,lat}')::float as latitude, + + (data#>>'{googleMapsObjectUrl}')::varchar as google_maps_url, + + (data#>>'{canonicalUrl}')::varchar as listing_url + from + source +) +select + * +from + flattened_json diff --git a/dbt/package-lock.yml b/dbt/package-lock.yml new file mode 100644 index 0000000..5490c2b --- /dev/null +++ b/dbt/package-lock.yml @@ -0,0 +1,5 @@ +packages: +- package: dbt-labs/dbt_utils + name: dbt_utils + version: 1.3.1 +sha1_hash: a58234d0b6335a94dffedc7a19f7278eaed2ecda diff --git a/dbt/packages.yml b/dbt/packages.yml new file mode 100644 index 0000000..48c5d57 --- /dev/null +++ b/dbt/packages.yml @@ -0,0 +1,3 @@ +packages: + - package: dbt-labs/dbt_utils + version: 1.3.1 diff --git a/dbt/seeds/.gitkeep b/dbt/seeds/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/dbt/snapshots/.gitkeep b/dbt/snapshots/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/dbt/tests/.gitkeep b/dbt/tests/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docker-compose.yaml b/docker-compose.yaml index 06fa50d..4720b3c 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,6 +1,6 @@ services: postgres: - image: docker.io/library/postgres:18 + image: docker.io/postgis/postgis:18-3.6 ports: - ${POSTGRES_PORT}:5432 environment: diff --git a/replication.yaml b/sling/replication.yaml similarity index 50% rename from replication.yaml rename to sling/replication.yaml index 4ec0514..36748d0 100644 --- a/replication.yaml +++ b/sling/replication.yaml @@ -2,10 +2,10 @@ source: LOCAL target: POSTGRES defaults: - mode: full-refresh - object: funda.projects + mode: snapshot + object: funda.raw_listings source_options: format: json streams: - "file:///storage/datasets/projects/": + "file:///storage/datasets/listings/": diff --git a/src/main.ts b/src/main.ts index 1d5f6fc..d96c45e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,13 +1,17 @@ import { PlaywrightCrawler } from 'crawlee'; -import { chromium, Locator, Page } from 'patchright'; -import * as z from 'zod'; +import { chromium } from 'patchright'; -const PROJECT_URL = /https:\/\/www\.funda\.nl\/detail\/nieuwbouw\/.*/; +const PROJECT_PAGE_URL = /^https:\/\/www\.funda\.nl\/detail\/nieuwbouw\/.*\/\d+\/$/; +const LISTING_PAGE_URL = /^https:\/\/www\.funda\.nl\/detail\/\d+\/$/; -function parseNuxtData(data: unknown[], offset: number = 0) { +function parseNuxtData(data: unknown[], offset: number = 0, exclude: number[] = []) { let item = data[offset]; - if (typeof item === "string" || typeof item === "number" || typeof item === "boolean" || typeof item === "undefined") { + if (exclude.includes(offset)) { + return; + } + + if (typeof item === "string" || typeof item === "number" || typeof item === "boolean" || typeof item === "undefined" || item === null) { return item; } @@ -37,20 +41,38 @@ function parseNuxtData(data: unknown[], offset: number = 0) { } const crawler = new PlaywrightCrawler({ - async requestHandler({ request, page, enqueueLinks, pushData }) { - const title = await page.title(); + async requestHandler({ request, page, enqueueLinks, log, pushData }) { + log.info(`Processing ${request.url}`); - if (PROJECT_URL.test(request.url)) { + if (LISTING_PAGE_URL.test(request.url)) { const rawData = await page.locator("#__NUXT_DATA__").innerText(); - const data = parseNuxtData(JSON.parse(rawData), 4); - await pushData(data, "projects"); + const data = parseNuxtData(JSON.parse(rawData), 6); + await pushData(data, "listings"); + return; } - await enqueueLinks({ regexps: [PROJECT_URL] }) + if (PROJECT_PAGE_URL.test(request.url)) { + const rawData = await page.locator("#__NUXT_DATA__").innerText(); + const data = parseNuxtData(JSON.parse(rawData), 4); + + const urls: string[] = []; + for (const objectType of data.projectListings.objectTypes) { + for (const listing of objectType.listings) { + urls.push(listing.listingUrl); + } + } + + await enqueueLinks({ urls: urls }); + return; + } + + await enqueueLinks({ selector: '[aria-label=Volgende]' }); + await enqueueLinks({ regexps: [PROJECT_PAGE_URL] }); }, - maxRequestsPerCrawl: 20, + maxRequestsPerCrawl: 100, headless: false, launchContext: { + // @ts-ignore launcher: chromium } }); diff --git a/src/resolve.ts b/src/resolve.ts deleted file mode 100644 index 9955dfd..0000000 --- a/src/resolve.ts +++ /dev/null @@ -1,35 +0,0 @@ -const a = [["ShallowReactive", 1], { "data": 2, "state": 504, "once": 508, "_errors": 509, "serverRendered": 237, "path": 472 }, ["ShallowReactive", 3], { "cachedProjectData_nl": 4 }, { "globalId": 5, "offeringType": 6, "address": 7, "price": 19, "media": 22, "fastView": 200, "description": 211, "projectListings": 215, "coordinates": 464, "promo": 467, "canonicalUrl": 470, "reportErrorUrl": 473, "advertising": 474, "tracking": 493, "friendlyUrlSlug": 501, "projectWebsiteUrl": 502, "cadastralMapBaseUrl": 503 }, 6617373, "Sale", { "addressTitle": 8, "addressSubtitle": 9, "neighborhood": 10, "city": 13, "postcode": 14, "houseNumber": 15, "province": 16, "country": 17, "isInternational": 18 }, "Jaagpad", "1821 BE Alkmaar", { "id": 11, "name": 12 }, "alkmaar/schermereiland-en-omval", "Schermereiland en Omval", "Alkmaar", "1821 BE", "31", "Noord-Holland", "Nederland", false, { "sellingPrice": 20, "rentalPrice": -1, "numericPrice": 21 }, "€ 579.000 - € 1.349.000 v.o.n.", 579000, { "photos": 23, "videos": 72, "legacyPhotos360": 78, "floorPlan": -1, "brochureUrl": 199 }, { "mediaBaseUrl": 24, "thumbnailBaseUrl": 24, "items": 25 }, "https://cloud.funda.nl/valentina_media/{id}.jpg", [26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70], { "id": 27, "displayName": 27 }, "168/959/203", { "id": 29, "displayName": 29 }, "168/959/199", { "id": 31, "displayName": 31 }, "204/103/489", { "id": 33, "displayName": 33 }, "204/103/494", { "id": 35, "displayName": 35 }, "204/103/495", { "id": 37, "displayName": 37 }, "204/103/504", { "id": 39, "displayName": 39 }, "204/103/508", { "id": 41, "displayName": 41 }, "204/103/512", { "id": 43, "displayName": 43 }, "204/103/514", { "id": 45, "displayName": 45 }, "204/103/518", { "id": 47, "displayName": 47 }, "204/103/522", { "id": 49, "displayName": 49 }, "204/103/524", { "id": 51, "displayName": 51 }, "204/103/526", { "id": 53, "displayName": 53 }, "204/103/527", { "id": 55, "displayName": 55 }, "168/959/198", { "id": 57, "displayName": 57 }, "168/959/200", { "id": 59, "displayName": 59 }, "168/959/205", { "id": 61, "displayName": 61 }, "168/959/201", { "id": 63, "displayName": 63 }, "168/959/204", { "id": 65, "displayName": 65 }, "168/959/206", { "id": 67, "displayName": 67 }, "168/959/208", { "id": 69, "displayName": 69 }, "168/959/207", { "id": 71, "displayName": 71 }, "188/062/701", { "mediaBaseUrl": 73, "thumbnailBaseUrl": 74, "items": 75 }, "https://customer-vzk8jgcsaz84e8sb.cloudflarestream.com/{id}/manifest/video.m3u8", "https://customer-vzk8jgcsaz84e8sb.cloudflarestream.com/{id}/thumbnails/thumbnail.jpg", [76], { "id": 77, "displayName": 77 }, "3875185e72c8fc80fe9dd2f7e0b7d337", { "mediaBaseUrl": 79, "thumbnailBaseUrl": 80, "items": 81 }, "https://cloud.funda.nl/valentina_media", "https://cloud.funda.nl/valentina_media/{id}_groot.jpg", [82, 105, 121, 136, 152, 168, 183], { "id": 83, "displayName": 84, "photo": 85 }, "204/008/577", "Woonkamer", { "id": 83, "displayName": 84, "name": 86, "verticalFieldOfView": 87, "initialHorizontalViewingAngle": 88, "tiledImageSetsTileSize": 89, "hotspots": 90, "infospots": 91, "tileImageSets": 92 }, "woonkamer", 90, 0, 512, [], [], { "mobile": 93, "tablet": 96, "zoomLevelOne": 99, "zoomLevelTwo": 102 }, { "path": 94, "width": 95, "height": 95 }, "/204/008/577/mobile_%s.jpg", 480, { "path": 97, "width": 98, "height": 98 }, "/204/008/577/tablet_%s.jpg", 1280, { "path": 100, "width": 101, "height": 101 }, "/204/008/577/tile.l1_%s_%00y_%00x.jpg", 729, { "path": 103, "width": 104, "height": 104 }, "/204/008/577/tile.l2_%s_%00y_%00x.jpg", 1458, { "id": 106, "displayName": 107, "photo": 108 }, "204/008/949", "Keuken", { "id": 106, "displayName": 107, "name": 109, "verticalFieldOfView": 87, "initialHorizontalViewingAngle": 88, "tiledImageSetsTileSize": 89, "hotspots": 110, "infospots": 111, "tileImageSets": 112 }, "keuken1", [], [], { "mobile": 113, "tablet": 115, "zoomLevelOne": 117, "zoomLevelTwo": 119 }, { "path": 114, "width": 95, "height": 95 }, "/204/008/949/mobile_%s.jpg", { "path": 116, "width": 98, "height": 98 }, "/204/008/949/tablet_%s.jpg", { "path": 118, "width": 101, "height": 101 }, "/204/008/949/tile.l1_%s_%00y_%00x.jpg", { "path": 120, "width": 104, "height": 104 }, "/204/008/949/tile.l2_%s_%00y_%00x.jpg", { "id": 122, "displayName": 107, "photo": 123 }, "204/008/578", { "id": 122, "displayName": 107, "name": 124, "verticalFieldOfView": 87, "initialHorizontalViewingAngle": 88, "tiledImageSetsTileSize": 89, "hotspots": 125, "infospots": 126, "tileImageSets": 127 }, "keuken2", [], [], { "mobile": 128, "tablet": 130, "zoomLevelOne": 132, "zoomLevelTwo": 134 }, { "path": 129, "width": 95, "height": 95 }, "/204/008/578/mobile_%s.jpg", { "path": 131, "width": 98, "height": 98 }, "/204/008/578/tablet_%s.jpg", { "path": 133, "width": 101, "height": 101 }, "/204/008/578/tile.l1_%s_%00y_%00x.jpg", { "path": 135, "width": 104, "height": 104 }, "/204/008/578/tile.l2_%s_%00y_%00x.jpg", { "id": 137, "displayName": 138, "photo": 139 }, "204/008/579", "Slaapkamer", { "id": 137, "displayName": 138, "name": 140, "verticalFieldOfView": 87, "initialHorizontalViewingAngle": 88, "tiledImageSetsTileSize": 89, "hotspots": 141, "infospots": 142, "tileImageSets": 143 }, "slaapkamer1", [], [], { "mobile": 144, "tablet": 146, "zoomLevelOne": 148, "zoomLevelTwo": 150 }, { "path": 145, "width": 95, "height": 95 }, "/204/008/579/mobile_%s.jpg", { "path": 147, "width": 98, "height": 98 }, "/204/008/579/tablet_%s.jpg", { "path": 149, "width": 101, "height": 101 }, "/204/008/579/tile.l1_%s_%00y_%00x.jpg", { "path": 151, "width": 104, "height": 104 }, "/204/008/579/tile.l2_%s_%00y_%00x.jpg", { "id": 153, "displayName": 154, "photo": 155 }, "204/008/580", "Badkamer", { "id": 153, "displayName": 154, "name": 156, "verticalFieldOfView": 87, "initialHorizontalViewingAngle": 88, "tiledImageSetsTileSize": 89, "hotspots": 157, "infospots": 158, "tileImageSets": 159 }, "badkamer", [], [], { "mobile": 160, "tablet": 162, "zoomLevelOne": 164, "zoomLevelTwo": 166 }, { "path": 161, "width": 95, "height": 95 }, "/204/008/580/mobile_%s.jpg", { "path": 163, "width": 98, "height": 98 }, "/204/008/580/tablet_%s.jpg", { "path": 165, "width": 101, "height": 101 }, "/204/008/580/tile.l1_%s_%00y_%00x.jpg", { "path": 167, "width": 104, "height": 104 }, "/204/008/580/tile.l2_%s_%00y_%00x.jpg", { "id": 169, "displayName": 138, "photo": 170 }, "204/008/581", { "id": 169, "displayName": 138, "name": 171, "verticalFieldOfView": 87, "initialHorizontalViewingAngle": 88, "tiledImageSetsTileSize": 89, "hotspots": 172, "infospots": 173, "tileImageSets": 174 }, "slaapkamer2", [], [], { "mobile": 175, "tablet": 177, "zoomLevelOne": 179, "zoomLevelTwo": 181 }, { "path": 176, "width": 95, "height": 95 }, "/204/008/581/mobile_%s.jpg", { "path": 178, "width": 98, "height": 98 }, "/204/008/581/tablet_%s.jpg", { "path": 180, "width": 101, "height": 101 }, "/204/008/581/tile.l1_%s_%00y_%00x.jpg", { "path": 182, "width": 104, "height": 104 }, "/204/008/581/tile.l2_%s_%00y_%00x.jpg", { "id": 184, "displayName": 185, "photo": 186 }, "204/008/582", "Berging", { "id": 184, "displayName": 185, "name": 187, "verticalFieldOfView": 87, "initialHorizontalViewingAngle": 88, "tiledImageSetsTileSize": 89, "hotspots": 188, "infospots": 189, "tileImageSets": 190 }, "berging", [], [], { "mobile": 191, "tablet": 193, "zoomLevelOne": 195, "zoomLevelTwo": 197 }, { "path": 192, "width": 95, "height": 95 }, "/204/008/582/mobile_%s.jpg", { "path": 194, "width": 98, "height": 98 }, "/204/008/582/tablet_%s.jpg", { "path": 196, "width": 101, "height": 101 }, "/204/008/582/tile.l1_%s_%00y_%00x.jpg", { "path": 198, "width": 104, "height": 104 }, "/204/008/582/tile.l2_%s_%00y_%00x.jpg", "https://cloud.funda.nl/valentina_media/201/885/327.pdf", { "livingArea": 201, "numberOfRooms": 202, "plotArea": -1, "availability": 203, "objectTypes": 205, "projectTimeline": 208 }, "102 tot 196 m²", "1 tot 4", { "expectedUnits": 88, "totalUnits": 204, "availableUnits": 204, "unavailableUnits": 88, "underOptionUnits": 88 }, 31, [206, 207], "Portiekflat", "Penthouse", { "phase": 209, "constructionStartDate": -1, "expectedDeliveryDate": 210, "startOfSaleDate": -1 }, "In voorbereiding", "Februari 2027", { "title": 212, "content": 213, "locationTitle": 214, "locationContent": -1 }, "Omschrijving", "APPARTEMENTEN JAAGPAD ALKMAAR – LAATSTE VERKOOPFASE!\n\nDe bouw van Jaagpad Alkmaar is in volle gang en de belangstelling is groot: inmiddels is meer dan 85% van de appartementen verkocht! Dit prachtige nieuwbouwproject aan het Noordhollandsch Kanaal krijgt steeds meer vorm. De oplevering van de eerste woningen staat gepland voor begin 2027. Hier woon je straks op een unieke locatie, op een steenworp afstand van het bruisende centrum van Alkmaar.\n\nLOCATIE\n\nAlkmaar, bekend als dé kaasstad van Nederland, biedt veel meer dan historische charme. Het sfeervolle centrum heeft gezellige winkelstraatjes, een breed aanbod aan horeca en een levendige uitgaansscene. Bovendien ligt Alkmaar ideaal ten opzichte van Haarlem en Amsterdam, met uitstekende verbindingen per auto én openbaar vervoer.\n\nVanaf Jaagpad wandel je in slechts 15 minuten naar het iconische Waagplein, of fiets je er in 5 minuten naartoe.\n\nBIJZONDERHEDEN\n\n- Laatste verkoopfase – meer dan 85% verkocht\n- Bouw gestart\n- Oplevering gepland begin 2027\n- Volledig gasloos en voorzien van energiezuinige vloerverwarming\n- Verplichte huur van parkeerplaats in onderliggende parkeergarage (€ 94,47 per maand).\n\nInteresse? Schrijf je in! Ben je geïnteresseerd in een appartement aan Jaagpad? Bekijk de woningzoeker en verkooptekeningen op de projectwebsite en schrijf je vandaag nog in of neem direct contact met een van de makelaars. ()\n\nLet op: De foto’s in de aanmelding zijn ter impressie en afkomstig van de modelwoning in het huurgebouw van het Jaagpad. Hoewel deze een goed beeld geven van de afwerking en sfeer, kunnen hier geen rechten aan worden ontleend. Tevens zijn de gebruikte afbeeldingen en mediabestanden dienen uitsluitend ter illustratie. Hieraan kunnen geen rechten worden ontleend, en de feitelijke indeling, inrichting of staat van de appartementen kan afwijken van de getoonde beelden.", "Omgeving", { "availability": 216, "objectTypes": 217 }, "Van de 97 huizen in dit project zijn er nog 31 beschikbaar", [218, 305, 385, 425, 450], { "globalId": 219, "projectId": 5, "price": 220, "title": 212, "description": 222, "name": 223, "livingArea": 224, "numberOfRooms": 225, "buildingType": 206, "thumbnailUrl": 226, "availability": 227, "listings": 229 }, 7744519, { "sellingPrice": 221, "rentalPrice": -1 }, "€ 782.500 - € 860.000 v.o.n.", "Het Jaagpad bevindt zich in de laatste verkoopfase, en van alle woningtypes zijn nog enkele appartementen beschikbaar. De L-appartementen onderscheiden zich door hun karakteristieke vormgeving, waarbij de slimme indeling zorgt voor veel licht en ruimte, zowel binnen als buiten.\n\nMet een woonoppervlakte van 128 tot 143 m² en een ruim balkon of terras, bieden deze woningen volop leefcomfort. De appartementen zijn beschikbaar vanaf € 782.500,- en beschikken daarnaast over een eigen parkeerplaats in de ondergelegen garage.\n\nOp een unieke plek in Alkmaar, direct aan het Noordhollandsch Kanaal en op korte afstand van het historische stadscentrum, wordt woonproject Jaagpad gerealiseerd. In de eerste fase komen diverse moderne koopappartementen beschikbaar die comfort, duurzaamheid en een prachtig uitzicht combineren.\n\nAlkmaar is veel meer dan de bekende kaasstad. Het sfeervolle centrum biedt een rijk aanbod aan winkels, restaurants en gezellige terrassen. Bovendien woon je hier op een strategische locatie: Haarlem en Amsterdam zijn uitstekend bereikbaar met de auto en het openbaar vervoer.\n\nDe beschikbare appartementen in het Jaagpad zijn gasloos en energiezuinig, met woonoppervlaktes van circa 102 tot 196 m². Dankzij de grote variatie in indelingen is er voor iedere woonwens een passend appartement. Kies voor een ruim drie- of vierkamerappartement, of ga voor een exclusief penthouse met plafonds tot wel 4 meter hoog. Elk appartement beschikt over een ruim balkon of terras. Daarnaast is er de mogelijkheid een eigen parkeerplaats onder het complex te huren.\n\nOp Jaagpad woon je op loop- en fietsafstand van de stad. Binnen 15 minuten wandel je naar het Waagplein, en met de fiets ben je er in slechts 5 minuten. Tegelijkertijd geniet je thuis van rust, ruimte en het uitzicht over het water.\n\nBen je nieuwsgierig geworden naar wonen aan het Jaagpad? Bekijk de woningzoeker en verkooptekeningen op de projectwebsite en neem contact op met een van de betrokken makelaars voor meer informatie of een persoonlijk gesprek.", "L appartement", "128 tot 143 m²", "4", "https://cloud.funda.nl/valentina_media/168/959/203_360.jpg", { "totalUnits": 228, "availableUnits": 228, "unavailableUnits": 88, "underOptionUnits": 88 }, 12, [230, 240, 246, 252, 258, 263, 269, 275, 280, 287, 294, 300], { "rooms": 231, "livingSpace": 232, "title": 233, "listingUrl": 234, "status": 235, "price": 238 }, 4, "140 m²", "L appartement (Bouwnr. 2.01.21)", "https://www.funda.nl/detail/43199914/", { "value": 236, "isAvailable": 237 }, "Beschikbaar", true, { "sellingPrice": 239, "rentalPrice": -1 }, "€ 782.500 v.o.n.", { "rooms": 231, "livingSpace": 241, "title": 242, "listingUrl": 243, "status": 244, "price": 245 }, "142 m²", "L appartement (Bouwnr. 2.01.22)", "https://www.funda.nl/detail/43199900/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 239, "rentalPrice": -1 }, { "rooms": 231, "livingSpace": 241, "title": 247, "listingUrl": 248, "status": 249, "price": 250 }, "L appartement (Bouwnr. 3.01.20)", "https://www.funda.nl/detail/43199916/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 251, "rentalPrice": -1 }, "€ 783.000 v.o.n.", { "rooms": 231, "livingSpace": 241, "title": 253, "listingUrl": 254, "status": 255, "price": 256 }, "L appartement (Bouwnr. 2.02.34)", "https://www.funda.nl/detail/43199908/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 257, "rentalPrice": -1 }, "€ 787.000 v.o.n.", { "rooms": 231, "livingSpace": 241, "title": 259, "listingUrl": 260, "status": 261, "price": 262 }, "L appartement (Bouwnr. 3.02.30)", "https://www.funda.nl/detail/43199919/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 257, "rentalPrice": -1 }, { "rooms": 231, "livingSpace": 241, "title": 264, "listingUrl": 265, "status": 266, "price": 267 }, "L appartement (Bouwnr. 2.03.46)", "https://www.funda.nl/detail/43199902/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 268, "rentalPrice": -1 }, "€ 790.000 v.o.n.", { "rooms": 231, "livingSpace": 241, "title": 270, "listingUrl": 271, "status": 272, "price": 273 }, "L appartement (Bouwnr. 2.04.58)", "https://www.funda.nl/detail/43199913/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 274, "rentalPrice": -1 }, "€ 795.000 v.o.n.", { "rooms": 231, "livingSpace": 241, "title": 276, "listingUrl": 277, "status": 278, "price": 279 }, "L appartement (Bouwnr. 3.04.50)", "https://www.funda.nl/detail/43199918/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 274, "rentalPrice": -1 }, { "rooms": 231, "livingSpace": 281, "title": 282, "listingUrl": 283, "status": 284, "price": 285 }, "128 m²", "L appartement (Bouwnr. 3.05.51)", "https://www.funda.nl/detail/43199910/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 286, "rentalPrice": -1 }, "€ 839.000 v.o.n.", { "rooms": 231, "livingSpace": 288, "title": 289, "listingUrl": 290, "status": 291, "price": 292 }, "141 m²", "L appartement (Bouwnr. 2.00.11)", "https://www.funda.nl/detail/43199901/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 293, "rentalPrice": -1 }, "€ 860.000 v.o.n.", { "rooms": 231, "livingSpace": 295, "title": 296, "listingUrl": 297, "status": 298, "price": 299 }, "143 m²", "L appartement (Bouwnr. 3.00.09)", "https://www.funda.nl/detail/43199915/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 293, "rentalPrice": -1 }, { "rooms": 231, "livingSpace": 288, "title": 301, "listingUrl": 302, "status": 303, "price": 304 }, "L appartement (Bouwnr. 3.00.10)", "https://www.funda.nl/detail/43199912/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 293, "rentalPrice": -1 }, { "globalId": 306, "projectId": 5, "price": 307, "title": 212, "description": 309, "name": 310, "livingArea": 311, "numberOfRooms": 312, "buildingType": 206, "thumbnailUrl": 226, "availability": 313, "listings": 315 }, 7744520, { "sellingPrice": 308, "rentalPrice": -1 }, "€ 579.000 - € 599.000 v.o.n.", "Het Jaagpad bevindt zich in de laatste verkoopfase. Van alle woningtypes zijn nog enkele appartementen beschikbaar, waaronder nog enkele tussen appartementen. Deze woningen combineren een slimme indeling met veel leefruimte, grote raampartijen en een prettige buitenruimte in de vorm van een balkon of terras.\n\nMet een woonoppervlakte van circa 102 tot 116 m² zijn deze tussenappartementen ideaal voor wie ruim wil wonen met bijvoorbeeld een thuiskantoor, hobbyruimte of extra slaapkamer. De appartementen zijn uiteraard gasloos en worden geleverd met een eigen parkeerplaats in de ondergelegen garage. Prijzen starten vanaf € 579.000,-.\n\nOp een unieke plek in Alkmaar, direct aan het Noordhollandsch Kanaal en op korte afstand van het historische stadscentrum, wordt woonproject Jaagpad gerealiseerd. In de eerste fase komen diverse moderne koopappartementen beschikbaar die comfort, duurzaamheid en een prachtig uitzicht combineren.\n\nAlkmaar is veel meer dan de bekende kaasstad. Het sfeervolle centrum biedt een rijk aanbod aan winkels, restaurants en gezellige terrassen. Bovendien woon je hier op een strategische locatie: Haarlem en Amsterdam zijn uitstekend bereikbaar met de auto en het openbaar vervoer.\n\nDe beschikbare appartementen in het Jaagpad zijn gasloos en energiezuinig, met woonoppervlaktes van circa 102 tot 196 m². Dankzij de grote variatie in indelingen is er voor iedere woonwens een passend appartement. Kies voor een ruim drie- of vierkamerappartement, of ga voor een exclusief penthouse met plafonds tot wel 4 meter hoog. Elk appartement beschikt over een ruim balkon of terras. Daarnaast is er de mogelijkheid een eigen parkeerplaats onder het complex te huren.\n\nOp Jaagpad woon je op loop- en fietsafstand van de stad. Binnen 15 minuten wandel je naar het Waagplein, en met de fiets ben je er in slechts 5 minuten. Tegelijkertijd geniet je thuis van rust, ruimte en het uitzicht over het water.\n\nBen je nieuwsgierig geworden naar wonen aan het Jaagpad? Bekijk de woningzoeker en verkooptekeningen op de projectwebsite en neem contact op met een van de betrokken makelaars voor meer informatie of een persoonlijk gesprek.", "Tussen appartement", "102 tot 116 m²", "3", { "totalUnits": 314, "availableUnits": 314, "unavailableUnits": 88, "underOptionUnits": 88 }, 11, [316, 324, 329, 335, 341, 348, 354, 359, 366, 372, 379], { "rooms": 317, "livingSpace": 318, "title": 319, "listingUrl": 320, "status": 321, "price": 322 }, 3, "105 m²", "Tussen appartement (Bouwnr. 1.00.06)", "https://www.funda.nl/detail/43199903/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 323, "rentalPrice": -1 }, "€ 579.000 v.o.n.", { "rooms": 317, "livingSpace": 318, "title": 325, "listingUrl": 326, "status": 327, "price": 328 }, "Tussen appartement (Bouwnr. 1.00.07)", "https://www.funda.nl/detail/43199911/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 323, "rentalPrice": -1 }, { "rooms": 317, "livingSpace": 330, "title": 331, "listingUrl": 332, "status": 333, "price": 334 }, "102 m²", "Tussen appartement (Bouwnr. 1.00.08)", "https://www.funda.nl/detail/43199917/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 323, "rentalPrice": -1 }, { "rooms": 317, "livingSpace": 336, "title": 337, "listingUrl": 338, "status": 339, "price": 340 }, "106 m²", "Tussen appartement (Bouwnr. 2.00.09)", "https://www.funda.nl/detail/43199923/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 323, "rentalPrice": -1 }, { "rooms": 317, "livingSpace": 342, "title": 343, "listingUrl": 344, "status": 345, "price": 346 }, "103 m²", "Tussen appartement (Bouwnr. 1.01.17)", "https://www.funda.nl/detail/43199928/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 347, "rentalPrice": -1 }, "€ 585.000 v.o.n.", { "rooms": 317, "livingSpace": 318, "title": 349, "listingUrl": 350, "status": 351, "price": 352 }, "Tussen appartement (Bouwnr. 1.02.26)", "https://www.funda.nl/detail/43199927/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 353, "rentalPrice": -1 }, "€ 587.500 v.o.n.", { "rooms": 317, "livingSpace": 342, "title": 355, "listingUrl": 356, "status": 357, "price": 358 }, "Tussen appartement (Bouwnr. 1.02.27)", "https://www.funda.nl/detail/43199929/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 353, "rentalPrice": -1 }, { "rooms": 317, "livingSpace": 360, "title": 361, "listingUrl": 362, "status": 363, "price": 364 }, "113 m²", "Tussen appartement (Bouwnr. 2.00.07)", "https://www.funda.nl/detail/43199924/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 365, "rentalPrice": -1 }, "€ 588.500 v.o.n.", { "rooms": 317, "livingSpace": 342, "title": 367, "listingUrl": 368, "status": 369, "price": 370 }, "Tussen appartement (Bouwnr. 1.04.47)", "https://www.funda.nl/detail/43199925/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 371, "rentalPrice": -1 }, "€ 595.000 v.o.n.", { "rooms": 317, "livingSpace": 373, "title": 374, "listingUrl": 375, "status": 376, "price": 377 }, "116 m²", "Tussen appartement (Bouwnr. 2.00.08)", "https://www.funda.nl/detail/43199926/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 378, "rentalPrice": -1 }, "€ 596.000 v.o.n.", { "rooms": 317, "livingSpace": 360, "title": 380, "listingUrl": 381, "status": 382, "price": 383 }, "Tussen appartement (Bouwnr. 2.03.42)", "https://www.funda.nl/detail/43199920/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 384, "rentalPrice": -1 }, "€ 599.000 v.o.n.", { "globalId": 386, "projectId": 5, "price": 387, "title": 212, "description": 389, "name": 390, "livingArea": 391, "numberOfRooms": 225, "buildingType": 206, "thumbnailUrl": 226, "availability": 392, "listings": 394 }, 7744521, { "sellingPrice": 388, "rentalPrice": -1 }, "€ 805.000 - € 885.000 v.o.n.", "Het Jaagpad bevindt zich in de laatste verkoopfase. Van alle woningtypes zijn nog enkele appartementen beschikbaar, waaronder de hoekappartementen met een unieke ligging en indeling.Deze exclusieve woningen onderscheiden zich door hun speelse indeling en unieke ligging op de hoek van het gebouw. Dankzij lichtinval van drie zijden geniet je hier van een heerlijk ruimtelijk gevoel, de hele dag door.\n\nMet een woonoppervlakte van 142 tot 159 m² en een royaal balkon of terras bieden de hoekappartementen volop leefcomfort, zowel binnen als buiten. Elk appartement beschikt over een eigen parkeerplaats in de ondergelegen garage en is beschikbaar vanaf € 805.000,-.\n\nOp een unieke plek in Alkmaar, direct aan het Noordhollandsch Kanaal en op korte afstand van het historische stadscentrum, wordt woonproject Jaagpad gerealiseerd. In de eerste fase komen diverse moderne koopappartementen beschikbaar die comfort, duurzaamheid en een prachtig uitzicht combineren.\n\nAlkmaar is veel meer dan de bekende kaasstad. Het sfeervolle centrum biedt een rijk aanbod aan winkels, restaurants en gezellige terrassen. Bovendien woon je hier op een strategische locatie: Haarlem en Amsterdam zijn uitstekend bereikbaar met de auto en het openbaar vervoer.\n\nDe beschikbare appartementen in het Jaagpad zijn gasloos en energiezuinig, met woonoppervlaktes van circa 102 tot 196 m². Dankzij de grote variatie in indelingen is er voor iedere woonwens een passend appartement. Kies voor een ruim drie- of vierkamerappartement, of ga voor een exclusief penthouse met plafonds tot wel 4 meter hoog. Elk appartement beschikt over een ruim balkon of terras. Daarnaast is er de mogelijkheid een eigen parkeerplaats onder het complex te huren.\n\nOp Jaagpad woon je op loop- en fietsafstand van de stad. Binnen 15 minuten wandel je naar het Waagplein, en met de fiets ben je er in slechts 5 minuten. Tegelijkertijd geniet je thuis van rust, ruimte en het uitzicht over het water.\n\nBen je nieuwsgierig geworden naar wonen aan het Jaagpad? Bekijk de woningzoeker en verkooptekeningen op de projectwebsite en neem contact op met een van de betrokken makelaars voor meer informatie of een persoonlijk gesprek.", "Hoek appartement", "142 tot 159 m²", { "totalUnits": 393, "availableUnits": 393, "unavailableUnits": 88, "underOptionUnits": 88 }, 5, [395, 401, 406, 412, 419], { "rooms": 231, "livingSpace": 241, "title": 396, "listingUrl": 397, "status": 398, "price": 399 }, "Hoek appartement (Bouwnr. 3.02.26)", "https://www.funda.nl/detail/43199906/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 400, "rentalPrice": -1 }, "€ 805.000 v.o.n.", { "rooms": 231, "livingSpace": 241, "title": 402, "listingUrl": 403, "status": 404, "price": 405 }, "Hoek appartement (Bouwnr. 3.03.36)", "https://www.funda.nl/detail/43199992/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 400, "rentalPrice": -1 }, { "rooms": 231, "livingSpace": 241, "title": 407, "listingUrl": 408, "status": 409, "price": 410 }, "Hoek appartement (Bouwnr. 3.04.46)", "https://www.funda.nl/detail/43199907/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 411, "rentalPrice": -1 }, "€ 810.000 v.o.n.", { "rooms": 231, "livingSpace": 413, "title": 414, "listingUrl": 415, "status": 416, "price": 417 }, "159 m²", "Hoek appartement (Bouwnr. 3.05.54)", "https://www.funda.nl/detail/43199909/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 418, "rentalPrice": -1 }, "€ 879.000 v.o.n.", { "rooms": 231, "livingSpace": 413, "title": 420, "listingUrl": 421, "status": 422, "price": 423 }, "Hoek appartement (Bouwnr. 3.06.58)", "https://www.funda.nl/detail/43199905/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 424, "rentalPrice": -1 }, "€ 885.000 v.o.n.", { "globalId": 426, "projectId": 5, "price": 427, "title": 212, "description": 429, "name": 430, "livingArea": 431, "numberOfRooms": 225, "buildingType": 207, "thumbnailUrl": 432, "availability": 433, "listings": 435 }, 7439205, { "sellingPrice": 428, "rentalPrice": -1 }, "€ 1.025.000 - € 1.349.000 v.o.n.", "Het Jaagpad bevindt zich in de laatste verkoopfase. Van alle woningtypes zijn nog enkele appartementen beschikbaar, waaronder de exclusieve penthouses met een unieke ligging en royale indeling.\n\nDeze bijzondere woningen bevinden zich op de hoogste verdieping van het gebouw en onderscheiden zich door hun luxe afwerking en een indrukwekkend uitzicht over het Noordhollandsch Kanaal en de stad Alkmaar. Dankzij grote raampartijen aan meerdere zijden geniet je hier de hele dag van een overvloed aan natuurlijk licht en een fantastisch ruimtelijk gevoel.\n\nMet een woonoppervlakte van 154 tot 196 m² en een royaal balkon of terras bieden de penthouses volop leefcomfort, zowel binnen als buiten. Elk penthouse beschikt over een eigen parkeerplaats in de ondergelegen garage en is beschikbaar vanaf € 1.025.000,-.\n\nOp een unieke plek in Alkmaar, direct aan het Noordhollandsch Kanaal en op korte afstand van het historische stadscentrum, wordt woonproject Jaagpad gerealiseerd. In de eerste fase komen diverse moderne koopappartementen beschikbaar die comfort, duurzaamheid en een prachtig uitzicht combineren.\n\nAlkmaar is veel meer dan de bekende kaasstad. Het sfeervolle centrum biedt een rijk aanbod aan winkels, restaurants en gezellige terrassen. Bovendien woon je hier op een strategische locatie: Haarlem en Amsterdam zijn uitstekend bereikbaar met de auto en het openbaar vervoer.\n\nDe beschikbare appartementen in het Jaagpad zijn gasloos en energiezuinig, met woonoppervlaktes van circa 102 tot 196 m². Dankzij de grote variatie in indelingen is er voor iedere woonwens een passend appartement. Kies voor een ruim drie- of vierkamerappartement, of ga voor een exclusief penthouse met plafonds tot wel 4 meter hoog. Elk appartement beschikt over een ruim balkon of terras. Daarnaast is er de mogelijkheid een eigen parkeerplaats onder het complex te huren.\n\nOp Jaagpad woon je op loop- en fietsafstand van de stad. Binnen 15 minuten wandel je naar het Waagplein, en met de fiets ben je er in slechts 5 minuten. Tegelijkertijd geniet je thuis van rust, ruimte en het uitzicht over het water.\n\nBen je nieuwsgierig geworden naar wonen aan het Jaagpad? Bekijk de woningzoeker en verkooptekeningen op de projectwebsite en neem contact op met een van de betrokken makelaars voor meer informatie of een persoonlijk gesprek.", "Penthouse appartementen", "154 tot 196 m²", "https://cloud.funda.nl/valentina_media/204/264/656_360.jpg", { "totalUnits": 434, "availableUnits": 434, "unavailableUnits": 88, "underOptionUnits": 88 }, 2, [436, 443], { "rooms": 231, "livingSpace": 437, "title": 438, "listingUrl": 439, "status": 440, "price": 441 }, "154 m²", "Penthouse Jaagpad (Bouwnr. 2.07.68)", "https://www.funda.nl/detail/43884603/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 442, "rentalPrice": -1 }, "€ 1.025.000 v.o.n.", { "rooms": 231, "livingSpace": 444, "title": 445, "listingUrl": 446, "status": 447, "price": 448 }, "196 m²", "Penthouse Jaagpad (Bouwnr. 3.07.59)", "https://www.funda.nl/detail/43884600/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 449, "rentalPrice": -1 }, "€ 1.349.000 v.o.n.", { "globalId": 451, "projectId": 5, "price": 452, "title": 212, "description": 453, "name": 454, "livingArea": 330, "numberOfRooms": 312, "buildingType": 206, "thumbnailUrl": 455, "availability": 456, "listings": 458 }, 6655824, { "sellingPrice": 323, "rentalPrice": -1 }, "AAPPARTEMENTEN JAAGPAD ALKMAAR – TE KOOP! \n\nAan het Noordhollandsch Kanaal, op steenworp afstand van het centrum van Alkmaar wordt een uniek project gerealiseerd. Hier verrijzen in de komende jaren in totaal 411 appartementen. De aantrekkelijke ligging met uitzicht over het water, de parkeergelegenheid direct onder de complexen en een ruim balkon of terras zorgen hier voor ontspannen en gemoedelijk wonen. \n\nAlkmaar staat bekend als dé kaasstad van Nederland en is natuurlijk veel meer dan dat! Het heeft een prachtig oud centrum met gezellige winkelstraatjes, een groot aanbod aan horeca- en uitgaansgelegenheden en een ideale ligging ten opzichte van grote steden als Haarlem en Amsterdam die zowel per auto als met het openbaar vervoer uitstekend bereikbaar zijn. \n\nJaagpad biedt een ruime keuze aan gasloze, energiezuinige appartementen in diverse prijsklassen. In de eerste fase zullen 183 koopappartementen worden gerealiseerd. Variërend in oppervlakte van circa 55 tot en met 160 m² en verdeeld over zo’n 70 verschillende woningtypes. Zo is bijna ieder appartement uniek. Kies voor een compact tweekamerappartement, een ruim drie- of vierkamerappartement of een penthouse met plafondhoogte van maar liefst 4 meter. Mooier wordt het niet! \n\nVanaf Jaagpad sta je binnen 15 wandelminuten op het Waagplein en op de fiets ben je er zelfs binnen vijf minuten. Kom wonen aan Jaagpad en geniet van de unieke ligging aan het Noordhollandsch Kanaal met balkon of terras op het zuiden! \n\nHeb je interesse in Jaagpad? Bekijk de woningzoeker en verkooptekeningen op de projectwebsite en schrijf je in!\n\nLET OP: De getoonde impressies dienen ter sfeerillustratie en kunnen afwijken van de daadwerkelijke indeling en afwerking van de betreffende eenheid.", "3-kamer appartement type 24", "https://cloud.funda.nl/valentina_media/170/501/320_360.jpg", { "totalUnits": 457, "availableUnits": 457, "unavailableUnits": 88, "underOptionUnits": 88 }, 1, [459], { "rooms": 317, "livingSpace": 330, "title": 460, "listingUrl": 461, "status": 462, "price": 463 }, "Jaagpad Bouwnummer 1.00.08", "https://www.funda.nl/detail/42000250/", { "value": 236, "isAvailable": 237 }, { "sellingPrice": 323, "rentalPrice": -1 }, { "lat": 465, "lng": 466 }, 52.627223339135185, 4.761241514663638, { "blikvanger": -1, "openHouseDates": 468, "nvmOpenHouseDates": 469 }, [], [], { "fullUrl": 471, "relativeUrl": 472 }, "https://www.funda.nl/detail/nieuwbouw/alkmaar/project-jaagpad/42062736/", "/detail/nieuwbouw/alkmaar/project-jaagpad/42062736/", "https://help.funda.nl:443/s/mef?globalID=6617373&returnURL=https%3a%2f%2fwww.funda.nl%2fdetail%2fnieuwbouw%2f42062736%2f&brokerID=12016", { "targetingOptions": 475 }, { "postcode": 476, "plaats": 477, "provincie": 478, "woonoppervlakte": 479, "vraagprijs": 480, "hoofdaanbieder": 481, "bouwvorm": 482, "branchevereniging": 483, "soortaanbieding": 484, "tinyid": 485, "vraagprijsrange": 486, "openhuis": 487, "gemeente": 477, "buurt": 488, "soortaanbod": 482, "adgroup": 489, "status": 490, "taal": 491, "globalid": 492 }, "1821be", "alkmaar", "noordholland", "102", "579000", "12016", "nieuwbouw", "nvm", "koop", "42062736", "550000", "true", "schermereilandenomval", "b", "beschikbaar", "nl", "6617373", { "global_id": 5, "listing_askingprice": 21, "listing_offering_type": 482, "listing_type": 494, "listing_status": 490, "listing_postal_code": 495, "listing_place": 13, "brokers": 496, "broker_id": 498, "broker_association": 483, "main_broker_id": 498, "main_broker_association": 483 }, "newly_built_project", "1821BE", [497, 499], { "broker_id": 498, "broker_association": 483 }, 12016, { "broker_id": 500, "broker_association": 483 }, 12169, "/detail/nieuwbouw/42062736/", "https://jaagpad-alkmaar.nl/", "https://service.pdok.nl/kadaster/kadastralekaart/wms/v5_0", ["Reactive", 505], { "$snuxt-i18n-meta": 506, "$sfunda.shell.state.auth.token-set": -1, "$spage-view-id": 507, "$sfunda.shell.state.auth.user": -1, "$sfavourites-saved-6617373": -1, "$sfavourites-pending-6617373": 18 }, {}, "fe81d074-e002-4c4c-bcf9-262f6d96497a", ["Set"], ["ShallowReactive", 510], { "cachedProjectData_nl": -1, "$2zmeiWOsh5": -1, "6617373-contactBlock-contact-flows": -1 }] - -function parseNuxtData(data: unknown[], offset: number = 0) { - let item = data[offset]; - - if (typeof item === "string" || typeof item === "number" || typeof item === "boolean" || typeof item === "undefined") { - return item; - } - - if (Array.isArray(item)) { - if (item[0] === "ShallowReactive") { - return parseNuxtData(data, item[1]); - } - - let arr = []; - for (const idx of item) { - arr.push(parseNuxtData(data, idx)) - } - - return arr; - } - - if (typeof item === 'object' && item !== null) { - let obj: Record = {} - for (const [key, value] of Object.entries(item)) { - obj[key] = parseNuxtData(data, parseInt(value)); - } - - return obj; - } - - throw new Error(`Unsupported item type: ${item}`) -} - -console.log(parseNuxtData(a, 4).projectListings.objectTypes)