Build1 distinct publisher3 min readUpdated
A Moscow new-build listings site cleaned up its programmatic metro and district pages with two lists of opposite shape. The shape choice, not the code, is the interesting part.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
A developer on the Russian new-build listings site podbor-minuta.ru has published how they stopped their own scraper from manufacturing pages: grouping apartments naively by scraped metro and district values produced about 193 thin, near-duplicate pages [6][1]. The fix is not a model or a rewrite, it is two filters of deliberately opposite shape, and the reason they differ is the part worth copying.
The site pre-generates one page per metro station and one per district from the database, each with its own URL, title and real apartment list [1]. Both grouping fields arrive from a scraper that copies them from other sites verbatim [2]. In the metro field that meant strings like "Tushinskaya (13 min)", with walking time glued onto the station name [3]. To a reader that is noise; to a GROUP BY it is fatal, because "Tushinskaya", "Tushinskaya (5 min)" and "Tushinskaya (13 min)" are three values and therefore three near-identical pages [4]. The district field was worse: project names such as "ZhK Sezar City", marketing fragments, and whole sentences lifted from descriptions complete with prices, areas and build stages, with real districts making up less than half the values [5]. The author's stated concern is not the pages themselves but the domain: on a young site, a pile of empty lookalikes can drag the whole thing down in search [7].
Metro is a closed set, so it gets an allow list. The team has a full reference of Moscow stations, so a cleaned value that is not in the reference produces no page at all [8]. Collapsing the duplicates is a separate move: the URL is built from the normalized name rather than the raw string, so every walking-time variant lands on one slug [9]. The exception is instructive. Transit lines are not stations, but MCD, MCK and BKL carry real search demand and thousands of apartments each, so they are kept as their own page type via a small hardcoded set of eight line keys [10][11][12].
District could not use the same medicine, because the reference is incomplete: the districts table is missing okrugs and the towns of the Moscow region, which are real groups, so an allow list would discard roughly half the good data along with the junk [13]. Open sets get block lists instead. Junk is defined by what it looks like: leading "ZhK", "MFK", "residential complex", "tower", "residences", or numbers attached to "million", "thousand", "rub", "sq m", "min", or construction words like "being built", "handed over", "phase" [14]. There is also a blunt length rule, since a district name is never a sentence: anything empty or over 60 characters is rejected [15].
Two implementation notes will save someone an afternoon. JavaScript's "\w" does not cover Cyrillic, so word continuations had to be written out as "[а-яё]*" [16]. And short stems need word boundaries, because a bare search for "dom" matches "Domodedovo" and deletes a legitimate district [17]. Both checks meet in one function that returns a display name and slug or null, and it is the only path by which geo values reach the catalog and the sitemap [18].
Worth watching: the write-up gives the pre-filter count but no post-filter count, so the actual page inventory after the gate is unstated [19]. Block lists also rot faster than allow lists, since developers keep inventing new marketing prefixes, and the missing okrug reference means district pages stay governed by pattern-matching rather than by a known universe [13][14].
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
On podbor-minuta.ru, listing pages are grouped by metro station and by district, built ahead of time from the database, each with its own URL, title and a real list of apartments.
The metro and district values come from a scraper that copies them from other sites as they are.
The metro field often contained strings like "Tushinskaya (13 min)", with the walking time glued onto the station name instead of a clean station name.
For grouping, "Tushinskaya", "Tushinskaya (5 min)" and "Tushinskaya (13 min)" count as three different values, so one station turned into several near-identical pages.
The scraper dumped project names ("ZhK Sezar City"), marketing fragments, and sometimes whole sentences from descriptions with prices, areas and build stages into the district field; real districts were less than half of the values.
Grouping naively on the scraped metro and district fields produced about 193 thin, near-duplicate pages.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Code shown, outcomes unmeasured
The mechanism is unusually well evidenced for a blog post: the actual regex, the allow-list Set, the isJunkDistrictValue guard and the resolveSeoGeoLabel resolver are reproduced, so the design claims can be read directly off the code. Everything about effect, however, rests on one author's recollection: the ~193 thin-page figure, the "less than half real districts" ratio and the ranking risk have no data behind them, and no post-filter measurement is given. Both sources are the same author on the same platform, so there is no independent corroboration.
One self-reported site
Adoption evidence is limited to the author's own property, podbor-minuta.ru, where the resolver, allow list, block list, slug cap and minimum-lot threshold are said to be in the live build. No other team, product, library or downstream user is named, and there is no package, repository or release for others to take up.
Slightly overstated framing
The article's own framing is modest and its code is on the page, so the gap is small. It is positive rather than zero because the headline problem number (about 193 thin pages) is a pre-fix figure presented without any after figure, the search-engine downgrade risk is asserted as fact, and the transit-line demand claim ("thousands of apartments", real search demand) is stated without traffic or query data. The generalized closing rule - allow-list closed sets, block-list open ones - is drawn from a single unmeasured case.
Author promotes own listings site
The write-up is by the operator of the commercial property it describes; the Russian version closes with a direct plug for podbor-minuta.ru and its daily Moscow new-build price monitoring, and the piece cross-references another of the author's articles. Publishing the same content twice on dev.to under separate member IDs also serves reach. The incentive is promotional and reputational rather than vendor- or funding-driven, and the technical content is specific enough to be checked, which keeps this in the middle of the range rather than the top.
Confident on mechanism, thin on impact
Confidence is moderate: what the code does and why the two lists have opposite shapes can be asserted with high certainty from reproduced source, and the two cluster sources agree completely. Confidence in the outcome, magnitude and generalizability is low because everything rests on one interested author, one site, and no post-change measurement.
build
The third answer: a dead-code tool allowed to say "not traced yet"1 distinct publisher
build
The money bug that survives your migration to decimals1 distinct publisher
build
A GAN beauty filter is a device budget allocation, not a feature toggle1 distinct publisher
build
A 5x publishing increase cost one site 1,000 indexed pages and every impression1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
2 articles · August 17, 2026