113 lines
4.1 KiB
Python
113 lines
4.1 KiB
Python
import requests
|
|
import logging
|
|
import time
|
|
import datetime
|
|
from platforms.base_platform import BasePlatform
|
|
from models.article import Article
|
|
|
|
REQUEST_RETRY_TIME = 5
|
|
|
|
class WallapopPlatform(BasePlatform):
|
|
"""Wallapop marketplace platform implementation"""
|
|
|
|
def __init__(self, item_monitor):
|
|
super().__init__(item_monitor)
|
|
self.logger = logging.getLogger(__name__)
|
|
|
|
def get_platform_name(self):
|
|
return "wallapop"
|
|
|
|
def create_url(self):
|
|
"""Create Wallapop API search URL"""
|
|
url = (
|
|
f"http://api.wallapop.com/api/v3/search"
|
|
f"?source=search_box"
|
|
f"&keywords={self._item_monitor.get_search_query()}"
|
|
f"&order_by=newest"
|
|
f"&language=es_ES"
|
|
)
|
|
|
|
# Only include latitude and longitude if both are not 0
|
|
if self._item_monitor.get_latitude() != 0 and self._item_monitor.get_longitude() != 0:
|
|
url += (
|
|
f"&latitude={self._item_monitor.get_latitude()}"
|
|
f"&longitude={self._item_monitor.get_longitude()}"
|
|
)
|
|
|
|
if self._item_monitor.get_min_price() != 0:
|
|
url += f"&min_sale_price={self._item_monitor.get_min_price()}"
|
|
|
|
if self._item_monitor.get_max_price() != 0:
|
|
url += f"&max_sale_price={self._item_monitor.get_max_price()}"
|
|
|
|
if self._item_monitor.get_max_distance() != 0:
|
|
url += f"&distance_in_km={self._item_monitor.get_max_distance()}"
|
|
|
|
if self._item_monitor.get_condition() != "all":
|
|
url += f"&condition={self._item_monitor.get_condition()}" # new, as_good_as_new, good, fair, has_given_it_all
|
|
|
|
return url
|
|
|
|
def get_request_headers(self):
|
|
"""Get Wallapop-specific headers"""
|
|
headers = super().get_request_headers()
|
|
headers['X-DeviceOS'] = '0'
|
|
return headers
|
|
|
|
def fetch_articles(self):
|
|
"""Fetch articles from Wallapop API"""
|
|
url = self.create_url()
|
|
|
|
while True:
|
|
try:
|
|
headers = self.get_request_headers()
|
|
response = requests.get(url, headers=headers)
|
|
response.raise_for_status()
|
|
break
|
|
except requests.exceptions.RequestException as err:
|
|
self.logger.error(f"Request Exception: {err}")
|
|
time.sleep(REQUEST_RETRY_TIME)
|
|
|
|
json_response = response.json()
|
|
json_items = json_response['data']['section']['payload']['items']
|
|
articles = self.parse_response(json_items)
|
|
return articles
|
|
|
|
def parse_response(self, json_items):
|
|
"""Parse Wallapop JSON response into Article objects"""
|
|
articles = []
|
|
for json_article in json_items:
|
|
article = self._parse_single_article(json_article)
|
|
if article:
|
|
articles.append(article)
|
|
return articles
|
|
|
|
def _parse_single_article(self, json_data):
|
|
"""Parse a single Wallapop article from JSON"""
|
|
try:
|
|
# Extract images with proper format
|
|
images = [img['urls']['medium'] for img in json_data['images'][:3]]
|
|
|
|
# Convert timestamp to datetime string
|
|
ts = int(json_data['modified_at'])
|
|
dt = datetime.datetime.fromtimestamp(ts / 1000)
|
|
modified_at = dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
return Article(
|
|
id=json_data['id'],
|
|
title=json_data['title'],
|
|
description=json_data['description'],
|
|
price=json_data['price']['amount'],
|
|
currency=json_data['price']['currency'],
|
|
location=json_data['location']['city'],
|
|
allows_shipping=json_data['shipping']['user_allows_shipping'],
|
|
url="https://wallapop.com/item/" + json_data['web_slug'],
|
|
images=images,
|
|
modified_at=modified_at,
|
|
platform=self.get_platform_name()
|
|
)
|
|
except (KeyError, ValueError) as e:
|
|
self.logger.error(f"Error parsing Wallapop article: {e}")
|
|
return None
|
|
|