mirror of
https://github.com/orangecoding/fredy.git
synced 2026-06-16 12:31:07 +00:00
fixing tests
This commit is contained in:
27
README.md
27
README.md
@@ -4,13 +4,13 @@
|
||||
|
||||
Searching an apartment in Germany can be a frustrating task. Not any longer though, as _Fredy_ will take over and will only notify you once new listings have been found that match your requirements.
|
||||
|
||||
_Fredy_ scrapes multiple services (Immonet, Immowelt etc.) and send new listings to you once they become available. The list of available services can easily be extended. For your convenience, _Fredy_ has a UI to help you configure your search jobs.
|
||||
_Fredy_ scrapes multiple services (Immonet, Immowelt etc.) and send new listings to you once they become available. The list of available services can easily be extended. For your convenience, _Fredy_ has a UI to help you configure your search jobs.
|
||||
|
||||
If _Fredy_ finds matching results, it will send them to you via Slack, Email, Telegram etc. (More adapters can be configured.) As _Fredy_ stores the listings it has found, new results will not be sent to you twice (and as a side-effect, _Fredy_ can show some statistics). Furthermore, _Fredy_ checks duplicates per scraping so that the same listings are not being sent twice or more when posted on various platforms (which happens more often than one might think).
|
||||
|
||||
<a href="https://www.producthunt.com/posts/fredy-find-real-estates-damn-easy?embed=true&utm_source=badge-featured&utm_medium=badge&utm_source=badge-fredy-find-real-estates-damn-easy" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=965690&theme=light&t=1747292331626" alt="Fredy - Find Real Estates Damn EasY  - Your personal real estate search bot | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
|
||||
|
||||
# Sponsorship [](https://github.com/sponsors/orangecoding)
|
||||
# Sponsorship [](https://github.com/sponsors/orangecoding)
|
||||
If you like my work, consider becoming a sponsor. I'm not expecting anybody to pay for _Fredy_ or any other Open Source Project I'm maintaining, however keep in mind, I'm doing all of this in my spare time :) Thanks.
|
||||
|
||||
[](https://jb.gg/OpenSourceSupport)
|
||||
@@ -20,9 +20,9 @@ _Fredy_ is supported by JetBrains under Open Source Support Program
|
||||
## Demo
|
||||
If you want to try out _Fredy_, you can access the demo version [here](https://fredy.orange-coding.net) 🤘
|
||||
|
||||
## Usage
|
||||
## Usage
|
||||
|
||||
- Make sure to use Node.js 22 or above
|
||||
- Make sure to use Node.js 20 or above
|
||||
- Run the following commands:
|
||||
```ssh
|
||||
yarn (or npm install)
|
||||
@@ -87,16 +87,16 @@ yarn run test
|
||||
Immoscout has implemented advanced bot detection. In order to work around this, we are using a reversed engineered version of their mobile api. See See [Immoscout Reverse Engineering Documentation](https://github.com/orangecoding/fredy/blob/master/reverse-engineered-immoscout.md)
|
||||
|
||||
# Analytics
|
||||
Fredy is completely free (and will always remain free). However, it would be a huge help if you’d allow me to collect some analytical data.
|
||||
Fredy is completely free (and will always remain free). However, it would be a huge help if you’d allow me to collect some analytical data.
|
||||
Before you freak out, let me explain...
|
||||
If you agree, Fredy will send a ping to my Mixpanel project each time it runs.
|
||||
The data includes: names of active adapters/providers, OS, architecture, Node version, and language. The information is entirely anonymous and helps me understand which adapters/providers are most frequently used.</p>
|
||||
**Thanks**🤘
|
||||
|
||||
# Docker
|
||||
Use the Dockerfile in this repository to build an image.
|
||||
# Docker
|
||||
Use the Dockerfile in this repository to build an image.
|
||||
|
||||
Example: `docker build -t fredy/fredy /path/to/your/Dockerfile`
|
||||
Example: `docker build -t fredy/fredy /path/to/your/Dockerfile`
|
||||
|
||||
Or use docker-compose:
|
||||
|
||||
@@ -106,12 +106,16 @@ Or use the container that will be built automatically.
|
||||
|
||||
`docker pull ghcr.io/orangecoding/fredy:master`
|
||||
|
||||
## Create & run a container
|
||||
## Create & run a container
|
||||
|
||||
Put your config.json into a path of your choice, such as `/path/to/your/conf/`.
|
||||
|
||||
Example: `docker create --name fredy -v /path/to/your/conf/:/conf -p 9998:9998 fredy/fredy`
|
||||
|
||||
## Logs
|
||||
|
||||
You can browse the logs with `docker logs fredy -f`.
|
||||
|
||||
### 👐 Contributing
|
||||
Thanks to all the people who already contributed!
|
||||
|
||||
@@ -121,6 +125,7 @@ Thanks to all the people who already contributed!
|
||||
|
||||
See [Contributing](https://github.com/orangecoding/fredy/blob/master/CONTRIBUTING.md)
|
||||
|
||||
## Logs
|
||||
|
||||
You can browse the logs with `docker logs fredy -f`.
|
||||
## Star History
|
||||
|
||||
[](https://www.star-history.com/#orangecoding/fredy&Date)
|
||||
|
||||
@@ -23,7 +23,7 @@ const config = {
|
||||
id: 'a@href',
|
||||
price: 'div[data-testid="cardmfe-price-testid"] | removeNewline | trim',
|
||||
size: 'div[data-testid="cardmfe-keyfacts-testid"] | removeNewline | trim',
|
||||
title: '.css-jv3zx6',
|
||||
title: 'div[data-testid="cardmfe-description-box-text-test-id"] > div:nth-of-type(2)',
|
||||
link: 'a@href',
|
||||
address: 'div[data-testid="cardmfe-description-box-address"] | removeNewline | trim',
|
||||
},
|
||||
|
||||
@@ -79,6 +79,7 @@ const PARAM_NAME_MAP = {
|
||||
geocoordinates: 'geocoordinates',
|
||||
shape: 'shape',
|
||||
sorting: 'sorting',
|
||||
newbuilding: 'newbuilding',
|
||||
};
|
||||
|
||||
const EQUIPMENT_MAP = {
|
||||
@@ -89,6 +90,7 @@ const EQUIPMENT_MAP = {
|
||||
garden: 'garden',
|
||||
guesttoilet: 'guestToilet',
|
||||
balcony: 'balcony',
|
||||
handicappedaccessible: 'handicappedAccessible',
|
||||
};
|
||||
|
||||
const REAL_ESTATE_TYPE = {
|
||||
@@ -98,6 +100,29 @@ const REAL_ESTATE_TYPE = {
|
||||
'haus-kaufen': 'housebuy',
|
||||
};
|
||||
|
||||
const WEB_PATH_TO_APARTMENT_EQUIPMENT_MAP = {
|
||||
// Category "Balkon/Terrasse"
|
||||
'wohnung-mit-balkon-mieten': { equipment: ['balcony'] },
|
||||
'wohnung-mit-garten-mieten': { equipment: ['garden'] },
|
||||
// Category "Wohnungstyp"
|
||||
'souterrainwohnung-mieten': { apartmenttypes: ['halfbasement'] },
|
||||
'erdgeschosswohnung-mieten': { apartmenttypes: ['groundfloor'] },
|
||||
'hochparterrewohnung-mieten': { apartmenttypes: ['raisedgroundfloor'] },
|
||||
'etagenwohnung-mieten': { apartmenttypes: ['apartment'] },
|
||||
'loft-mieten': { apartmenttypes: ['loft'] },
|
||||
'maisonette-mieten': { apartmenttypes: ['maisonette'] },
|
||||
'terrassenwohnung-mieten': { apartmenttypes: ['terracedflat'] },
|
||||
'penthouse-mieten': { apartmenttypes: ['penthouse'] },
|
||||
'dachgeschosswohnung-mieten': { apartmenttypes: ['roofstorey'] },
|
||||
// Category "Ausstattung"
|
||||
'wohnung-mit-garage-mieten': { equipment: ['parking'] },
|
||||
'wohnung-mit-einbaukueche-mieten': { equipment: ['builtinkitchen'] },
|
||||
'wohnung-mit-keller-mieten': { equipment: ['cellar'] },
|
||||
// Category "Merkmale"
|
||||
'neubauwohnung-mieten': { newbuilding: true },
|
||||
'barrierefreie-wohnung-mieten': { equipment: ['handicappedaccessible'] },
|
||||
};
|
||||
|
||||
export function convertWebToMobile(webUrl) {
|
||||
let url;
|
||||
try {
|
||||
@@ -112,9 +137,17 @@ export function convertWebToMobile(webUrl) {
|
||||
}
|
||||
|
||||
const realTypeKey = segments.at(-1);
|
||||
const realType = REAL_ESTATE_TYPE[realTypeKey];
|
||||
let realType = REAL_ESTATE_TYPE[realTypeKey];
|
||||
let additionalParamsFromWebPath;
|
||||
|
||||
if (!realType) {
|
||||
throw new Error(`Real estate type not found: ${realTypeKey}`);
|
||||
// Test for seo optimized apartment path (only used on the ImmoScout web app)
|
||||
if (WEB_PATH_TO_APARTMENT_EQUIPMENT_MAP[realTypeKey]) {
|
||||
additionalParamsFromWebPath = WEB_PATH_TO_APARTMENT_EQUIPMENT_MAP[realTypeKey];
|
||||
realType = REAL_ESTATE_TYPE['wohnung-mieten'];
|
||||
} else {
|
||||
throw new Error(`Real estate type not found: ${realTypeKey}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (segments.includes('shape')) {
|
||||
@@ -132,6 +165,7 @@ export function convertWebToMobile(webUrl) {
|
||||
searchType: isRadius ? 'radius' : 'region',
|
||||
realestatetype: realType,
|
||||
...(isRadius ? {} : { geocodes }),
|
||||
...additionalParamsFromWebPath,
|
||||
};
|
||||
|
||||
if (webParams.geocoordinates) {
|
||||
@@ -141,7 +175,11 @@ export function convertWebToMobile(webUrl) {
|
||||
for (const [key, val] of Object.entries(webParams)) {
|
||||
if (key === 'equipment') {
|
||||
const items = [].concat(val).flatMap((v) => `${v}`.split(','));
|
||||
mobileParams[PARAM_NAME_MAP[key]] = items.map((item) => EQUIPMENT_MAP[item.toLowerCase()]).filter(Boolean);
|
||||
const currentEquipmentParams = mobileParams[PARAM_NAME_MAP[key]];
|
||||
mobileParams[PARAM_NAME_MAP[key]] = [
|
||||
...(currentEquipmentParams ?? []),
|
||||
...items.map((item) => EQUIPMENT_MAP[item.toLowerCase()]).filter(Boolean),
|
||||
];
|
||||
} else {
|
||||
mobileParams[PARAM_NAME_MAP[key]] = val;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "fredy",
|
||||
"version": "12.0.0",
|
||||
"version": "11.2.1",
|
||||
"description": "[F]ind [R]eal [E]states [d]amn eas[y].",
|
||||
"scripts": {
|
||||
"start": "node prod.js",
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"enabled": true
|
||||
},
|
||||
"wgGesucht": {
|
||||
"url": "https://www.wg-gesucht.de/wg-zimmer-in-Duesseldorf.30.0.1.0.html?offer_filter=1&noDeact=1&city_id=30&category=0&rent_type=0&rMax=5000",
|
||||
"url": "https://www.wg-gesucht.de/wg-zimmer-in-Duesseldorf.30.0.1.0.html",
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,15 @@ describe('#immoscout-mobile URL conversion', () => {
|
||||
expect(actualMobileUrl).to.equal(expectedMobileUrl);
|
||||
});
|
||||
|
||||
// Test URL conversion of web-only SEO path
|
||||
it('should convert a SEO web path to the correct query params', () => {
|
||||
const webUrl = 'https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mit-balkon-mieten?equipment=garden';
|
||||
|
||||
const converted = convertWebToMobile(webUrl);
|
||||
const queryParams = new URL(converted).searchParams;
|
||||
expect(queryParams.get('equipment').split(',')).to.include.members(['garden', 'balcony']);
|
||||
});
|
||||
|
||||
// Test URL conversion with unsupported query parameters
|
||||
it('should remove unsupported query parameters', () => {
|
||||
const webUrl = 'https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten?minimuminternetspeed=100000';
|
||||
|
||||
Reference in New Issue
Block a user