-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
123 lines (101 loc) · 3.99 KB
/
index.js
File metadata and controls
123 lines (101 loc) · 3.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
const puppeteer = require('puppeteer');
const fs = require('fs');
class BrowserFactory {
static async createBrowser() {
return await puppeteer.launch({ headless: 'shell' });
}
static async createPage(browser) {
const page = await browser.newPage();
const ua = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36";
await page.setUserAgent(ua);
await page.setViewport({ width: 1920, height: 1080, deviceScaleFactor: 1 });
return page;
}
}
class PageInteractor {
constructor(page, region) {
this.page = page;
this.region = region;
}
async navigateTo(url) {
await this.page.goto(url, { waitUntil: 'networkidle0' });
}
async selectRegion() {
await this.page.waitForNavigation({ waitUntil: 'domcontentloaded' });
await this.page.waitForSelector('.Region_regionIcon__oZ0Rt');
await this.page.click('.Region_regionIcon__oZ0Rt');
await this.page.evaluate((region) => {
const regionItems = Array.from(document.querySelectorAll('.UiRegionListBase_item___ly_A'));
const desiredRegion = regionItems.find((item) => item.textContent.includes(region));
if (desiredRegion) {
desiredRegion.click();
}
}, this.region);
}
async makeScreenshot() {
await this.page.waitForNavigation({ waitUntil: 'domcontentloaded' });
await this.page.screenshot({ path: 'screenshot.jpg' });
}
async getProductDto() {
return this.page.evaluate(() => {
const getPrice = (selector) => {
const priceText = document.querySelector(selector)?.textContent.trim() || null;
return priceText ? priceText.replace(/[^0-9,.-]+/g, '') : null;
};
const getReviews = (selector) => {
return document.querySelector(selector)?.textContent.trim().replace(/\D/g, '') || '0';
};
return {
price: getPrice('.Price_price__QzA8L.Price_size_XL__MHvC1.Price_role_regular__X6X4D') ||
getPrice('.Price_price__QzA8L.Price_size_XL__MHvC1.Price_role_discount__l_tpE') ||
'null',
oldPrice: getPrice('.Price_price__QzA8L.Price_size_XS__ESEhJ.Price_role_old__r1uT1') || 'null',
rating: getPrice('.ActionsRow_stars__EKt42') || '0',
reviews: getReviews('.ActionsRow_reviews__AfSj_') || '0'
};
});
}
}
class ProductDataSaver {
static saveToFile(data) {
const productInfo = `price=${data.price || 'null'}\npriceOld=${data.oldPrice || 'null'}\nrating=${data.rating || '0'}\nreviewCount=${data.reviews || '0'}`;
fs.writeFileSync('product.txt', productInfo);
}
}
class ProductScraper {
constructor(link, region) {
this.link = link;
this.region = region;
}
async run() {
try {
this.browser = await BrowserFactory.createBrowser();
this.page = await BrowserFactory.createPage(this.browser);
const interactor = new PageInteractor(this.page, this.region);
await interactor.navigateTo(this.link);
await interactor.selectRegion();
await interactor.makeScreenshot();
const productData = await interactor.getProductDto();
ProductDataSaver.saveToFile(productData);
} catch (error) {
console.error('Error during scraping process:', error);
} finally {
if (this.browser) {
await this.browser.close();
}
}
}
}
const [link, region] = process.argv.slice(2);
if (!link || !region) {
console.error('Usage: node index.js <product_link> <region>');
process.exit(1);
}
(async function main() {
try {
const scraper = new ProductScraper(link, region);
await scraper.run();
} catch (error) {
console.error('Failed to scrape product:', error);
}
})();