Student Housing Watcher.
Scrapes the Studierendenwerk's private housing board, filters the new listings and remembers them in SQLite so none is handled twice — then sends a tailored email to any listing that published an address, and a Telegram ping to me.
One template, a different letter each time
Every listing gets an email within minutes of appearing. Not a form letter: the page is read for a name, and the address goes in bold, because a landlord can tell in one line whether a human read their advert. Change the fields and watch the greeting move.
No name on the page — falling back
Dear {{name}}, I read your advertisement for the room at {{address}} and would very much like to apply for it. I am a Mechatronics and Information Technology student at KIT, non-smoking and quiet, and I could move in at short notice. I would be glad to view the room at any time that suits you. Thank you for your time. Kind regards, Danylo Khobta
What gets sent
The substitution itself is unremarkable — placeholders in double braces, filled and posted over SMTP from my own address. What matters is which field is allowed to be missing. The address is always on the page, so it is always in the letter. The name often is not, and guessing one would be worse than the polite fallback.
The page that fights back
The listings live behind a login on the Studierendenwerk's private housing board, and the page they arrive on is rendered on the server and served as plain markup — almost no classes, almost no structure, nothing to select. There is nothing to query, so the data is pulled out by pattern instead.
This is the project where I actually learned regular expressions, out of necessity rather than interest, and it turned out to be one of the more portable things I have picked up — I keep noticing places it belongs.
Five minutes, on the way to ten
New listings are checked every five minutes. I am planning to slow that to ten, and the reason is not load: an email arriving the same second an advert goes up reads as a machine, and a landlord who feels processed does not reply. Being first is worth less than being plausible.
There is room to slow down because the competition is not other bots. The board has no filters, does not mark which listings are new, and sorts barely at all — so tracking it by hand means re-reading hundreds of entries to find the handful that changed. Most students give up on it. That is the whole advantage, and five minutes is already far more than enough of one.
Why the results live in Telegram
Every new listing is stored in SQLite so nothing is handled twice — and a database inside a container on a server is useless at the moment you need it. When a landlord rings back about a flat, the answer cannot require a laptop and an SSH session.
So each listing is also pushed to me as a Telegram message: the details that matter and a link. Which means the search is already in my pocket. A landlord names a street, I search the chat for it, and I know which advert we are talking about before the sentence is finished. Failures arrive on the same channel.
It became the other bot
Both the Telegram layer and the scraper were written here first, then reused whole in the Anny Seat Booker. This is the project where I found out that the second use is what makes something worth building properly.
It worked. One month from running it to a signed contract, in the season when every other student in the city is looking for the same rooms.
The repository is private. Happy to walk through the code on request.