From 7589f20a181da0f278d5e48966027f070d48a435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brockm=C3=B6ller?= Date: Sat, 27 Sep 2025 09:43:24 +0200 Subject: [PATCH] Add sparkasse immobilien (#199) --- lib/provider/sparkasse.js | 46 +++++++++++++++++++++++++++++++++ test/provider/sparkasse.test.js | 37 ++++++++++++++++++++++++++ test/provider/testProvider.json | 4 +++ 3 files changed, 87 insertions(+) create mode 100755 lib/provider/sparkasse.js create mode 100644 test/provider/sparkasse.test.js diff --git a/lib/provider/sparkasse.js b/lib/provider/sparkasse.js new file mode 100755 index 0000000..2a5627e --- /dev/null +++ b/lib/provider/sparkasse.js @@ -0,0 +1,46 @@ +import { isOneOf, buildHash } from '../utils.js'; +import checkIfListingIsActive from '../services/listings/listingActiveTester.js'; +let appliedBlackList = []; + +function normalize(o) { + const originalId = o.id.split('/').pop().replace('.html', ''); + const id = buildHash(originalId, o.price); + const size = o.size?.replace(' Wohnfläche', '') ?? null; + const title = o.title || 'No title available'; + const link = o.link != null ? `https://immobilien.sparkasse.de${o.link}` : config.url; + return Object.assign(o, { id, size, title, link }); +} +function applyBlacklist(o) { + const titleNotBlacklisted = !isOneOf(o.title, appliedBlackList); + const descNotBlacklisted = !isOneOf(o.description, appliedBlackList); + return titleNotBlacklisted && descNotBlacklisted; +} +const config = { + url: null, + crawlContainer: '.estate-list-item-row', + sortByDateParam: 'sortBy=date_desc', + waitForSelector: 'body', + crawlFields: { + id: 'div[data-testid="estate-link"] a@href', + title: 'h3 | trim', + price: '.estate-list-price | trim', + size: '.estate-mainfact:first-child span | trim', + address: 'h6 | trim', + image: '.estate-list-item-image-container img@src', + link: 'div[data-testid="estate-link"] a@href', + }, + normalize: normalize, + filter: applyBlacklist, + activeTester: checkIfListingIsActive, +}; +export const init = (sourceConfig, blacklist) => { + config.enabled = sourceConfig.enabled; + config.url = sourceConfig.url; + appliedBlackList = blacklist || []; +}; +export const metaInformation = { + name: 'Sparkasse Immobilien', + baseUrl: 'https://immobilien.sparkasse.de/', + id: 'sparkasse', +}; +export { config }; diff --git a/test/provider/sparkasse.test.js b/test/provider/sparkasse.test.js new file mode 100644 index 0000000..ac65e4f --- /dev/null +++ b/test/provider/sparkasse.test.js @@ -0,0 +1,37 @@ +import * as similarityCache from '../../lib/services/similarity-check/similarityCache.js'; +import { get } from '../mocks/mockNotification.js'; +import { mockFredy, providerConfig } from '../utils.js'; +import { expect } from 'chai'; +import * as provider from '../../lib/provider/sparkasse.js'; + +describe('#sparkasse testsuite()', () => { + after(() => { + similarityCache.stopCacheCleanup(); + }); + + it('should test sparkasse provider', async () => { + const Fredy = await mockFredy(); + provider.init(providerConfig.sparkasse, []); + + const fredy = new Fredy(provider.config, null, provider.metaInformation.id, 'sparkasse', similarityCache); + const listing = await fredy.execute(); + + expect(listing).to.be.a('array'); + const notificationObj = get(); + expect(notificationObj).to.be.a('object'); + expect(notificationObj.serviceName).to.equal('sparkasse'); + notificationObj.payload.forEach((notify) => { + /** check the actual structure **/ + expect(notify.id).to.be.a('string'); + expect(notify.price).to.be.a('string'); + expect(notify.size).to.be.a('string'); + expect(notify.title).to.be.a('string'); + expect(notify.link).to.be.a('string'); + expect(notify.address).to.be.a('string'); + /** check the values if possible **/ + expect(notify.size).that.does.include('m²'); + expect(notify.title).to.be.not.empty; + expect(notify.address).to.be.not.empty; + }); + }); +}); diff --git a/test/provider/testProvider.json b/test/provider/testProvider.json index 442bcbd..3fbd0d6 100644 --- a/test/provider/testProvider.json +++ b/test/provider/testProvider.json @@ -32,6 +32,10 @@ "url": "https://www.neubaukompass.de/neubau-immobilien/duesseldorf-region/eigentumswohnung/", "enabled": true }, + "sparkasse": { + "url": "https://immobilien.sparkasse.de/immobilien/treffer?marketingType=buy&objectType=flat&perimeter=10&usageType=residential&zipCityEstateId=62782__Hamburg", + "enabled": true + }, "wgGesucht": { "url": "https://www.wg-gesucht.de/wg-zimmer-in-Duesseldorf.30.0.1.0.html", "enabled": true