diff --git a/README.md b/README.md
index 1769e09..02c47ce 100644
--- a/README.md
+++ b/README.md
@@ -51,12 +51,12 @@ eventually, together with the current level of implementation
⛔️ = Not implemented
```
-| Source | Status | Comments |
-| ---------------------------------------------------- | ------ | ---------------------------------------- |
-| [iLMeteo](https://www.ilmeteo.it) | ✅ | |
-| [3Bmeteo](https://www.3bmeteo.com/) | 🚧 | Precipitation might not work as intended |
-| [OpenMeteo](https://open-meteo.com/) | ✅ | |
-| [Meteo Aeronautica Militare](http://www.meteoam.it/) | ⛔️ | |
+| Source | Status | Comments |
+| ---------------------------------------------- | ------ | ----------------------------------------------- |
+| [iLMeteo](https://www.ilmeteo.it) | ✅ | |
+| [3Bmeteo](https://www.3bmeteo.com/) | 🚧 | Precipitation might not work as intended |
+| [OpenMeteo](https://open-meteo.com/) | ✅ | |
+| [Aeronautica Militare](http://www.meteoam.it/) | 🚧 | Week only has `[0..4]` instead of `[0..6]` days |
iLMeteo
@@ -216,3 +216,35 @@ Format:
```
+
+
+Aeronautica Militare
+
+Format:
+
+```json
+{
+ "hourly": {
+ "temperature": {
+ "type": "number",
+ "unit": "°C"
+ },
+ "precipitationProbability": {
+ "type": "number",
+ "unit": "%"
+ }
+ },
+ "daily": {
+ "minimumTemperature": {
+ "type": "number",
+ "unit": "°C"
+ },
+ "maximumTemperature": {
+ "type": "number",
+ "unit": "°C"
+ }
+ }
+}
+```
+
+
diff --git a/index.js b/index.js
index aa2ef49..afb3286 100644
--- a/index.js
+++ b/index.js
@@ -3,6 +3,7 @@ import puppeteer from 'puppeteer'
import fetchILMeteo from './scrapers/iLMeteo.js'
import fetch3Bmeteo from './scrapers/3Bmeteo.js'
+import fetchAeronauticaMilitare from './scrapers/AeronauticaMilitare.js'
import fetchOpenMeteo from './scrapers/OpenMeteo.js'
const NIX_OPS = {
@@ -18,10 +19,12 @@ const run = async () => {
iLMeteo,
treBmeteo,
openMeteo,
+ aeronauticaMilitare,
] = await Promise.all([
fetchILMeteo(browser),
fetch3Bmeteo(browser),
fetchOpenMeteo(),
+ fetchAeronauticaMilitare(browser),
])
await browser.close()
@@ -30,6 +33,7 @@ const run = async () => {
iLMeteo,
treBmeteo,
openMeteo,
+ aeronauticaMilitare,
}
}
diff --git a/scrapers/AeronauticaMilitare.js b/scrapers/AeronauticaMilitare.js
new file mode 100644
index 0000000..4f31412
--- /dev/null
+++ b/scrapers/AeronauticaMilitare.js
@@ -0,0 +1,160 @@
+const FORMAT = {
+ hourly: {
+ temperature: {
+ type: 'number',
+ unit: '°C',
+ },
+ precipitationProbability: {
+ type: 'number',
+ unit: '%',
+ },
+ // weatherCode: {
+ // type: 'number',
+ // unit: 'Aeronautica Militare Weather Icons',
+ // },
+ },
+ daily: {
+ minimumTemperature: {
+ type: 'number',
+ unit: '°C',
+ },
+ maximumTemperature: {
+ type: 'number',
+ unit: '°C',
+ },
+ // weatherCode: {
+ // type: 'number',
+ // unit: 'Aeronautica Militare Weather Icons',
+ // },
+ },
+}
+
+const range = (start, end) => {
+ /// returns [start .. (end-1)]
+ return [...Array(end - start).keys()].map(x => x + start)
+}
+
+const parseTemp = el => {
+ // return el.textContent
+ return parseFloat(el.textContent)
+}
+const parsePrecProb = el => {
+ const text = el.textContent.trim()
+ return parseFloat(text)
+ return text
+ 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
+ } catch (error) {
+ console.log(error)
+ return text
+ }
+}
+
+export default async browser => {
+ const page = await browser.newPage()
+ await page.goto('https://www.meteoam.it/it/meteo-citta/pisa')
+
+ const meteogramInfoContainer = await page
+ .locator('.meteogram-info-container')
+ .waitHandle()
+
+ const startTime = new Date().getHours() + 1
+ const endTime = 24
+
+ const scrapeColumn = async i => {
+ const column = await meteogramInfoContainer.$(
+ `#weather_info_container_${i}`,
+ )
+
+ const tempDiv = await column.$('.weather-info-temperature')
+ const precProbDiv = await column.$('.weather-rain-probability')
+
+ const temperature = await tempDiv.evaluate(parseTemp)
+ const precipitationProbability =
+ await precProbDiv.evaluate(parsePrecProb)
+
+ return { temperature, precipitationProbability }
+ }
+
+ const scrapeBlock = async i => {
+ const block = await meteogramInfoContainer.$(
+ `.swiper-slide[aria-label="${i + 1} / 5"]`,
+ )
+
+ const tempMaxDiv = await block.$('.meteogram-info-temp-max')
+ const tempMinDiv = await block.$('.meteogram-info-temp-min')
+
+ const maximumTemperature = await tempMaxDiv.evaluate(parseTemp)
+ const minimumTemperature = await tempMinDiv.evaluate(parseTemp)
+
+ return { minimumTemperature, maximumTemperature }
+ }
+
+ const scrapeToday = async () => {
+ let today = {}
+ const indices = range(startTime, endTime)
+ const results = await Promise.all(indices.map(scrapeColumn))
+
+ for (let i = startTime; i < endTime; i++) {
+ today[i] = results[i - startTime]
+ }
+
+ return today
+ }
+
+ const scrapeTomorrow = async () => {
+ let tomorrow = {}
+ const indices = range(24 - startTime, 48 - startTime)
+ const results = await Promise.all(indices.map(scrapeColumn))
+
+ for (let i = 0; i < 24; i++) {
+ tomorrow[i] = results[i]
+ }
+
+ return tomorrow
+ }
+
+ const scrapeDayAfterTomorrow = async () => {
+ let dayAfterTomorrow = {}
+ const indices = range(48 - startTime, 72 - startTime)
+ const results = await Promise.all(indices.map(scrapeColumn))
+
+ for (let i = 0; i < 24; i++) {
+ dayAfterTomorrow[i] = results[i]
+ }
+
+ return dayAfterTomorrow
+ }
+
+ const scrapeWeek = async () => {
+ let week = {}
+ const indices = range(0, 5)
+ const results = await Promise.all(indices.map(scrapeBlock))
+
+ for (let i = 0; i < 5; i++) {
+ week[i] = results[i]
+ }
+
+ return week
+ }
+
+ const [today, tomorrow, dayAfterTomorrow, week] = await Promise.all([
+ scrapeToday(),
+ scrapeTomorrow(),
+ scrapeDayAfterTomorrow(),
+ scrapeWeek(),
+ ])
+
+ await page.close()
+
+ return {
+ format: FORMAT,
+ today,
+ tomorrow,
+ dayAfterTomorrow,
+ week,
+ }
+}