← back to Wine Finder Next

lib/services/wineBidScraper.js

108 lines

const axios = require('axios');

/**
 * WineBid Auction Scraper
 * Fetches live auction data and historical sale prices
 */
class WineBidScraper {
  constructor() {
    this.baseUrl = 'https://www.winebid.com';
  }

  async search(query) {
    try {
      // WineBid search endpoint
      const searchUrl = `${this.baseUrl}/BuyWine/Search`;
      const response = await axios.get(searchUrl, {
        params: {
          searchText: query,
          pageSize: 50
        },
        headers: {
          'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
          'Accept': 'application/json'
        },
        timeout: 10000
      });

      const wines = [];
      const items = response.data.items || [];

      for (const item of items) {
        wines.push({
          name: item.lotTitle || item.name,
          price: parseFloat(item.currentBid || item.startingBid || 0),
          highestBid: parseFloat(item.currentBid || 0),
          startingBid: parseFloat(item.startingBid || 0),
          estimatedValue: parseFloat(item.estimatedValue || 0),
          vintage: item.vintage,
          winery: item.producer,
          region: item.region,
          country: item.country,
          lotNumber: item.lotNumber,
          auctionEndDate: item.endDate,
          bidsCount: item.bidCount || 0,
          source: 'WineBid',
          type: 'auction',
          url: `${this.baseUrl}/Lot/${item.lotNumber}`,
          image: item.imageUrl,
          availability: item.endDate ? `Ends ${new Date(item.endDate).toLocaleDateString()}` : 'Live Auction',
          bottleSize: item.bottleSize,
          quantity: item.quantity || 1
        });
      }

      return {
        success: true,
        wines,
        count: wines.length,
        source: 'WineBid'
      };
    } catch (error) {
      console.error('WineBid scraper error:', error.message);
      return {
        success: false,
        wines: [],
        count: 0,
        error: error.message,
        source: 'WineBid'
      };
    }
  }

  async getHistoricalPrices(wineName, vintage) {
    try {
      // Fetch historical auction results
      const response = await axios.get(`${this.baseUrl}/api/historical`, {
        params: {
          wine: wineName,
          vintage: vintage
        },
        headers: {
          'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        }
      });

      const history = response.data.map(sale => ({
        date: sale.saleDate,
        price: parseFloat(sale.hammerPrice),
        quantity: sale.quantity,
        bottleSize: sale.bottleSize,
        auction: sale.auctionHouse
      }));

      return {
        success: true,
        history,
        averagePrice: history.reduce((sum, h) => sum + h.price, 0) / history.length,
        highestPrice: Math.max(...history.map(h => h.price)),
        lowestPrice: Math.min(...history.map(h => h.price))
      };
    } catch (error) {
      return { success: false, history: [], error: error.message };
    }
  }
}

module.exports = new WineBidScraper();