mirror of
https://github.com/R0m1k3/Priceflow.git
synced 2026-10-24 07:38:13 +02:00
fix: Add extract_text parameter to fix broken product search
**Problem:**
Previous commit changed get_page_content() to always return visible text (inner_text)
instead of HTML source. This broke product search which uses BeautifulSoup to parse
HTML with CSS selectors. Search was returning 0 results for all sites.
**Root Cause:**
- Search service uses: `soup.select(config["product_selector"])` on HTML
- But was receiving plain text instead of HTML structure
- BeautifulSoup couldn't find any product links → 0 results
**Solution: Add extract_text parameter**
Modified `get_page_content()` signature:
```python
async def get_page_content(
url: str,
use_proxy: bool = False,
wait_selector: str = None,
extract_text: bool = False # NEW parameter
) -> tuple[str, str]:
```
**Behavior:**
- `extract_text=False` (DEFAULT): Returns HTML source via `page.content()`
→ Used by search service for BeautifulSoup parsing
- `extract_text=True`: Returns visible text via `page.inner_text('body')`
→ Used by AI monitoring for price extraction
→ Includes Amazon price prepending ("PRIX DÉTECTÉ: ...")
**Changes:**
1. **browserless_service.py** (Lines 197-329)
- Added `extract_text` parameter with default `False`
- Conditional logic: if extract_text, use inner_text + Amazon extraction
- Else: use page.content() (HTML source)
- Preserves backward compatibility (default = HTML)
2. **scheduler_service.py** (Line 113)
- Added `extract_text=True` for AI monitoring
- Ensures AI gets visible text with Amazon prices
3. **search_service.py** (Line 104)
- Added `extract_text=True` for scrape_item() AI analysis
- Search itself uses default (HTML) for BeautifulSoup parsing
**Impact:**
✅ Search now works again (gets HTML for BeautifulSoup)
✅ AI monitoring gets visible text (better extraction)
✅ Amazon price extraction only runs when extract_text=True
✅ Backward compatible (default behavior = HTML)
Fixes issue where all searches returned: "Found 0 results for [site]"
This commit is contained in:
3 files changed
+45
-22
No files matched your search
@@ -194,10 +194,24 @@ class BrowserlessService:
|
|||||||
logger.warning("Could not extract Amazon price with any selector")
|
logger.warning("Could not extract Amazon price with any selector")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
async def get_page_content(self, url: str, use_proxy: bool = False, wait_selector: str = None) -> tuple[str, str]:
|
async def get_page_content(
|
||||||
|
self,
|
||||||
|
url: str,
|
||||||
|
use_proxy: bool = False,
|
||||||
|
wait_selector: str = None,
|
||||||
|
extract_text: bool = False
|
||||||
|
) -> tuple[str, str]:
|
||||||
"""
|
"""
|
||||||
Fetch page content with full stealth lifecycle.
|
Fetch page content with full stealth lifecycle.
|
||||||
Returns (html_content, screenshot_path)
|
|
||||||
|
Args:
|
||||||
|
url: URL to fetch
|
||||||
|
use_proxy: Whether to use proxy rotation
|
||||||
|
wait_selector: CSS selector to wait for before capturing
|
||||||
|
extract_text: If True, returns visible text; if False, returns HTML source
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(content, screenshot_path) where content is either HTML or visible text
|
||||||
"""
|
"""
|
||||||
context = await self.get_context(use_proxy=use_proxy)
|
context = await self.get_context(use_proxy=use_proxy)
|
||||||
page = await context.new_page()
|
page = await context.new_page()
|
||||||
@@ -291,23 +305,28 @@ class BrowserlessService:
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Extract visible text instead of raw HTML
|
# Extract content based on extract_text parameter
|
||||||
# This gets the text as rendered by JavaScript, not the HTML source
|
if extract_text:
|
||||||
try:
|
# Extract visible text for AI analysis (monitoring use case)
|
||||||
content = await page.inner_text('body')
|
try:
|
||||||
logger.info(f"Extracted {len(content)} chars of visible text from page")
|
content = await page.inner_text('body')
|
||||||
except Exception as e:
|
logger.info(f"Extracted {len(content)} chars of visible text from page")
|
||||||
# Fallback to HTML content if inner_text fails
|
except Exception as e:
|
||||||
logger.warning(f"Failed to extract inner_text, falling back to HTML: {e}")
|
# Fallback to HTML content if inner_text fails
|
||||||
content = await page.content()
|
logger.warning(f"Failed to extract inner_text, falling back to HTML: {e}")
|
||||||
|
content = await page.content()
|
||||||
|
|
||||||
# For Amazon, extract price directly and prepend to content
|
# For Amazon, extract price directly and prepend to content
|
||||||
# This helps AI by providing explicit price information
|
# This helps AI by providing explicit price information
|
||||||
if "amazon" in url.lower() and "/dp/" in url:
|
if "amazon" in url.lower() and "/dp/" in url:
|
||||||
amazon_price_text = await self._extract_amazon_price(page)
|
amazon_price_text = await self._extract_amazon_price(page)
|
||||||
if amazon_price_text:
|
if amazon_price_text:
|
||||||
content = f"PRIX DÉTECTÉ: {amazon_price_text}\n\n{content}"
|
content = f"PRIX DÉTECTÉ: {amazon_price_text}\n\n{content}"
|
||||||
logger.info(f"Prepended Amazon price to content: {amazon_price_text}")
|
logger.info(f"Prepended Amazon price to content: {amazon_price_text}")
|
||||||
|
else:
|
||||||
|
# Extract raw HTML for parsing (search use case)
|
||||||
|
content = await page.content()
|
||||||
|
logger.debug(f"Extracted {len(content)} chars of HTML from page")
|
||||||
|
|
||||||
|
|
||||||
# Take screenshot if needed for AI analysis
|
# Take screenshot if needed for AI analysis
|
||||||
|
|||||||
@@ -105,10 +105,12 @@ async def process_item_check(item_id: int):
|
|||||||
logger.info(f"Checking item: {item_data['name']} ({item_data['url']})")
|
logger.info(f"Checking item: {item_data['name']} ({item_data['url']})")
|
||||||
# Use new browserless service
|
# Use new browserless service
|
||||||
# Note: smart_scroll is handled internally by browserless_service
|
# Note: smart_scroll is handled internally by browserless_service
|
||||||
|
# extract_text=True to get visible text for AI analysis (not HTML)
|
||||||
page_text, screenshot_path = await browserless_service.get_page_content(
|
page_text, screenshot_path = await browserless_service.get_page_content(
|
||||||
item_data["url"],
|
item_data["url"],
|
||||||
use_proxy="amazon" in item_data["url"], # Simple heuristic for now
|
use_proxy="amazon" in item_data["url"], # Simple heuristic for now
|
||||||
wait_selector=item_data["selector"]
|
wait_selector=item_data["selector"],
|
||||||
|
extract_text=True # Get visible text for AI, not raw HTML
|
||||||
)
|
)
|
||||||
|
|
||||||
# Determine availability based on content presence
|
# Determine availability based on content presence
|
||||||
|
|||||||
@@ -96,10 +96,12 @@ class NewSearchService:
|
|||||||
use_proxy = config.get("requires_proxy", False) if config else False
|
use_proxy = config.get("requires_proxy", False) if config else False
|
||||||
|
|
||||||
# Use browserless to get content and screenshot
|
# Use browserless to get content and screenshot
|
||||||
html, screenshot_path = await browserless_service.get_page_content(
|
# extract_text=True to get visible text for AI analysis
|
||||||
|
page_text, screenshot_path = await browserless_service.get_page_content(
|
||||||
result.url,
|
result.url,
|
||||||
use_proxy=use_proxy,
|
use_proxy=use_proxy,
|
||||||
wait_selector=None
|
wait_selector=None,
|
||||||
|
extract_text=True # Get visible text for AI price extraction
|
||||||
)
|
)
|
||||||
|
|
||||||
if not screenshot_path:
|
if not screenshot_path:
|
||||||
@@ -107,7 +109,7 @@ class NewSearchService:
|
|||||||
|
|
||||||
# Use AI to analyze
|
# Use AI to analyze
|
||||||
from app.services.ai_service import AIService
|
from app.services.ai_service import AIService
|
||||||
ai_result = await AIService.analyze_image(screenshot_path, page_text=html)
|
ai_result = await AIService.analyze_image(screenshot_path, page_text=page_text)
|
||||||
|
|
||||||
if ai_result:
|
if ai_result:
|
||||||
extraction, _ = ai_result
|
extraction, _ = ai_result
|
||||||
|
|||||||
Reference in new issue
Block a user