const FORMAT = { hourly: { temperature: { type: 'number', unit: '°C', }, precipitation: { type: 'number', unit: 'mm', }, apparentTemperature: { type: 'number', unit: '°C', }, weatherCode: { type: 'string', }, }, daily: { minimumTemperature: { type: 'number', unit: '°C', }, maximumTemperature: { type: 'number', unit: '°C', }, minimumApparentTemperature: { type: 'number', unit: '°C', }, maximumApparentTemperature: { type: 'number', unit: '°C', }, precipitationSum: { type: 'number', unit: 'mm', }, }, } const parseTemp = el => { return parseFloat(el.textContent) } const parsePrec = el => { const text = el.textContent.trim() if (text === 'assenti') return 0 if (text === 'deboli') return 0.05 try { //TODO not 100% sure that this would work as it was never tested return parseFloat(text) } catch (error) { console.log(error) return text } } // const getStartTime = isToday => { // if (!isToday) return 0 // // const d = new Date() // const h = d.getHours() // // if (d.getMinutes() > 30) return h + 1 // return h // } const scrapePage = async (browser, url, isToday) => { let result = {} const page = await browser.newPage() await page.goto(url) const tablePrevisioni = await page .locator('.table-previsioni-ora') .waitHandle() const rows = await tablePrevisioni.$$('.row-table.noPad') // const startTime = getStartTime(isToday) const startTime = isToday ? new Date().getHours() + 1 : 0 const endTime = 23 for (let i = startTime; i <= endTime; i++) { try { const row = rows[rows.length - 1 - (endTime - i)] const [rowLeft, rowRight] = await row.$$(':scope > div') const codeDiv = (await (await rowLeft.$('.row-table')).$$('div'))[2] const rightFields = await (await rowRight.$('.row-table')).$$('div') const tempDiv = rightFields[0] const precDiv = rightFields[1] const appTempDiv = rightFields[4] const weatherCode = await codeDiv.evaluate(el => el.textContent.trim(), ) const temperature = await ( await tempDiv.$('span') ).evaluate(parseTemp) const precipitation = await precDiv.evaluate(parsePrec) const apparentTemperature = await ( await appTempDiv.$('span') ).evaluate(parseTemp) result[i] = { temperature, precipitation, apparentTemperature, weatherCode, } } catch (error) { result[i] = null console.log(error) } } await page.close() return result } const getDaySummary = day => { let minimumTemperature = Number.MAX_VALUE let maximumTemperature = Number.MIN_VALUE let minimumApparentTemperature = Number.MAX_VALUE let maximumApparentTemperature = Number.MIN_VALUE let precipitationSum = 0 for (const h in day) { minimumTemperature = Math.min(minimumTemperature, day[h]?.temperature) maximumTemperature = Math.max(maximumTemperature, day[h]?.temperature) minimumApparentTemperature = Math.min( minimumApparentTemperature, day[h]?.apparentTemperature, ) maximumApparentTemperature = Math.max( maximumApparentTemperature, day[h]?.apparentTemperature, ) precipitationSum += day[h]?.precipitation } return { minimumTemperature, maximumTemperature, minimumApparentTemperature, maximumApparentTemperature, precipitationSum, } } export default async browser => { const url = text => `https://www.3bmeteo.com/meteo/pisa/${text}` const results = await Promise.all([ scrapePage(browser, url(''), true), scrapePage(browser, url('1'), false), scrapePage(browser, url('2'), false), scrapePage(browser, url('3'), false), scrapePage(browser, url('4'), false), scrapePage(browser, url('5'), false), scrapePage(browser, url('6'), false), ]) return { format: FORMAT, today: results[0], tomorrow: results[1], dayAfterTomorrow: results[2], week: { ...results.map(getDaySummary) }, } }