Fix Best Buy scraper picking up payment plan prices

- Add global filter in priceParser to reject monthly/payment plan prices
- Filters: "/mo", "per month", "payments starting", "4 payments", etc.
- Update Best Buy scraper to check each price element for payment terms
- Prevents scraping "$25/mo" instead of actual "$229.99" price

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
clucraft 2026-01-24 04:01:16 -05:00
parent 710e4c0483
commit 40c45b49c8
2 changed files with 34 additions and 5 deletions

View file

@ -381,11 +381,26 @@ const siteScrapers: SiteScraper[] = [
let price: ParsedPrice | null = null;
for (const selector of priceSelectors) {
const el = $(selector).first();
if (el.length) {
price = parsePrice(el.text().trim());
if (price) break;
}
const elements = $(selector);
// Check each element, skip payment plan prices (contain "/mo", "per month", etc.)
elements.each((_, el) => {
if (price) return false; // Already found a valid price
const text = $(el).text().trim();
const lowerText = text.toLowerCase();
// Skip if it looks like a monthly payment plan
if (lowerText.includes('/mo') ||
lowerText.includes('per month') ||
lowerText.includes('monthly') ||
lowerText.includes('financing')) {
return true; // Continue to next element
}
const parsed = parsePrice(text);
if (parsed) {
price = parsed;
return false; // Break the loop
}
});
if (price) break;
}
const name = $('h1.heading-5').text().trim() ||

View file

@ -37,6 +37,20 @@ export function parsePrice(text: string): ParsedPrice | null {
// Clean up the text
const cleanText = text.trim().replace(/\s+/g, ' ');
// Reject monthly payment/financing prices (e.g., "$25/mo", "per month", "4 payments", etc.)
const lowerText = cleanText.toLowerCase();
if (lowerText.includes('/mo') ||
lowerText.includes('per month') ||
lowerText.includes('monthly payment') ||
lowerText.includes('a month') ||
lowerText.includes('payments starting') ||
lowerText.includes('payment of') ||
lowerText.includes('payments of') ||
/\d+\s*payments?\b/.test(lowerText) ||
/\d+\s*mo\b/.test(lowerText)) {
return null;
}
for (const pattern of pricePatterns) {
const match = cleanText.match(pattern);
if (match && match.groups) {