You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
4.6 KiB
JavaScript

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