{"description":"Searches Das Örtliche, the German phone directory, for businesses by trade or name in a city or postcode: name, category, address, public phone number, whether it is open now with the opening text, and a link to the entry. Returns about 30 entries from the A–Z list (two result pages). The paid 'Premiumtreffer (Anzeigen)' entries are dropped by default; include_ads keeps them, marked sponsored.","effect":"read","id":"dasoertliche.de/search-businesses","keywords":["das örtliche","telefonbuch","telefonnummer","branchen","firmen","adresse","öffnungszeiten","zahnarzt","handwerker","phone book","phone number","local business","directory","opening hours"],"output":{"schema":{"properties":{"businesses":{"items":{"properties":{"address":{"type":["string","null"]},"category":{"type":["string","null"]},"name":{"type":"string"},"open_now":{"description":"null when the entry shows no opening hours","type":["boolean","null"]},"opening":{"description":"As Das Örtliche shows it, e.g. '24 h geöffnet', 'öffnet am Montag'","type":["string","null"]},"phone":{"description":"The business's public number","type":["string","null"]},"sponsored":{"description":"A paid premium entry (only with include_ads)","type":"boolean"},"url":{"type":"string"}},"type":"object"},"type":"array"},"city":{"type":"string"},"keyword":{"type":"string"}},"required":["keyword","city","businesses"],"type":"object"},"value":"let $ads = params.include_ads == `true`, $org = steps.search[].organic[] || `[]`, $orgUrls = steps.search[].organic[].href || `[]` in {keyword: params.keyword, city: params.city, businesses: [($ads && map(&merge((let $tc = times_class || '' in {name: name, category: category || `null`, address: address || `null`, phone: (phone && trim(replace(phone, 'Tel.', ''))) || `null`, open_now: (`[[\"opnopen\", true], [\"opnclosed\", false]]`[?contains($tc, @[0])] | [0][1]), opening: times || `null`, url: href}), {sponsored: `true`}), (steps.search[0].all || `[]`)[?!contains($orgUrls, href)])) || `[]`, map(&merge((let $tc = times_class || '' in {name: name, category: category || `null`, address: address || `null`, phone: (phone && trim(replace(phone, 'Tel.', ''))) || `null`, open_now: (`[[\"opnopen\", true], [\"opnclosed\", false]]`[?contains($tc, @[0])] | [0][1]), opening: times || `null`, url: href}), {sponsored: `false`}), $org)][]}"},"params":{"additionalProperties":false,"properties":{"city":{"description":"City or postcode, e.g. 'Berlin', 'Köln', '80331'","maxLength":60,"minLength":2,"type":"string"},"include_ads":{"default":false,"description":"Also return the paid premium entries (marked sponsored)","type":"boolean"},"keyword":{"description":"Trade or business name, e.g. 'Zahnarzt', 'Elektriker', 'Apotheke', 'Bäckerei Müller'","maxLength":60,"minLength":2,"type":"string"}},"required":["keyword","city"],"type":"object"},"provenance":{"method":"browser-inspect","notes":"The homepage search form (name search_nat: kw, ci, hidden form_name=search_nat) loads /?form_name=search_nat&kw=…&ci=…; its paging links add recFrom=26, 51, … (25 entries per page). Each entry is div.hit with a.hitlnk_name (name and detail link), .category, address, .phoneblock span ('Tel. …'), and .hitlnk_times whose class is opnopen or opnclosed. Page 1 starts with paid entries under div.headline02.filter headings 'Premiumtreffer (Anzeigen)' and 'Weitere Premiumtreffer (Anzeigen)'; the A–Z list follows div.headline02 'A - Z Trefferliste' (for Zahnarzt Berlin: 21 paid, 5 A–Z on page 1, 25 A–Z on page 2). The recipe keeps the entries after that heading from both pages; include_ads adds page 1's paid entries, marked. No hits, or a page past the last one, answers HTTP 410 with an HTML page without entries; the recipe accepts 410 as an empty page. Ratings are drawn by a script (showRatings) and are left out.","recorded_at":"2026-11-07T21:57:00+01:00","recorded_by":"C4"},"requires_login":false,"schema":"https://wield.run/schema/recipe/v1.json","site":{"country":"DE","id":"dasoertliche.de","language":"de","name":"Das Örtliche","origin":"https://www.dasoertliche.de","origins":["https://www.dasoertliche.de"]},"steps":[{"delay_ms":300,"description":"Das Örtliche's search (the homepage form search_nat: kw, ci), results 1–25 and 26–50 (recFrom), as the page's own paging links. Paid premium entries come first under 'Premiumtreffer (Anzeigen)' headings; the A–Z list follows the 'A - Z Trefferliste' heading.","expect":{"content_type":"html","status":[200,410]},"extract":{"html_items":{"all":{"fields":{"address":{"selector":"address"},"category":{"selector":".category"},"href":{"attr":"href","selector":"a.hitlnk_name"},"name":{"selector":"a.hitlnk_name"},"phone":{"selector":".phoneblock span"},"times":{"selector":".hitlnk_times"},"times_class":{"attr":"class","selector":".hitlnk_times"}},"max":30,"selector":"div.hit"},"organic":{"fields":{"address":{"selector":"address"},"category":{"selector":".category"},"href":{"attr":"href","selector":"a.hitlnk_name"},"name":{"selector":"a.hitlnk_name"},"phone":{"selector":".phoneblock span"},"times":{"selector":".hitlnk_times"},"times_class":{"attr":"class","selector":".hitlnk_times"}},"max":25,"selector":"div.headline02:not(.filter) ~ div.hit"}}},"foreach":{"as":"from","in":"[`1`, `26`]","max":2},"id":"search","request":{"headers":{"Accept":"text/html"},"method":"GET","query":{"ci":"{{params.city}}","form_name":"search_nat","kw":"{{params.keyword}}","recFrom":"{{from}}"},"url":"/"}}],"task":"Find businesses and phone numbers by keyword and city","tos":{"notes":"robots.txt allows everything. Two requests per call (the first two result pages, 300 ms apart); no calls, e-mails or reverse lookups. Business phone numbers and addresses are the public entries the directory publishes.","reviewed":false},"verify":{"checks":["length(output.businesses) >= `20`","length(output.businesses[?sponsored]) == `0`","length(output.businesses[?starts_with(url, 'https://www.dasoertliche.de/?form_name=detail')]) == length(output.businesses)","length(output.businesses[?phone != `null`]) > `15`","length(output.businesses[?contains(address || '', 'Berlin')]) == length(output.businesses)"],"example_params":{"city":"Berlin","keyword":"Zahnarzt"},"max_ms":5000},"version":1}