BeautifulSoup

๐Œ๐ฒ ๐š๐ฉ๐ฉ๐ฌ ๐š๐ซ๐ž ๐ง๐จ๐ญ ๐š๐›๐š๐ง๐๐จ๐ง๐ฐ๐š๐ซ๐ž!

Written by  on July 10, 2026

Yesterday, #RitterRadar got some updates: first, all dependencies were refreshed (no more CVEs); then I fixed some bugs I had noticed over the past few weeks; and finally, the best news: a new feature that gives you a copyable list of the events matching your current filter.

So, for instance, if you live near Potsdam and want to see all medieval events within 50 km over the next two months – you get this:

——-

04. Juli 2026 | Kinder- und Sommerfest in Gannahall 2026 | 14641 Nauen (26 km)
04. Juli 2026 – 05. Juli 2026 | Mythologie und Handwerk des Mittelalters 2026 | 15569 Woltersdorf (47 km)
22. Aug. 2026 – 23. Aug. 2026 | Sommerfest Lรผbarser Hofkulturdiverse Konzerte | 13469 Berlin (30 km)
29. Aug. 2026 | Mittelalterliches zum Ackerbรผrgerfest | 14641 Nauen (26 km)

——-

#FastAPI #WebScraping #OpenStreetMap #Geocoding #OpenSource #EventDiscovery

URL to the GitHub-project: https://github.com/marcelpetrick/RitterRadarย if you haven’t given it a try yet โš”๏ธ๐Ÿ‰

โš”๏ธ๐Ÿ‰ ๐—ฅ๐—ถ๐˜๐˜๐—ฒ๐—ฟ๐—ฅ๐—ฎ๐—ฑ๐—ฎ๐—ฟ ๐Ÿ›ก๏ธ๐Ÿฐ๐Ÿ‡

Written by  on June 27, 2026

๐˜๐˜ฆ๐˜ข๐˜ณ๐˜ฌ๐˜ฆ๐˜ฏ, ๐˜จ๐˜ฐ๐˜ฐ๐˜ฅ ๐˜ต๐˜ณ๐˜ข๐˜ท๐˜ฆ๐˜ญ๐˜ญ๐˜ฆ๐˜ณ, ๐˜ข๐˜ฏ๐˜ฅ ๐˜ญ๐˜ฆ๐˜ฏ๐˜ฅ ๐˜ต๐˜ฉ๐˜ช๐˜ฏ๐˜ฆ ๐˜ฆ๐˜ข๐˜ณ!

๐˜™๐˜ช๐˜ต๐˜ต๐˜ฆ๐˜ณ๐˜™๐˜ข๐˜ฅ๐˜ข๐˜ณ ๐˜ช๐˜ด ๐˜ข ๐˜ค๐˜ถ๐˜ฏ๐˜ฏ๐˜ช๐˜ฏ๐˜จ ๐˜ช๐˜ฏ๐˜ด๐˜ต๐˜ณ๐˜ถ๐˜ฎ๐˜ฆ๐˜ฏ๐˜ต, ๐˜ง๐˜ฐ๐˜ณ๐˜จ๐˜ฆ๐˜ฅ ๐˜ช๐˜ฏ ๐˜ต๐˜ฉ๐˜ฆ ๐˜ง๐˜ช๐˜ณ๐˜ฆ๐˜ด ๐˜ฐ๐˜ง ๐˜—๐˜บ๐˜ต๐˜ฉ๐˜ฐ๐˜ฏ, ๐˜ต๐˜ฐ ๐˜ข๐˜ช๐˜ฅ ๐˜ต๐˜ฉ๐˜ฆ๐˜ฆ ๐˜ช๐˜ฏ ๐˜ต๐˜ฉ๐˜บ ๐˜ฏ๐˜ฐ๐˜ฃ๐˜ญ๐˜ฆ ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต: ๐˜ต๐˜ฉ๐˜ฆ ๐˜ฅ๐˜ช๐˜ด๐˜ค๐˜ฐ๐˜ท๐˜ฆ๐˜ณ๐˜บ ๐˜ฐ๐˜ง ๐˜ฎ๐˜ฆ๐˜ฅ๐˜ช๐˜ฆ๐˜ท๐˜ข๐˜ญ ๐˜ฎ๐˜ข๐˜ณ๐˜ฌ๐˜ฆ๐˜ต๐˜ด, ๐˜™๐˜ฆ๐˜ฏ๐˜ข๐˜ช๐˜ด๐˜ด๐˜ข๐˜ฏ๐˜ค๐˜ฆ ๐˜ง๐˜ข๐˜ช๐˜ณ๐˜ด, ๐˜๐˜ช๐˜ฌ๐˜ช๐˜ฏ๐˜จ ๐˜ด๐˜ฑ๐˜ฆ๐˜ค๐˜ต๐˜ข๐˜ค๐˜ญ๐˜ฆ๐˜ด, ๐˜ข๐˜ฏ๐˜ฅ ๐˜Š๐˜ฉ๐˜ณ๐˜ช๐˜ด๐˜ต๐˜ฎ๐˜ข๐˜ด ๐˜ณ๐˜ฆ๐˜ท๐˜ฆ๐˜ญ๐˜ณ๐˜ช๐˜ฆ๐˜ด ๐˜ฐ๐˜ง ๐˜ต๐˜ฉ๐˜ฆ ๐˜ข๐˜ฏ๐˜ค๐˜ช๐˜ฆ๐˜ฏ๐˜ต ๐˜ด๐˜ต๐˜บ๐˜ญ๐˜ฆ – ๐˜ข๐˜ค๐˜ณ๐˜ฐ๐˜ด๐˜ด ๐˜ต๐˜ฉ๐˜ฆ ๐˜Ž๐˜ฆ๐˜ณ๐˜ฎ๐˜ข๐˜ฏ ๐˜ญ๐˜ข๐˜ฏ๐˜ฅ๐˜ด ๐˜ข๐˜ฏ๐˜ฅ ๐˜ฃ๐˜ฆ๐˜บ๐˜ฐ๐˜ฏ๐˜ฅ.

๐˜›๐˜ฉ๐˜ช๐˜ด ๐˜ต๐˜ฐ๐˜ฐ๐˜ญ ๐˜ฅ๐˜ฐ๐˜ต๐˜ฉ ๐˜ฅ๐˜ช๐˜ด๐˜ฑ๐˜ข๐˜ต๐˜ค๐˜ฉ ๐˜ต๐˜ช๐˜ณ๐˜ฆ๐˜ญ๐˜ฆ๐˜ด๐˜ด ๐˜ธ๐˜ฆ๐˜ฃ-๐˜ค๐˜ณ๐˜ข๐˜ธ๐˜ญ๐˜ช๐˜ฏ๐˜จ ๐˜ข๐˜จ๐˜ฆ๐˜ฏ๐˜ต๐˜ด ๐˜ช๐˜ฏ๐˜ต๐˜ฐ ๐˜ต๐˜ฉ๐˜ฆ ๐˜ท๐˜ข๐˜ด๐˜ต ๐˜ฅ๐˜ช๐˜จ๐˜ช๐˜ต๐˜ข๐˜ญ ๐˜ธ๐˜ช๐˜ญ๐˜ฅ๐˜ฆ๐˜ณ๐˜ฏ๐˜ฆ๐˜ด๐˜ด. ๐˜›๐˜ฉ๐˜ฆ๐˜บ ๐˜ณ๐˜ฆ๐˜ต๐˜ถ๐˜ณ๐˜ฏ ๐˜ญ๐˜ข๐˜ฅ๐˜ฆ๐˜ฏ ๐˜ธ๐˜ช๐˜ต๐˜ฉ ๐˜ต๐˜ช๐˜ฅ๐˜ช๐˜ฏ๐˜จ๐˜ด ๐˜ฐ๐˜ง ๐˜ง๐˜ฐ๐˜ณ๐˜ต๐˜ฉ๐˜ค๐˜ฐ๐˜ฎ๐˜ช๐˜ฏ๐˜จ ๐˜ฆ๐˜ท๐˜ฆ๐˜ฏ๐˜ต๐˜ด – ๐˜ต๐˜ฉ๐˜ฆ๐˜ช๐˜ณ ๐˜ฏ๐˜ข๐˜ฎ๐˜ฆ๐˜ด, ๐˜ต๐˜ฉ๐˜ฆ๐˜ช๐˜ณ ๐˜ฅ๐˜ข๐˜ต๐˜ฆ๐˜ด, ๐˜ต๐˜ฉ๐˜ฆ๐˜ช๐˜ณ ๐˜ธ๐˜ฉ๐˜ฆ๐˜ณ๐˜ฆ๐˜ข๐˜ฃ๐˜ฐ๐˜ถ๐˜ต๐˜ด โ€” ๐˜ข๐˜ฏ๐˜ฅ ๐˜ด๐˜ต๐˜ฐ๐˜ณ๐˜ฆ ๐˜ข๐˜ญ๐˜ญ ๐˜ธ๐˜ช๐˜ต๐˜ฉ๐˜ช๐˜ฏ ๐˜ข ๐˜ญ๐˜ฐ๐˜ค๐˜ข๐˜ญ ๐˜ต๐˜ณ๐˜ฆ๐˜ข๐˜ด๐˜ถ๐˜ณ๐˜บ ๐˜ฐ๐˜ง ๐˜š๐˜˜๐˜“๐˜ช๐˜ต๐˜ฆ.

๐˜œ๐˜ฑ๐˜ฐ๐˜ฏ ๐˜ต๐˜ฉ๐˜ช๐˜ฏ๐˜ฆ ๐˜ฐ๐˜ธ๐˜ฏ ๐˜ฎ๐˜ข๐˜ค๐˜ฉ๐˜ช๐˜ฏ๐˜ฆ ๐˜ช๐˜ต ๐˜ฅ๐˜ฐ๐˜ต๐˜ฉ ๐˜ณ๐˜ฆ๐˜ฏ๐˜ฅ๐˜ฆ๐˜ณ ๐˜ข ๐˜ฎ๐˜ฐ๐˜ด๐˜ต ๐˜ฃ๐˜ฆ๐˜ข๐˜ถ๐˜ต๐˜ช๐˜ง๐˜ถ๐˜ญ ๐˜ช๐˜ฏ๐˜ต๐˜ฆ๐˜ณ๐˜ข๐˜ค๐˜ต๐˜ช๐˜ท๐˜ฆ ๐˜ฎ๐˜ข๐˜ฑ, ๐˜ธ๐˜ฉ๐˜ฆ๐˜ณ๐˜ฆ๐˜ถ๐˜ฑ๐˜ฐ๐˜ฏ ๐˜ต๐˜ฉ๐˜ฐ๐˜ถ ๐˜ฎ๐˜ข๐˜บ๐˜ฆ๐˜ด๐˜ต ๐—ณ๐—ถ๐—น๐˜๐—ฒ๐—ฟ ๐—ฏ๐˜† ๐—ฝ๐—ฒ๐—ฟ๐—ถ๐—ผ๐—ฑ (๐˜ธ๐˜ฉ๐˜ช๐˜ค๐˜ฉ ๐˜ฎ๐˜ฐ๐˜ฏ๐˜ต๐˜ฉ๐˜ด ๐˜ต๐˜ฉ๐˜ฐ๐˜ถ ๐˜ธ๐˜ช๐˜ด๐˜ฉ๐˜ฆ๐˜ด๐˜ต ๐˜ต๐˜ฐ ๐˜ด๐˜ถ๐˜ณ๐˜ท๐˜ฆ๐˜บ) ๐˜ข๐˜ฏ๐˜ฅ ๐—ณ๐—ถ๐—น๐˜๐—ฒ๐—ฟ ๐—ฏ๐˜† ๐˜€๐—ฝ๐—ฎ๐—ฐ๐—ฒ (๐˜ต๐˜ฉ๐˜บ ๐˜ฉ๐˜ฐ๐˜ฎ๐˜ฆ ๐˜ฑ๐˜ฐ๐˜ด๐˜ช๐˜ต๐˜ช๐˜ฐ๐˜ฏ ๐˜ข๐˜ฏ๐˜ฅ ๐˜ข ๐˜ณ๐˜ข๐˜ฅ๐˜ช๐˜ถ๐˜ด ๐˜ฐ๐˜ง ๐˜ต๐˜ฉ๐˜บ ๐˜ค๐˜ฉ๐˜ฐ๐˜ฐ๐˜ด๐˜ช๐˜ฏ๐˜จ, ๐˜ง๐˜ณ๐˜ฐ๐˜ฎ ๐˜ข ๐˜ด๐˜ต๐˜ฐ๐˜ฏ๐˜ฆ’๐˜ด ๐˜ต๐˜ฉ๐˜ณ๐˜ฐ๐˜ธ ๐˜ต๐˜ฐ 1024 ๐˜ญ๐˜ฆ๐˜ข๐˜จ๐˜ถ๐˜ฆ๐˜ด). ๐˜Š๐˜ญ๐˜ช๐˜ค๐˜ฌ ๐˜ถ๐˜ฑ๐˜ฐ๐˜ฏ ๐˜ข๐˜ฏ๐˜บ ๐˜ฎ๐˜ข๐˜ณ๐˜ฌ๐˜ฆ๐˜ณ ๐˜ต๐˜ฐ ๐˜ญ๐˜ฆ๐˜ข๐˜ณ๐˜ฏ ๐˜ต๐˜ฉ๐˜ฆ ๐˜ง๐˜ถ๐˜ญ๐˜ญ ๐˜ฑ๐˜ข๐˜ณ๐˜ต๐˜ช๐˜ค๐˜ถ๐˜ญ๐˜ข๐˜ณ๐˜ด. ๐˜›๐˜ฉ๐˜ฆ ๐˜ค๐˜ณ๐˜ข๐˜ธ๐˜ญ๐˜ฆ๐˜ณ ๐˜ณ๐˜ถ๐˜ฏ๐˜ฏ๐˜ฆ๐˜ต๐˜ฉ ๐˜ช๐˜ฏ ๐˜ต๐˜ฉ๐˜ฆ ๐˜ฃ๐˜ข๐˜ค๐˜ฌ๐˜จ๐˜ณ๐˜ฐ๐˜ถ๐˜ฏ๐˜ฅ; ๐˜ต๐˜ฉ๐˜ฆ ๐˜ฎ๐˜ข๐˜ฑ ๐˜ณ๐˜ฆ๐˜ง๐˜ณ๐˜ฆ๐˜ด๐˜ฉ๐˜ฆ๐˜ต๐˜ฉ ๐˜ฐ๐˜ฏ ๐˜ช๐˜ต๐˜ด ๐˜ฐ๐˜ธ๐˜ฏ ๐˜ข๐˜ค๐˜ค๐˜ฐ๐˜ณ๐˜ฅ.

๐˜•๐˜ฐ ๐˜ค๐˜ญ๐˜ฐ๐˜ถ๐˜ฅ. ๐˜•๐˜ฐ ๐˜ข๐˜ค๐˜ค๐˜ฐ๐˜ถ๐˜ฏ๐˜ต๐˜ด. ๐˜•๐˜ฐ ๐˜ฅ๐˜ข๐˜ต๐˜ข ๐˜ญ๐˜ฆ๐˜ข๐˜ท๐˜ฆ๐˜ต๐˜ฉ ๐˜ต๐˜ฉ๐˜บ ๐˜ฎ๐˜ข๐˜ค๐˜ฉ๐˜ช๐˜ฏ๐˜ฆ. ๐˜›๐˜ฉ๐˜ถ๐˜ด: ๐˜ข ๐˜ฉ๐˜ฆ๐˜ญ๐˜ฑ๐˜ฆ๐˜ณ ๐˜ต๐˜ฐ๐˜ฐ๐˜ญ ๐˜ต๐˜ฉ๐˜ข๐˜ต ๐˜ค๐˜ณ๐˜ข๐˜ธ๐˜ญ๐˜ฆ๐˜ต๐˜ฉ ๐˜ต๐˜ฉ๐˜ฆ ๐˜ธ๐˜ฆ๐˜ฃ ๐˜ธ๐˜ช๐˜ต๐˜ฉ ๐˜ค๐˜ถ๐˜ด๐˜ต๐˜ฐ๐˜ฎ ๐˜ค๐˜ณ๐˜ข๐˜ธ๐˜ญ๐˜ฆ๐˜ณ๐˜ด, ๐˜ฑ๐˜ณ๐˜ฆ๐˜ด๐˜ฆ๐˜ฏ๐˜ต๐˜ฆ๐˜ต๐˜ฉ ๐˜ต๐˜ฉ๐˜ฆ ๐˜ง๐˜ช๐˜ฏ๐˜ฅ๐˜ช๐˜ฏ๐˜จ๐˜ด, ๐˜ข๐˜ฏ๐˜ฅ ๐˜ข๐˜ญ๐˜ญ๐˜ฐ๐˜ธ๐˜ฆ๐˜ต๐˜ฉ ๐˜ต๐˜ฉ๐˜ฆ๐˜ฆ ๐˜ต๐˜ฐ ๐˜ด๐˜ช๐˜ง๐˜ต ๐˜ต๐˜ฉ๐˜ฆ๐˜ฎ ๐˜ฃ๐˜บ ๐˜ต๐˜ช๐˜ฎ๐˜ฆ ๐˜ข๐˜ฏ๐˜ฅ ๐˜ฃ๐˜บ ๐˜ฅ๐˜ช๐˜ด๐˜ต๐˜ข๐˜ฏ๐˜ค๐˜ฆ. ๐˜•๐˜ฐ๐˜ต๐˜ฉ๐˜ช๐˜ฏ๐˜จ ๐˜ฎ๐˜ฐ๐˜ณ๐˜ฆ, ๐˜ฏ๐˜ฐ๐˜ต๐˜ฉ๐˜ช๐˜ฏ๐˜จ ๐˜ญ๐˜ฆ๐˜ด๐˜ด – ๐˜ฃ๐˜ถ๐˜ต ๐˜ง๐˜ข๐˜ด๐˜ฉ๐˜ช๐˜ฐ๐˜ฏ๐˜ฆ๐˜ฅ ๐˜ธ๐˜ช๐˜ต๐˜ฉ ๐˜ค๐˜ข๐˜ณ๐˜ฆ.

——-

Also: Wir besuchen recht gerne Mittelaltermรคrkte. Jetzt ist es so, dass die Schaustellergruppen umherziehen beziehungsweise bestimmte Events an historischen Orten stattfinden. Ich wohne nicht an einem historischen Ort.

Also sucht man eine der vielen Seiten im Netz auf, die Termine auflisten. Diese sind รผber die Jahre gewachsen, und viele Seiten bieten auch Komfortfunktionen wie โ€žFilter nach Datum oder Bundeslandโ€œ an, aber:
* ๐—™๐—ฟ๐—ฎ๐—ด๐—บ๐—ฒ๐—ป๐˜๐—ถ๐—ฒ๐—ฟ๐˜‚๐—ป๐—ด: Nicht alle Seiten zeigen โ€žalle Eventsโ€œ
* Ein Filter nach Bundesland hat das Problem, dass man alles einzeln sichten muss, wenn man auch gewillt ist, Landesgrenzen zu รผberschreiten (oder eben ungefiltert, yada yada)
* ๐—™๐—ถ๐—น๐˜๐—ฒ๐—ฟ๐˜‚๐—ป๐—ด ๐—ป๐—ฎ๐—ฐ๐—ต ๐—ญ๐—ฒ๐—ถ๐˜๐—ฟ๐—ฎ๐˜‚๐—บ (Vergangenes interessiert mich nicht)

Also, wie man sieht: ein komplexer Task, wenn man sich einen Plan fรผr die nรคchsten Monate machen mรถchte. Durchaus lรถsbar, aber wie Clarence Bleicher sagt: โ€ž[..] ๐˜๐—ต๐—ฎ๐˜ ๐˜„๐—ต๐—ฒ๐—ป ๐—ต๐—ฒ ๐—ต๐—ฎ๐—ฑ ๐—ฎ ๐—ต๐—ฎ๐—ฟ๐—ฑ ๐—ท๐—ผ๐—ฏ, ๐—ต๐—ฒ ๐˜„๐—ผ๐˜‚๐—น๐—ฑ ๐—ฎ๐˜€๐˜€๐—ถ๐—ด๐—ป ๐—ถ๐˜ ๐˜๐—ผ ๐—ฎ โ€˜๐—น๐—ฎ๐˜‡๐˜† ๐—บ๐—ฎ๐—ปโ€™ ๐—ฏ๐—ฒ๐—ฐ๐—ฎ๐˜‚๐˜€๐—ฒ ๐˜๐—ต๐—ฒ๐˜† ๐˜„๐—ผ๐˜‚๐—น๐—ฑ ๐—ณ๐—ถ๐—ป๐—ฑ ๐—ฎ๐—ป ๐—ฒ๐—ฎ๐˜€๐˜† ๐˜„๐—ฎ๐˜† ๐˜๐—ผ ๐—ฑ๐—ผ ๐—ถ๐˜.โ€œ โ€“ kein Job fรผr mich ๐Ÿ™ˆ

Nun bin ich auch KEIN Webentwickler. Aber das sollte mich nicht daran hindern, โ€žRitter Radarโ€œ zu entwickeln.

Eine App, die aus mehreren Webcrawlern sowie Front- und Backend besteht. Alle bekannten Mittelaltermarkt-Seiten werden durchsucht, die Ergebnisse kommen in eine lokale Datenbank, und dann hat man die Mรถglichkeit, in einem Web-UI nach Entfernung zum Startort und Zeitraum zu filtern. Easy peasy.

BeautifulSoup, OpenStreetMap, Python, SQLite, Uvicorn, ein bisschen HTML und CSS … und fertig.

Ich habe es bisher nicht auf ein Web-Deployment getrimmt, weil ich die Arbeit der Ersteller der Mittelaltermarkt-Seiten honoriere. Wenn ich jetzt so ein Portal hosten wรผrde, wรคre ich wie Google mit den KI-Suchergebnissen: Eine Zusammenfassung drรคngt sich zwischen Nutzer und Ersteller und fรคngt so Webseiten-Traffic ab.

Daher: Einfach auf https://github.com/marcelpetrick/RitterRadar das Repository klonen und selbst bootstrappen: zwei Shell-Skripte ausfรผhren, fertig ist der Lack. โš”๏ธ๐Ÿ‰

simple webscraper for last.fm with BeautifulSoup

Written by  on September 29, 2020

tl;dr:
Simple webscraper with Python and BeautifulSoup for one user’s favorite tracks (‘loved songs’) at last.fm.
Repository: github

full text:
Looks like last.fm is shutting down its services (one feature at at time, lol). They started this process more or less ten years ago.
I’ve realized that I would miss my curated list of favorite tracks and I am also very bad at remembering, so … let’s automate the process of grabbing that information from their public page. I know, they offer a REST API, but I wanted to use once BS4.
Since I had somehow two free hours fourteen days ago, I went full-speed to some tutorials, played with the get-requests and how to parse. And then spent the last minutes parsing the received “artist+track”-string into something usable. Alltogether four hours were spent and I am amazed by the result. Of course, by leveraging three quite powerful libraries (beautifulsoup4, requests, lxml) and skipping TDD (;) I’ve reached the goal quite fast. And since the script works (my 1500 loved songs are scraped in less than 60 seconds), I will also not spend additional effort to make it “pretty”.