Crawler-Parser: og/product:price-Meta (toom 799 €, Hornbach) + Hornbach.ch als erste Ausland-Live-Quelle (cc)
This commit is contained in:
+19
-1
@@ -36,6 +36,22 @@ def _num(s):
|
|||||||
g=m.groups()
|
g=m.groups()
|
||||||
return float(g[0]) + (float(g[1])/100 if len(g)>1 and g[1] else 0)
|
return float(g[0]) + (float(g[1])/100 if len(g)>1 and g[1] else 0)
|
||||||
|
|
||||||
|
def clean_price(v):
|
||||||
|
v=(v or "").strip()
|
||||||
|
if not v: return None
|
||||||
|
if "," in v: v=v.replace(".","").replace(",",".")
|
||||||
|
m=re.search(r"\d+(?:\.\d+)?", v)
|
||||||
|
return float(m.group()) if m else None
|
||||||
|
|
||||||
|
def price_from_meta(h):
|
||||||
|
for pat in ("product:price:amount","og:price:amount"):
|
||||||
|
m=re.search(r'<meta[^>]+(?:property|name)=["\']'+pat+r'["\'][^>]+content=["\']([^"\']+)', h, re.I) or \
|
||||||
|
re.search(r'<meta[^>]+content=["\']([^"\']+)["\'][^>]+(?:property|name)=["\']'+pat+r'["\']', h, re.I)
|
||||||
|
if m:
|
||||||
|
p=clean_price(m.group(1))
|
||||||
|
if p: return p
|
||||||
|
return None
|
||||||
|
|
||||||
def parse(htmltext):
|
def parse(htmltext):
|
||||||
# 1) JSON-LD Offer
|
# 1) JSON-LD Offer
|
||||||
price=None; avail=None
|
price=None; avail=None
|
||||||
@@ -56,6 +72,8 @@ def parse(htmltext):
|
|||||||
low=htmltext.lower()
|
low=htmltext.lower()
|
||||||
in_store = ("vorrätig" in low or "verfügbar" in low) and not ("nicht vorrätig" in low or "nicht verfügbar" in low)
|
in_store = ("vorrätig" in low or "verfügbar" in low) and not ("nicht vorrätig" in low or "nicht verfügbar" in low)
|
||||||
online = ("in den warenkorb" in low) or ("lieferung" in low and "nicht möglich" not in low) or (avail and "instock" in avail.lower())
|
online = ("in den warenkorb" in low) or ("lieferung" in low and "nicht möglich" not in low) or (avail and "instock" in avail.lower())
|
||||||
|
if price is None:
|
||||||
|
price=price_from_meta(htmltext)
|
||||||
if price is None:
|
if price is None:
|
||||||
mp=_num(htmltext[:200000])
|
mp=_num(htmltext[:200000])
|
||||||
price=mp
|
price=mp
|
||||||
@@ -75,7 +93,7 @@ async def fetch_one(client, src):
|
|||||||
if r.status_code!=200:
|
if r.status_code!=200:
|
||||||
return {**src,"price":None,"availability":"unknown","status":r.status_code}
|
return {**src,"price":None,"availability":"unknown","status":r.status_code}
|
||||||
price, avail = parse(r.text)
|
price, avail = parse(r.text)
|
||||||
return {"chain":src["chain"],"kind":src["kind"],"productId":src["productId"],"name":src["name"],
|
return {"chain":src["chain"],"kind":src["kind"],"cc":src.get("cc","DE"),"productId":src["productId"],"name":src["name"],
|
||||||
"url":src["url"],"price":price,"availability":avail}
|
"url":src["url"],"price":price,"availability":avail}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.warning("fetch fail %s: %s", src["url"], e)
|
log.warning("fetch fail %s: %s", src["url"], e)
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ SOURCES = [
|
|||||||
"url":"https://toom.de/p/mobiles-klimageraet-portasplit-12000-btuh/9350668"},
|
"url":"https://toom.de/p/mobiles-klimageraet-portasplit-12000-btuh/9350668"},
|
||||||
{"chain":"toom","kind":"baumarkt","productId":"midea-portasplit-cool-8000","name":"Midea PortaSplit Cool 8.000 BTU",
|
{"chain":"toom","kind":"baumarkt","productId":"midea-portasplit-cool-8000","name":"Midea PortaSplit Cool 8.000 BTU",
|
||||||
"url":"https://toom.de/p/split-klimaanlage-portasplit-cool-8000btuh/10515238"},
|
"url":"https://toom.de/p/split-klimaanlage-portasplit-cool-8000btuh/10515238"},
|
||||||
|
# Ausland (live, Hornbach international – gleiche Plattform wie .de):
|
||||||
|
{"chain":"Hornbach","cc":"CH","kind":"baumarkt","productId":"midea-portasplit-12000","name":"Midea PortaSplit 12.000 BTU (CH)",
|
||||||
|
"url":"https://www.hornbach.ch/de/p/mobile-split-klimaanlage-midea-portasplit-ch-12000-btu-42m-weiss/12613899/"},
|
||||||
]
|
]
|
||||||
# Elektroketten / Online -> offizielle APIs nötig (mit Keys von Till):
|
# Elektroketten / Online -> offizielle APIs nötig (mit Keys von Till):
|
||||||
# Amazon Product Advertising API 5.0 (Access/Secret/Partner-Tag)
|
# Amazon Product Advertising API 5.0 (Access/Secret/Partner-Tag)
|
||||||
|
|||||||
Reference in New Issue
Block a user