|
|
|
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) },
|
|
|
|
}
|
|
|
|
}
|