Files
cannaiq/backend/archive/debug-sale-price.ts
Kelly d91c55a344 feat: Add stale process monitor, users route, landing page, archive old scripts
- Add backend stale process monitoring API (/api/stale-processes)
- Add users management route
- Add frontend landing page and stale process monitor UI on /scraper-tools
- Move old development scripts to backend/archive/
- Update frontend build with new features

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 04:07:31 -07:00

114 lines
3.9 KiB
TypeScript

import { firefox } from 'playwright';
import { getRandomProxy } from './src/utils/proxyManager.js';
async function main() {
const productUrl = 'https://dutchie.com/embedded-menu/AZ-Deeply-Rooted/product/easy-tiger-live-rosin-aio-pete-s-peach';
console.log('🔍 Investigating Product with Sale Price...\n');
console.log(`URL: ${productUrl}\n`);
const proxyConfig = await getRandomProxy();
if (!proxyConfig) {
throw new Error('No proxy available');
}
console.log(`🔐 Using proxy: ${proxyConfig.server}\n`);
const browser = await firefox.launch({
headless: true,
proxy: proxyConfig
});
const context = await browser.newContext({
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0'
});
const page = await context.newPage();
try {
console.log('📄 Loading product page...');
await page.goto(productUrl, {
waitUntil: 'domcontentloaded',
timeout: 60000
});
await page.waitForTimeout(3000);
console.log('✅ Page loaded\n');
// Get the full page HTML for inspection
const html = await page.content();
// Look for price-related elements
const priceData = await page.evaluate(() => {
// Try JSON-LD structured data
const scripts = Array.from(document.querySelectorAll('script[type="application/ld+json"]'));
let jsonLdData: any = null;
for (const script of scripts) {
try {
const data = JSON.parse(script.textContent || '');
if (data['@type'] === 'Product') {
jsonLdData = data;
break;
}
} catch (e) {}
}
// Look for price elements in various ways
const priceElements = Array.from(document.querySelectorAll('[class*="price"], [class*="Price"]'));
const priceTexts = priceElements.map(el => ({
className: el.className,
textContent: el.textContent?.trim().substring(0, 100)
}));
// Get all text containing dollar signs
const pageText = document.body.textContent || '';
const priceMatches = pageText.match(/\$\d+\.?\d*/g);
// Look for strikethrough prices (often used for original price when there's a sale)
const strikethroughElements = Array.from(document.querySelectorAll('s, del, [style*="line-through"]'));
const strikethroughPrices = strikethroughElements.map(el => el.textContent?.trim());
// Look for elements with "sale", "special", "discount" in class names
const saleElements = Array.from(document.querySelectorAll('[class*="sale"], [class*="Sale"], [class*="special"], [class*="Special"], [class*="discount"], [class*="Discount"]'));
const saleTexts = saleElements.map(el => ({
className: el.className,
textContent: el.textContent?.trim().substring(0, 100)
}));
return {
jsonLdData,
priceElements: priceTexts.slice(0, 10),
priceMatches: priceMatches?.slice(0, 20) || [],
strikethroughPrices: strikethroughPrices.slice(0, 5),
saleElements: saleTexts.slice(0, 10)
};
});
console.log('💰 Price Data Found:');
console.log(JSON.stringify(priceData, null, 2));
// Take a screenshot for visual reference
await page.screenshot({ path: '/tmp/sale-price-product.png', fullPage: true });
console.log('\n📸 Screenshot saved to /tmp/sale-price-product.png');
// Save a snippet of the HTML around price elements
const priceHtmlSnippet = await page.evaluate(() => {
const priceElements = Array.from(document.querySelectorAll('[class*="price"], [class*="Price"]'));
if (priceElements.length > 0) {
return priceElements.slice(0, 3).map(el => el.outerHTML).join('\n\n');
}
return 'No price elements found';
});
console.log('\n📝 Price HTML Snippet:');
console.log(priceHtmlSnippet);
} catch (error: any) {
console.error('❌ Error:', error.message);
} finally {
await browser.close();
}
}
main().catch(console.error);