← back to Handbag Authentication
crawler/yahoo-jp.js
125 lines
const puppeteer = require('puppeteer');
class YahooAuctionsJPScraper {
constructor() {
this.baseUrl = 'https://auctions.yahoo.co.jp/search/search';
this.brands = [
'グッチ バッグ',
'ルイヴィトン バッグ',
'シャネル バッグ',
'エルメス バッグ',
'プラダ バッグ',
'ディオール バッグ',
'フェンディ バッグ',
'バレンシアガ バッグ',
'セリーヌ バッグ',
'ボッテガヴェネタ バッグ',
'ロエベ バッグ',
'ミュウミュウ バッグ',
'サンローラン バッグ',
'ジバンシー バッグ'
];
this.maxPages = 10; // Increased for more listings
}
async scrapeSearch(brand, page = 1) {
try {
const browser = await puppeteer.launch({
headless: 'new',
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
const browserPage = await browser.newPage();
await browserPage.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36');
const searchUrl = `${this.baseUrl}?p=${encodeURIComponent(brand)}&b=${(page - 1) * 50 + 1}`;
console.log(`Scraping Yahoo Auctions JP: ${searchUrl}`);
await browserPage.goto(searchUrl, { waitUntil: 'networkidle2', timeout: 30000 });
await browserPage.waitForSelector('.Product, .Product__item', { timeout: 10000 }).catch(() => {});
const listings = await browserPage.evaluate(() => {
const items = [];
const productElements = document.querySelectorAll('.Product, .Product__item');
productElements.forEach((item) => {
try {
const titleEl = item.querySelector('.Product__title, a');
const title = titleEl?.textContent?.trim() || '';
const priceEl = item.querySelector('.Product__price, .u-tax');
const priceText = priceEl?.textContent?.trim() || '';
const priceMatch = priceText.match(/[\d,]+/);
const price = priceMatch ? parseInt(priceMatch[0].replace(/,/g, '')) : 0;
const imgEl = item.querySelector('img');
const image = imgEl?.src || '';
const linkEl = item.querySelector('a');
const url = linkEl?.href || '';
const idMatch = url.match(/\/([a-z0-9]+)$/);
const id = idMatch?.[1] || url;
const timeEl = item.querySelector('.Product__time');
const endTime = timeEl?.textContent?.trim() || '';
if (title && price > 0) {
items.push({
external_id: id,
title,
price_jpy: price,
image_url: image,
thumbnail_url: image,
product_url: url,
listing_type: 'auction',
auction_end_date: endTime,
condition: 'Used'
});
}
} catch (e) {
console.error('Error parsing Yahoo auction item:', e);
}
});
return items;
});
await browser.close();
return listings;
} catch (error) {
console.error(`Error scraping Yahoo Auctions JP:`, error.message);
return [];
}
}
async scrapeAllBrands() {
const allListings = [];
for (const brand of this.brands) {
console.log(`\nScraping Yahoo Auctions JP for ${brand}...`);
for (let page = 1; page <= this.maxPages; page++) {
const listings = await this.scrapeSearch(brand, page);
if (listings.length === 0) break;
listings.forEach(listing => {
listing.brand = brand;
listing.source = 'yahoo_auctions_jp';
});
allListings.push(...listings);
console.log(`Found ${listings.length} items on page ${page}`);
await new Promise(resolve => setTimeout(resolve, 3000));
}
}
return allListings;
}
}
module.exports = YahooAuctionsJPScraper;