mirror of
https://github.com/Second-Hand-Friends/kleinanzeigen-bot.git
synced 2026-03-12 18:41:50 +01:00
add support for shipping_costs
This commit is contained in:
@@ -216,6 +216,7 @@ ad_defaults:
|
|||||||
suffix: ""
|
suffix: ""
|
||||||
price_type: NEGOTIABLE # one of: FIXED, NEGOTIABLE, GIVE_AWAY
|
price_type: NEGOTIABLE # one of: FIXED, NEGOTIABLE, GIVE_AWAY
|
||||||
shipping_type: SHIPPING # one of: PICKUP, SHIPPING, NOT_APPLICABLE
|
shipping_type: SHIPPING # one of: PICKUP, SHIPPING, NOT_APPLICABLE
|
||||||
|
shipping_costs: # e.g. 2.95
|
||||||
contact:
|
contact:
|
||||||
name: ""
|
name: ""
|
||||||
street: ""
|
street: ""
|
||||||
@@ -277,6 +278,7 @@ special_attributes:
|
|||||||
# haus_mieten.zimmer_d: value # Zimmer
|
# haus_mieten.zimmer_d: value # Zimmer
|
||||||
|
|
||||||
shipping_type: # one of: PICKUP, SHIPPING, NOT_APPLICABLE
|
shipping_type: # one of: PICKUP, SHIPPING, NOT_APPLICABLE
|
||||||
|
shipping_costs: # e.g. 2.95
|
||||||
|
|
||||||
# list of wildcard patterns to select images
|
# list of wildcard patterns to select images
|
||||||
# if relative paths are specified, then they are relative to this ad configuration file
|
# if relative paths are specified, then they are relative to this ad configuration file
|
||||||
|
|||||||
@@ -241,6 +241,9 @@ class KleinanzeigenBot(SeleniumMixin):
|
|||||||
if ad_cfg["category"]:
|
if ad_cfg["category"]:
|
||||||
ad_cfg["category"] = self.categories.get(ad_cfg["category"], ad_cfg["category"])
|
ad_cfg["category"] = self.categories.get(ad_cfg["category"], ad_cfg["category"])
|
||||||
|
|
||||||
|
if ad_cfg["shipping_costs"]:
|
||||||
|
ad_cfg["shipping_costs"] = str(utils.parse_decimal(ad_cfg["shipping_costs"]))
|
||||||
|
|
||||||
if ad_cfg["images"]:
|
if ad_cfg["images"]:
|
||||||
images = set()
|
images = set()
|
||||||
for image_pattern in ad_cfg["images"]:
|
for image_pattern in ad_cfg["images"]:
|
||||||
@@ -397,6 +400,17 @@ class KleinanzeigenBot(SeleniumMixin):
|
|||||||
else:
|
else:
|
||||||
ensure(is_category_auto_selected, f"No category specified in [{ad_file}] and automatic category detection failed")
|
ensure(is_category_auto_selected, f"No category specified in [{ad_file}] and automatic category detection failed")
|
||||||
|
|
||||||
|
#############################
|
||||||
|
# set shipping type/costs
|
||||||
|
#############################
|
||||||
|
if ad_cfg["shipping_type"] == "PICKUP":
|
||||||
|
self.web_click(By.XPATH, '//*[contains(@class, "ShippingPickupSelector")]//label[text()[contains(.,"Nur Abholung")]]/input[@type="radio"]')
|
||||||
|
elif ad_cfg["shipping_costs"]:
|
||||||
|
self.web_click(By.XPATH, '//*[contains(@class, "ShippingOption")]//input[@type="radio"]')
|
||||||
|
self.web_click(By.XPATH, '//*[contains(@class, "CarrierOptionsPopup")]//*[contains(@class, "IndividualPriceSection")]//input[@type="checkbox"]')
|
||||||
|
self.web_input(By.XPATH, '//*[contains(@class, "IndividualShippingInput")]//input[@type="text"]', str.replace(ad_cfg["shipping_costs"], ".", ","))
|
||||||
|
self.web_click(By.XPATH, '//*[contains(@class, "ReactModalPortal")]//button[.//*[text()[contains(.,"Weiter")]]]')
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
# set price
|
# set price
|
||||||
#############################
|
#############################
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ special_attributes: {}
|
|||||||
price:
|
price:
|
||||||
price_type: # one of: FIXED, NEGOTIABLE, GIVE_AWAY
|
price_type: # one of: FIXED, NEGOTIABLE, GIVE_AWAY
|
||||||
shipping_type: # one of: PICKUP, SHIPPING, NOT_APPLICABLE
|
shipping_type: # one of: PICKUP, SHIPPING, NOT_APPLICABLE
|
||||||
|
shipping_costs:
|
||||||
images: []
|
images: []
|
||||||
contact:
|
contact:
|
||||||
name:
|
name:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Copyright (C) 2022 Sebastian Thomschke and contributors
|
Copyright (C) 2022 Sebastian Thomschke and contributors
|
||||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
"""
|
"""
|
||||||
import copy, json, logging, os, secrets, sys, traceback, time
|
import copy, decimal, json, logging, os, re, secrets, sys, traceback, time
|
||||||
from importlib.resources import read_text as get_resource_as_string
|
from importlib.resources import read_text as get_resource_as_string
|
||||||
from collections.abc import Callable, Iterable
|
from collections.abc import Callable, Iterable
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
@@ -216,3 +216,28 @@ def save_dict(filepath:str, content:dict[str, Any]) -> None:
|
|||||||
yaml.allow_duplicate_keys = False
|
yaml.allow_duplicate_keys = False
|
||||||
yaml.explicit_start = False
|
yaml.explicit_start = False
|
||||||
yaml.dump(content, file)
|
yaml.dump(content, file)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_decimal(number:float | int | str) -> decimal.Decimal:
|
||||||
|
"""
|
||||||
|
>>> parse_decimal(5)
|
||||||
|
Decimal('5')
|
||||||
|
>>> parse_decimal(5.5)
|
||||||
|
Decimal('5.5')
|
||||||
|
>>> parse_decimal("5.5")
|
||||||
|
Decimal('5.5')
|
||||||
|
>>> parse_decimal("5,5")
|
||||||
|
Decimal('5.5')
|
||||||
|
>>> parse_decimal("1.005,5")
|
||||||
|
Decimal('1005.5')
|
||||||
|
>>> parse_decimal("1,005.5")
|
||||||
|
Decimal('1005.5')
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return decimal.Decimal(number)
|
||||||
|
except decimal.InvalidOperation as ex:
|
||||||
|
parts = re.split("[.,]", str(number))
|
||||||
|
try:
|
||||||
|
return decimal.Decimal("".join(parts[:-1]) + "." + parts[-1])
|
||||||
|
except decimal.InvalidOperation:
|
||||||
|
raise decimal.DecimalException(f"Invalid number format: {number}") from ex
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ max-attributes = 10
|
|||||||
max-branches = 20
|
max-branches = 20
|
||||||
max-locals = 30
|
max-locals = 30
|
||||||
max-returns = 10
|
max-returns = 10
|
||||||
max-statements = 80
|
max-statements = 90
|
||||||
|
|
||||||
|
|
||||||
#####################
|
#####################
|
||||||
|
|||||||
Reference in New Issue
Block a user