Skip to content

Stop noise matching from eating real article content - #192

Merged
vedaant00 merged 5 commits into
mldsveda:mainfrom
mercael91:fix/issue-186
Oct 22, 2026
Merged

vedaant00 merged 5 commits into
mldsveda:mainfrom
mercael91:fix/issue-186

Conversation

@mercael91

Copy link
Copy Markdown
Contributor

Closes #186. The noise regex matched substrings inside class tokens, so names like gradient, download-guide or headline were treated as ads and real article text silently disappeared. Instead of anchoring the pattern to the whole attribute value (which silently stops matching multi-class elements such as 'content ad-banner'), the improved fix matches per word: class/id values are split on whitespace and then on '-'/'_' and only whole words are compared against the noise word set. That keeps compound noise names (ad-banner, social-share, comment-list, sidebar-widget, author-bio) and longer noise names (navigation, advert, newsletter, breadcrumb, cookie-banner) being removed, including when they appear on multi-class elements, while leaving look-alike content classes (gradient, download-guide, headline) untouched. Removed elements are guarded so a nested element already decomposed by its parent is not decomposed twice. Added regression tests covering preserved classes, still-removed noise, multi-class elements, longer noise names and noise ids.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The expanded noise vocabulary can delete legitimate content, and underscore-separated biography names are handled inconsistently.

2 open findings
What changed in this PR

Addresses #186 by replacing substring-based noise filtering in TextExtractor with word-based class and ID matching.

Changes:

  • Introduces a noise-word set and compound-name matching.
  • Guards against decomposing already-removed descendants.
  • Adds regression tests for preserved content and noise removal.
File Description
tests/​test_text_extractor_noise.py Adds preservation and noise-filtering regressions.
src/​pyscrappy/​generic/​extractors.py Reworks noise matching and guards nested removal.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/pyscrappy/generic/extractors.py Outdated
Comment thread src/pyscrappy/generic/extractors.py Outdated
Two soundness gaps in the whole-word noise matching, both reported on the
pull request review:

- the expanded word set contained neutral layout/content labels (profile,
  gallery, review, accordion, search, ...), so a single such class deleted a
  whole subtree of real text; the set now holds only names that are
  boilerplate on their own,
- "_" was normalised to "-" only after the exact-word lookup, so
  "author_bio" survived while "author-bio" was removed; the normalisation
  now happens before the lookup and both separators behave the same way.

Regression tests cover book-review, profile, gallery, accordion-content and
search-results being preserved, and underscore class/id values being removed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Legitimate content can still be deleted, decomposition guards introduce avoidable subtree searches, and promised breadcrumb filtering is missing.

2 open findings
2 resolved since last review
Previously missed (1)

In code that hasn't changed since last review

Medium severity Read _decomposed directly to avoid quadratic descendant searches

src/​pyscrappy/​generic/​extractors.py:159

On intact BeautifulSoup tags, _decomposed is absent, so getattr falls through to Tag.__getattr__, which searches descendants for that tag name. Doing this for every element can make noise removal quadratic on deeply nested pages. Read the instance dictionary directly in both decomposition guards to avoid these subtree searches.

🧠 Review effort: Balanced

Comment thread src/pyscrappy/generic/extractors.py Outdated
Comment on lines +98 to +99
"cookie",
"cookies",
"cookie",
"cookies",
"newsletter",
"pagination",
Two gaps in the noise word set, both reported on the pull request review:

- the bare words "cookie"/"cookies" deleted content that merely mentions
  cookies ("post tag-cookies", "cookie-recipe"); the cookie interface block
  is named explicitly instead ("cookie-banner", "cookie-consent"), so the
  bare word is gone from the set,
- the word "breadcrumb" was promised by this pull request but missing from
  the set, so breadcrumb blocks outside already-removed containers stayed in
  the extracted text; the exact word is now listed.

Explicit compound names match as a whole token only: prefix matching is what
used to delete real text, so a wrapper such as "cookie-banner-wrapper" is
deliberately left alone.

Regression tests cover cookie content labels being preserved, the explicit
cookie interface names still being removed, and breadcrumb blocks being
removed.
@vedaant00
vedaant00 merged commit b0785fe into mldsveda:main Oct 22, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Noise-removal regex over-matches, silently deleting real article content

3 participants