Files
openclaw/tools/scrape-price.py
Clawd Bot ca9b510922 chore: align with upstream openclaw/openclaw and overlay local additions
- Reset master to upstream/main (16,697 commits)
- Overlay 2,271 local-only files (skills, tools, workspace, configs, apps)
- Restore IDENTITY.md and USER.md templates
- Build verified, gateway running, Discord working

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 07:40:46 +01:00

82 lines
2.8 KiB
Python

#!/usr/bin/env python3
"""Scrape en pris fra en URL via Scrapling. Returnerer heltal eller N/A."""
import sys, re, json
if len(sys.argv) < 2:
print("N/A"); sys.exit(1)
url = sys.argv[1]
try:
from scrapling import StealthyFetcher
except ImportError:
print("ERROR:scrapling-not-installed"); sys.exit(1)
try:
page = StealthyFetcher.fetch(url, stealthy_headers=True, auto_match=False)
except Exception as e:
print(f"ERROR:{e}"); sys.exit(1)
# Metode 1: JSON-LD structured data
for el in page.css('script[type="application/ld+json"]'):
try:
obj = json.loads(el.get().extract())
offers = obj.get('offers', {})
if isinstance(offers, list): offers = offers[0] if offers else {}
p = offers.get('price') or offers.get('lowPrice')
if p:
price = float(str(p).replace(',', '.'))
if 100 < price < 100000:
print(int(price)); sys.exit(0)
except Exception: pass
# Metode 2: itemprop="price" content attribut
for el in page.css('[itemprop="price"]'):
try:
content = el.get().extract()
m = re.search(r'content=["\']([0-9.,]+)["\']', content)
if m:
p = float(m.group(1).replace(',', '.'))
if 100 < p < 100000:
print(int(p)); sys.exit(0)
except Exception: pass
# Metode 3: Next.js __NEXT_DATA__
for el in page.css('script#__NEXT_DATA__'):
try:
raw = el.get().extract()
data = json.loads(raw.split('>', 1)[1].rsplit('<', 1)[0])
prices = []
def find_prices(obj, depth=0):
if depth > 15: return
if isinstance(obj, dict):
for k, v in obj.items():
if k in ('price', 'lowestPrice', 'minPrice', 'amount'):
try:
p = float(str(v).replace(',', '.'))
if 100 < p < 100000: prices.append(p)
except Exception: pass
else: find_prices(v, depth+1)
elif isinstance(obj, list):
for item in obj: find_prices(item, depth+1)
find_prices(data)
if prices: print(int(min(prices))); sys.exit(0)
except Exception: pass
# Metode 4: Synlig tekst (get_all_text) — undgår afbetalingspriser og SVG-data
visible = page.get_all_text(separator="\n")
# Ekskluder linjer med afdrag (kr./md, kr/måned, betalinger af)
lines = [l for l in visible.split("\n")
if not re.search(r'kr\./md|kr/m[åa]ned|betalinger\s+af', l, re.I)]
text4 = "\n".join(lines)
matches4 = re.findall(r'(\d{1,2}[.\s]?\d{3}|\d{3,5})\s*(?:\xa0|[\s\u202f])*(?:kr\.?|DKK|,-)', text4)
prices4 = []
for raw in matches4:
try:
p = float(re.sub(r'[\s.]', '', raw))
if 100 < p < 100000: prices4.append(p)
except: pass
if prices4: print(int(min(prices4))); sys.exit(0)
print("N/A")