mirror of
https://github.com/Second-Hand-Friends/kleinanzeigen-bot.git
synced 2026-03-12 02:31:45 +01:00
ADD ability to select shipping packages and sell directly
This commit is contained in:
committed by
Sebastian Thomschke
parent
664c0dfc7f
commit
e483c003d0
17
README.md
17
README.md
@@ -232,6 +232,7 @@ ad_defaults:
|
|||||||
price_type: NEGOTIABLE # one of: FIXED, NEGOTIABLE, GIVE_AWAY, NOT_APPLICABLE
|
price_type: NEGOTIABLE # one of: FIXED, NEGOTIABLE, GIVE_AWAY, NOT_APPLICABLE
|
||||||
shipping_type: SHIPPING # one of: PICKUP, SHIPPING, NOT_APPLICABLE
|
shipping_type: SHIPPING # one of: PICKUP, SHIPPING, NOT_APPLICABLE
|
||||||
shipping_costs: # e.g. 2.95
|
shipping_costs: # e.g. 2.95
|
||||||
|
sell_directly: false # requires shipping_options to take effect
|
||||||
contact:
|
contact:
|
||||||
name: ""
|
name: ""
|
||||||
street: ""
|
street: ""
|
||||||
@@ -295,6 +296,22 @@ special_attributes:
|
|||||||
shipping_type: # one of: PICKUP, SHIPPING, NOT_APPLICABLE
|
shipping_type: # one of: PICKUP, SHIPPING, NOT_APPLICABLE
|
||||||
shipping_costs: # e.g. 2.95
|
shipping_costs: # e.g. 2.95
|
||||||
|
|
||||||
|
# specify shipping options / packages
|
||||||
|
# it is possible to select multiple packages, but only from one size (S, M, L)!
|
||||||
|
# possible package types for size S:
|
||||||
|
# - DHL_2
|
||||||
|
# - Hermes_Päckchen
|
||||||
|
# - Hermes_S
|
||||||
|
# possible package types for size M:
|
||||||
|
# - DHL_5
|
||||||
|
# - Hermes_M
|
||||||
|
# possible package types for size L:
|
||||||
|
# - DHL_10
|
||||||
|
# - DHL_31,5
|
||||||
|
# - Hermes_L
|
||||||
|
shipping_options: []
|
||||||
|
sell_directly: # true or false, requires shipping_options to take effect
|
||||||
|
|
||||||
# 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
|
||||||
images:
|
images:
|
||||||
|
|||||||
@@ -469,13 +469,15 @@ class KleinanzeigenBot(SeleniumMixin):
|
|||||||
self.__set_category(ad_file, ad_cfg)
|
self.__set_category(ad_file, ad_cfg)
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
# set shipping type/costs
|
# set shipping type/options/costs
|
||||||
#############################
|
#############################
|
||||||
if ad_cfg["shipping_type"] == "PICKUP":
|
if ad_cfg["shipping_type"] == "PICKUP":
|
||||||
try:
|
try:
|
||||||
self.web_click(By.XPATH, '//*[contains(@class, "ShippingPickupSelector")]//label[text()[contains(.,"Nur Abholung")]]/input[@type="radio"]')
|
self.web_click(By.XPATH, '//*[contains(@class, "ShippingPickupSelector")]//label[text()[contains(.,"Nur Abholung")]]/input[@type="radio"]')
|
||||||
except NoSuchElementException as ex:
|
except NoSuchElementException as ex:
|
||||||
LOG.debug(ex, exc_info = True)
|
LOG.debug(ex, exc_info = True)
|
||||||
|
elif ad_cfg["shipping_options"]:
|
||||||
|
self.__set_shipping_options(ad_cfg)
|
||||||
elif ad_cfg["shipping_costs"]:
|
elif ad_cfg["shipping_costs"]:
|
||||||
try:
|
try:
|
||||||
self.web_click(By.XPATH, '//*[contains(@class, "ShippingOption")]//input[@type="radio"]')
|
self.web_click(By.XPATH, '//*[contains(@class, "ShippingOption")]//input[@type="radio"]')
|
||||||
@@ -495,6 +497,16 @@ class KleinanzeigenBot(SeleniumMixin):
|
|||||||
if safe_get(ad_cfg, "price"):
|
if safe_get(ad_cfg, "price"):
|
||||||
self.web_input(By.XPATH, "//input[@id='post-ad-frontend-price' or @id='micro-frontend-price' or @id='pstad-price']", ad_cfg["price"])
|
self.web_input(By.XPATH, "//input[@id='post-ad-frontend-price' or @id='micro-frontend-price' or @id='pstad-price']", ad_cfg["price"])
|
||||||
|
|
||||||
|
#############################
|
||||||
|
# set sell_directly
|
||||||
|
#############################
|
||||||
|
sell_directly = ad_cfg["sell_directly"]
|
||||||
|
if sell_directly and ad_cfg["shipping_type"] == "SHIPPING" and ad_cfg["shipping_options"] and price_type in {"FIXED", "NEGOTIABLE"}:
|
||||||
|
try:
|
||||||
|
self.web_click(By.XPATH, '//*[contains(@class, "BuyNowSection")]//span[contains(@class, "Toggle--Slider")]')
|
||||||
|
except NoSuchElementException as ex:
|
||||||
|
LOG.debug(ex, exc_info = True)
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
# set description
|
# set description
|
||||||
#############################
|
#############################
|
||||||
@@ -609,6 +621,43 @@ class KleinanzeigenBot(SeleniumMixin):
|
|||||||
raise NoSuchElementException(f"Failed to set special attribute [{special_attribute_key}]") from ex
|
raise NoSuchElementException(f"Failed to set special attribute [{special_attribute_key}]") from ex
|
||||||
LOG.debug("Successfully set attribute field [%s] to [%s]...", special_attribute_key, special_attribute_value)
|
LOG.debug("Successfully set attribute field [%s] to [%s]...", special_attribute_key, special_attribute_value)
|
||||||
|
|
||||||
|
def __set_shipping_options(self, ad_cfg: dict[str, Any]) -> None:
|
||||||
|
try:
|
||||||
|
shipping_option_mapping = {
|
||||||
|
"DHL_2": ("Klein", "Paket 2 kg"),
|
||||||
|
"Hermes_Päckchen": ("Klein", "Päckchen"),
|
||||||
|
"Hermes_S": ("Klein", "S-Paket"),
|
||||||
|
"DHL_5": ("Mittel", "Paket 5 kg"),
|
||||||
|
"Hermes_M": ("Mittel", "M-Paket"),
|
||||||
|
"DHL_10": ("Mittel", "Paket 10 kg"),
|
||||||
|
"DHL_31,5": ("Groß", "Paket 31,5 kg"),
|
||||||
|
"Hermes_L": ("Groß", "L-Paket"),
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
mapped_shipping_options = [shipping_option_mapping[option] for option in ad_cfg["shipping_options"]]
|
||||||
|
shipping_sizes, shipping_packages = zip(*mapped_shipping_options)
|
||||||
|
except KeyError as ex:
|
||||||
|
raise KeyError(f"Unknown shipping option(s), please refer to the documentation/README: {ad_cfg['shipping_options']}") from ex
|
||||||
|
|
||||||
|
unique_shipping_sizes = set(shipping_sizes)
|
||||||
|
if len(unique_shipping_sizes) > 1:
|
||||||
|
raise ValueError("You can only specify shipping options for one package size!")
|
||||||
|
|
||||||
|
shipping_size, = unique_shipping_sizes
|
||||||
|
self.web_click(By.XPATH, f'//*[contains(@class, "ShippingOption")]//input[@type="radio" and @data-testid="{shipping_size}"]')
|
||||||
|
|
||||||
|
for shipping_package in shipping_packages:
|
||||||
|
self.web_click(
|
||||||
|
By.XPATH,
|
||||||
|
'//*[contains(@class, "CarrierOptionsPopup")]'
|
||||||
|
'//*[contains(@class, "CarrierOption")]'
|
||||||
|
f'//input[@type="checkbox" and @data-testid="{shipping_package}"]'
|
||||||
|
)
|
||||||
|
|
||||||
|
self.web_click(By.XPATH, '//*[contains(@class, "ReactModalPortal")]//button[.//*[text()[contains(.,"Weiter")]]]')
|
||||||
|
except NoSuchElementException as ex:
|
||||||
|
LOG.debug(ex, exc_info = True)
|
||||||
|
|
||||||
def __upload_images(self, ad_cfg: dict[str, Any]):
|
def __upload_images(self, ad_cfg: dict[str, Any]):
|
||||||
LOG.info(" -> found %s", pluralize("image", ad_cfg["images"]))
|
LOG.info(" -> found %s", pluralize("image", ad_cfg["images"]))
|
||||||
image_upload = self.web_find(By.XPATH, "//input[@type='file']")
|
image_upload = self.web_find(By.XPATH, "//input[@type='file']")
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ price:
|
|||||||
price_type: # one of: FIXED, NEGOTIABLE, GIVE_AWAY, NOT_APPLICABLE
|
price_type: # one of: FIXED, NEGOTIABLE, GIVE_AWAY, NOT_APPLICABLE
|
||||||
shipping_type: # one of: PICKUP, SHIPPING, NOT_APPLICABLE
|
shipping_type: # one of: PICKUP, SHIPPING, NOT_APPLICABLE
|
||||||
shipping_costs:
|
shipping_costs:
|
||||||
|
shipping_options: [] # see README.md for more information
|
||||||
|
sell_directly: # requires shipping_options to take effect
|
||||||
images: []
|
images: []
|
||||||
contact:
|
contact:
|
||||||
name:
|
name:
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ ad_defaults:
|
|||||||
suffix: ""
|
suffix: ""
|
||||||
price_type: NEGOTIABLE # one of: FIXED, NEGOTIABLE, GIVE_AWAY, NOT_APPLICABLE
|
price_type: NEGOTIABLE # one of: FIXED, NEGOTIABLE, GIVE_AWAY, NOT_APPLICABLE
|
||||||
shipping_type: SHIPPING # one of: PICKUP, SHIPPING, NOT_APPLICABLE
|
shipping_type: SHIPPING # one of: PICKUP, SHIPPING, NOT_APPLICABLE
|
||||||
|
sell_directly: false # requires shipping_options to take effect
|
||||||
contact:
|
contact:
|
||||||
name: ""
|
name: ""
|
||||||
street: ""
|
street: ""
|
||||||
|
|||||||
Reference in New Issue
Block a user