您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A script with the goal of enriching funda.nl and pararius.nl sites with information about the listing from official sources
// ==UserScript== // @name housingEnricherNL // @namespace com.parker.david // @version V0.0.9 // @description A script with the goal of enriching funda.nl and pararius.nl sites with information about the listing from official sources // @author David Parker // @match https://www.funda.nl/zoeken/huur* // @match https://www.funda.nl/zoeken/koop* // @match https://www.pararius.nl/koopwoningen* // @match https://www.pararius.nl/huurwoningen* // @icon https://www.google.com/s2/favicons?sz=64&domain=funda.nl // @grant GM_xmlhttpRequest // @connect www.ep-online.nl // @connect www.wozwaardeloket.nl // ==/UserScript== //switching stuff for old vs new funda //https://stackoverflow.com/questions/48587922/using-the-same-userscript-to-run-different-code-at-different-urls 'use strict'; const labelColor = new Map([ ['A+++', '#00A54E'], ['A++', '#4CB948'], ['A+', '#BFD72F'], ['A', '#FFF100'], ['B', '#FDB914'], ['C', '#F56E20'], ['D', "#EF1C22"], ['E', "#EF1C22"], ['F', "#EF1C22"], ['G', "#EF1C22"], [undefined, "#D8A3DD"], ]); //debugger; const eponline = 'https://www.ep-online.nl/Energylabel/Search' async function Request(url, opt = {}) { Object.assign(opt, { url, timeout: 5000, responseType: 'json' }) return new Promise((resolve, reject) => { opt.onerror = opt.ontimeout = reject opt.onload = resolve GM_xmlhttpRequest(opt) }) } function extractPostcode(base) { var parts = base.split(' '); return parts[0] + parts[1]; } function extractAddress(base) { if (!/\d/.test(base)) return undefined //get last number var number = base.match('\(\\d\+\)\(\?\!\.\*\\d\)')[0]; //get last character var letter = base.match('\[a\-zA\-Z\]\(\?\!\.\*\[a\-zA\-Z\]\)')[0]; // if ends with letter, return number+letter, else just number return (base.slice(-1) == letter) ? number + ' ' + letter : number } async function getToken() { let response = await Request(eponline, { method: 'GET' }) let parser = new DOMParser(); let responseDoc = parser.parseFromString(response.responseText, "text/html"); return responseDoc.querySelector('[name="__RequestVerificationToken"]').value; } async function getLabel(token, address, postcode) { let response = await Request(eponline, { method: 'POST', headers: { "Content-Type": "application/x-www-form-urlencoded" }, data: new URLSearchParams({ __RequestVerificationToken: token, SearchValue: `${postcode} ${address}` }) }) return extractLabel(response, address, postcode); } function extractLabel(response, address, postcode) { //todo: handle multi-page eponline results, one such example is "1072NK 2" var parser = new DOMParser(); var responseDoc = parser.parseFromString(response.responseText, "text/html"); var labelBlock = Array.from(responseDoc.querySelectorAll('.se-result-item-nta.se-sm-noborder')) .filter((doc) => { //empty = false, else true return doc.querySelector('span.sort-value-pht.text-nowrap').textContent.trim() === postcode + ' ' + address })[0] return labelBlock } function generateLabelSummary(node) { if (node === undefined) return { text: "issue getting label", label: undefined } //get the letter label let label = node.querySelector('[class*=bg-label-class-] > span').innerText.trim() // check if label is valid let Opnamedatum = Array.from(node.querySelectorAll('.se-item-description-nta')).filter(x => x.innerText.trim() === "Opnamedatum")[0].nextElementSibling.innerText.trim() if (Opnamedatum === "-") { return { text: "unofficial " + label, label: label } } //check if pre-2021 type label let energyIndex = Array.from(node.querySelectorAll('.se-item-description-nta')).filter(x => x.innerText.trim() === "EI") if (!!energyIndex.length) { return { text: "EnergyIndex: " + energyIndex[0].nextElementSibling.innerText.trim() + " (letter: " + label + ")", label: label } } // return current energy label class return { text: "EnergyLabel: " + label, label: label } } async function getWoz() { return "WIP" } async function generateWozSummary(node) { return node } function applyEnrichment(nodeToEnrich, labelSummary, wozText) { let pLabel = document.createElement('p') pLabel.textContent = labelSummary.text pLabel.style.backgroundColor = labelColor.get(labelSummary.label) nodeToEnrich.after(pLabel) // handle pWoz } async function enrich(nodes) { let token = await getToken() await Promise.all(nodes.map(async (node) => { let labelNode = await getLabel(token, node.address, node.postcode) let labelSummary = generateLabelSummary(labelNode) let wozNodes = await getWoz(node.address, node.postcode) let wozSummary = generateWozSummary(wozNodes) applyEnrichment(node.appendNode, labelSummary, wozSummary) })); } function getNodesToEnrichPararius() { let searchResultBase = document.querySelectorAll('.search-list__item--listing') return Array.from(searchResultBase) .map(node => { let address = extractAddress(node.querySelector('.listing-search-item__link--title').textContent.trim()); let postcode = extractPostcode(node.querySelector(".listing-search-item__sub-title\\'").textContent.trim()); let appendNode = node.querySelector('.listing-search-item__features') return { appendNode: appendNode, address: address, postcode: postcode }; }) } function getNodesToEnrichFunda() { let searchResultBase = document.querySelectorAll('[data-test-id="search-result-item"]') return Array.from(searchResultBase) .map(node => { let address = extractAddress(node.querySelector('[data-test-id="street-name-house-number"]').textContent.trim()); let postcode = extractPostcode(node.querySelector('[data-test-id="postal-code-city"]').textContent.trim()); let appendNode = node.querySelector('.flex-wrap.overflow-hidden') return { appendNode: appendNode, address: address, postcode: postcode }; }) } (async () => { // https://stackoverflow.com/questions/48587922/using-the-same-userscript-to-run-different-code-at-different-urls if (/funda\.nl/.test(location.hostname)) { // Run code for new funda.nl await enrich(getNodesToEnrichFunda()) } else if (/pararius\.nl/.test(location.hostname)) { // Run code for pararius.nl await enrich(getNodesToEnrichPararius()) } })().catch(err => { console.error(err); }); // process for wozwardeloket: //await fetch("https://api.pdok.nl/bzk/locatieserver/search/v3_1/suggest?q=2665BH%2C%20105&rows=10", { // "credentials": "omit", // "headers": { // "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/114.0", // "Accept": "application/json, text/plain, */*", // "Accept-Language": "en-US,en;q=0.5", // "Sec-Fetch-Dest": "empty", // "Sec-Fetch-Mode": "cors", // "Sec-Fetch-Site": "cross-site" // }, // "method": "GET", // "mode": "cors" //}); //await fetch("https://api.pdok.nl/bzk/locatieserver/search/v3_1/lookup?fl=*&id=adr-8eba3e1f7fd5d73e3f3402da85f62b7c", { // "credentials": "omit", // "headers": { // "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/114.0", // "Accept": "application/json, text/plain, */*", // "Accept-Language": "en-US,en;q=0.5", // "Sec-Fetch-Dest": "empty", // "Sec-Fetch-Mode": "cors", // "Sec-Fetch-Site": "cross-site" // }, // "method": "GET", // "mode": "cors" //}); //await fetch("https://www.wozwaardeloket.nl/wozwaardeloket-api/v1/wozwaarde/nummeraanduiding/1621200000027796", { // "credentials": "include", // "headers": { // "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/114.0", // "Accept": "application/json, text/plain, */*", // "Accept-Language": "en-US,en;q=0.5", // "Sec-Fetch-Dest": "empty", // "Sec-Fetch-Mode": "cors", // "Sec-Fetch-Site": "same-origin" // }, // "referrer": "https://www.wozwaardeloket.nl/", // "method": "GET", // "mode": "cors" //}); //{ // "properties": { // "identificatie": "1621010000027755", // "rdf_seealso": "http://bag.basisregistraties.overheid.nl/bag/id/verblijfsobject/1621010000027755", // "oppervlakte": 71, // "status": "Verblijfsobject in gebruik", // "gebruiksdoel": "woonfunctie", // "openbare_ruimte": "Dorpsstraat", // "huisnummer": 105, // "huisletter": "", // "toevoeging": "", // "postcode": "2665BH", // "woonplaats": "Bleiswijk", // "bouwjaar": 2017, // "pandidentificatie": "1621100000037510", // "pandstatus": "Pand in gebruik" // } //}