|
import puppeteer from "puppeteer"; |
|
import fs from 'fs'; |
|
import path from 'path'; |
|
import moment from 'moment'; |
|
import csv from 'csv-parser'; |
|
|
|
const SN_PENDING_DELETE_DIR = path.join(__dirname, 'lists/snapnames/pending_delete'); |
|
const SN_EXPIRING_DIR = path.join(__dirname, 'lists/snapnames/expiring'); |
|
const SN_EXCLUSIVE_AUCTION_DIR = path.join(__dirname, 'lists/snapnames/in_auction'); |
|
|
|
if (!fs.existsSync(SN_EXPIRING_DIR)) { |
|
fs.mkdirSync(SN_EXPIRING_DIR, { recursive: true }); |
|
} |
|
|
|
if (!fs.existsSync(SN_PENDING_DELETE_DIR)) { |
|
fs.mkdirSync(SN_PENDING_DELETE_DIR, { recursive: true }); |
|
} |
|
|
|
if (!fs.existsSync(SN_EXCLUSIVE_AUCTION_DIR)) { |
|
fs.mkdirSync(SN_EXCLUSIVE_AUCTION_DIR, { recursive: true }); |
|
} |
|
|
|
const basePage = 'https://www.snapnames.com/download.action?format=csv'; |
|
|
|
(async () => { |
|
const browser = await puppeteer.launch({headless: false}); |
|
const page = await browser.newPage(); |
|
|
|
await page.goto(basePage); |
|
|
|
const target = page.target(); |
|
const session = await target.createCDPSession(); |
|
|
|
const result1: any = await page.evaluate('Array.from(document.querySelectorAll("#list-subscribe > div:nth-child(3) a")).map(a => ({href: a.href, name: a.title}))') // Expiring Domains |
|
const result2: any = await page.evaluate('Array.from(document.querySelectorAll("#list-subscribe > div:nth-child(4) a")).map(a => ({href: a.href, name: a.title}))') // Pending Delete Domains |
|
const result3: any = await page.evaluate('Array.from(document.querySelectorAll("#list-subscribe > div:nth-child(2) a")).map(a => ({href: a.href, name: a.title}))') // Exclusive Auctions |
|
|
|
const allDomains = [...result1, ...result2, ...result3]; |
|
|
|
const datedEntries = allDomains.filter((item) => { |
|
const match = item.name.match(/(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d+/); |
|
|
|
// get closest year to matched date |
|
let closestYear = moment().year(); |
|
|
|
// if the month is less than the current month, add a year |
|
if (moment(match, 'MMM DD').month() < moment().month()) { |
|
closestYear + 1; |
|
} |
|
|
|
if (match) { |
|
item.date = moment(`${match}, ${closestYear}`, 'MMM DD').format('YYYY-MM-DD'); |
|
return item |
|
} |
|
}); |
|
|
|
const entries = datedEntries.filter(entry => { |
|
if (entry.name.match(/expiring/)) { |
|
entry.type = 'expiring' |
|
} |
|
if (entry.name.match(/deleting/)) { |
|
if (entry.href.match(/live/)) { |
|
entry.type = 'in_auction' |
|
} else { |
|
entry.type = 'pending_delete' |
|
} |
|
} |
|
|
|
return entry |
|
}) |
|
|
|
for (const entry of entries) { |
|
const { name, href, type } = entry; |
|
console.log(`Downloading ${name}...`); |
|
|
|
const downloadPath = path.join(__dirname, `lists/snapnames/${type}/`); |
|
|
|
await session.send('Page.setDownloadBehavior', { |
|
behavior: 'allow', |
|
downloadPath: downloadPath |
|
}); |
|
|
|
await page.click(`a[href="${href.split('.com/')[1]}"]`); |
|
|
|
await page.goto(basePage); |
|
} |
|
|
|
await new Promise((resolve) => { |
|
setTimeout(resolve, 5000); |
|
} |
|
); |
|
|
|
console.log(`Downloaded ${entries.length} files.`) |
|
|
|
await page.close(); |
|
await browser.close(); |
|
|
|
const expiringFiles = fs.readdirSync(SN_EXPIRING_DIR, { withFileTypes: true }) |
|
.filter(dirent => dirent.name.endsWith('.csv')); |
|
const pendingDeleteFiles = fs.readdirSync(SN_PENDING_DELETE_DIR, { withFileTypes: true }) |
|
.filter(dirent => dirent.name.endsWith('.csv')); |
|
const exclusiveAuctionFiles = fs.readdirSync(SN_EXCLUSIVE_AUCTION_DIR, { withFileTypes: true }) |
|
.filter(dirent => dirent.name.endsWith('.csv')); |
|
|
|
for (const file of expiringFiles) { |
|
const filePath = path.join(SN_EXPIRING_DIR, file.name); |
|
const fileContents = fs.readFileSync(filePath, 'utf-8'); |
|
const parsed: any[] = await new Promise((resolve, reject) => { |
|
const results = []; |
|
fs.createReadStream(filePath) |
|
.pipe(csv()) |
|
.on('data', (data) => results.push(data)) |
|
.on('end', () => resolve(results)) |
|
.on('error', reject); |
|
}); |
|
|
|
console.log(`Parsed ${parsed.length} domains from ${file.name}.`); |
|
|
|
const domains = parsed.map((item) => ({ |
|
fqdn: item["Domain Name"], |
|
currentBid: item["Current Bid"], |
|
preorderByDate: item["Join By Date (ET)"], |
|
})) |
|
|
|
const output = JSON.stringify(domains); |
|
|
|
fs.writeFileSync(filePath.replace('.csv', '.json'), output); |
|
} |
|
|
|
for (const file of pendingDeleteFiles) { |
|
const filePath = path.join(SN_PENDING_DELETE_DIR, file.name); |
|
const fileContents = fs.readFileSync(filePath, 'utf-8'); |
|
const parsed: any[] = await new Promise((resolve, reject) => { |
|
const results = []; |
|
fs.createReadStream(filePath) |
|
.pipe(csv()) |
|
.on('data', (data) => results.push(data)) |
|
.on('end', () => resolve(results)) |
|
.on('error', reject); |
|
}); |
|
|
|
console.log(`Parsed ${parsed.length} domains from ${file.name}.`); |
|
|
|
const domains = parsed.map((item) => ({ |
|
fqdn: item["Domain Name"], |
|
currentBid: item["Current Bid"], |
|
preorderByDate: item["Join By Date (ET)"], |
|
})) |
|
|
|
const output = JSON.stringify(domains); |
|
|
|
fs.writeFileSync(filePath.replace('.csv', '.json'), output); |
|
} |
|
|
|
for (const file of exclusiveAuctionFiles) { |
|
const filePath = path.join(SN_EXCLUSIVE_AUCTION_DIR, file.name); |
|
const parsed: any[] = await new Promise((resolve, reject) => { |
|
const results = []; |
|
fs.createReadStream(filePath) |
|
.pipe(csv({ skipLines: 2 })) |
|
.on('data', (data) => results.push(data)) |
|
.on('end', () => resolve(results)) |
|
.on('error', reject); |
|
}); |
|
|
|
console.log(`Parsed ${parsed.length} domains from ${file.name}.`); |
|
|
|
const domains = parsed.map((item) => ({ |
|
fqdn: item["Domain name"], |
|
currentBid: item["Current bid"], |
|
endDate: item["Auction end date"], |
|
})) |
|
|
|
const output = JSON.stringify(domains); |
|
|
|
fs.writeFileSync(filePath.replace('.csv', '.json'), output); |
|
} |
|
})(); |
|
|