diff --git a/README.md b/README.md index 50b78ef..cfbf9dc 100644 --- a/README.md +++ b/README.md @@ -385,6 +385,666 @@ gismeteo.getTomorrow('London').then((data) => { +### Ten days + +6-hour forecast for ten days. + +```ts +gismeteo.getTenDays('London').then((data) => { + console.log(data) +}) +``` + +
+ Output + +```ts +;[ + { + dt: 1654117200, + temp: 16, + pressure: 752, + wind_speed: 2, + wind_gust: 0, + wind_dir: 'ЮВ', + precipitation: 0, + humidity: 'Ночь', + summary: 'Облачно', + geomagnetic: 2, + road_condition: 'Влажная дорога', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654138800, + temp: 18, + pressure: 752, + wind_speed: 2, + wind_gust: 0, + wind_dir: 'ЮВ', + precipitation: 0, + humidity: 'Утро', + summary: 'Малооблачно', + geomagnetic: 2, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654160400, + temp: 20, + pressure: 751, + wind_speed: 3, + wind_gust: 3, + wind_dir: 'ЮВ', + precipitation: 0, + humidity: 'День', + summary: 'Пасмурно', + geomagnetic: 1, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654182000, + temp: 23, + pressure: 749, + wind_speed: 3, + wind_gust: 5, + wind_dir: 'В', + precipitation: 1.2, + humidity: 'Вечер', + summary: 'Облачно, небольшой дождь, гроза', + geomagnetic: 1, + road_condition: 'Вода', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654203600, + temp: 15, + pressure: 749, + wind_speed: 2, + wind_gust: 7, + wind_dir: 'Ю', + precipitation: 2.7, + humidity: 'Ночь', + summary: 'Пасмурно, дождь', + geomagnetic: 1, + road_condition: 'Вода', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654225200, + temp: 18, + pressure: 748, + wind_speed: 3, + wind_gust: 4, + wind_dir: 'З', + precipitation: 0.4, + humidity: 'Утро', + summary: 'Облачно, небольшой дождь, гроза', + geomagnetic: 2, + road_condition: 'Влажная дорога', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654246800, + temp: 23, + pressure: 749, + wind_speed: 6, + wind_gust: 6, + wind_dir: 'СЗ', + precipitation: 0.3, + humidity: 'День', + summary: 'Пасмурно, небольшой дождь', + geomagnetic: 2, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654268400, + temp: 18, + pressure: 750, + wind_speed: 6, + wind_gust: 9, + wind_dir: 'З', + precipitation: 0.4, + humidity: 'Вечер', + summary: 'Малооблачно, небольшой дождь', + geomagnetic: 1, + road_condition: 'Влажная дорога', + pollen_birch: 1, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654290000, + temp: 12, + pressure: 752, + wind_speed: 4, + wind_gust: 7, + wind_dir: 'З', + precipitation: 0, + humidity: 'Ночь', + summary: 'Ясно', + geomagnetic: 2, + road_condition: 'Сухая дорога', + pollen_birch: 1, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654311600, + temp: 15, + pressure: 752, + wind_speed: 4, + wind_gust: 6, + wind_dir: 'З', + precipitation: 0, + humidity: 'Утро', + summary: 'Малооблачно', + geomagnetic: 2, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654333200, + temp: 20, + pressure: 751, + wind_speed: 5, + wind_gust: 7, + wind_dir: 'З', + precipitation: 0, + humidity: 'День', + summary: 'Малооблачно', + geomagnetic: 1, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654354800, + temp: 20, + pressure: 750, + wind_speed: 5, + wind_gust: 3, + wind_dir: 'З', + precipitation: 0, + humidity: 'Вечер', + summary: 'Пасмурно', + geomagnetic: 1, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 2, + pollen_ragweed: 0, + }, + { + dt: 1654376400, + temp: 15, + pressure: 749, + wind_speed: 2, + wind_gust: 4, + wind_dir: 'Ю', + precipitation: 0, + humidity: 'Ночь', + summary: 'Пасмурно', + geomagnetic: 4, + road_condition: 'Влажная дорога', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654398000, + temp: 16, + pressure: 747, + wind_speed: 3, + wind_gust: 5, + wind_dir: 'З', + precipitation: 2.5, + humidity: 'Утро', + summary: 'Пасмурно, дождь', + geomagnetic: 5, + road_condition: 'Вода', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654419600, + temp: 14, + pressure: 747, + wind_speed: 3, + wind_gust: 5, + wind_dir: 'ЮЗ', + precipitation: 3.9, + humidity: 'День', + summary: 'Пасмурно, дождь', + geomagnetic: 6, + road_condition: 'Влажная дорога', + pollen_birch: 0, + pollen_grass: 2, + pollen_ragweed: 0, + }, + { + dt: 1654441200, + temp: 12, + pressure: 745, + wind_speed: 4, + wind_gust: 6, + wind_dir: 'З', + precipitation: 1.1, + humidity: 'Вечер', + summary: 'Облачно, небольшой дождь', + geomagnetic: 7, + road_condition: 'Влажная дорога', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654462800, + temp: 11, + pressure: 745, + wind_speed: 4, + wind_gust: 8, + wind_dir: 'С', + precipitation: 0, + humidity: 'Ночь', + summary: 'Малооблачно', + geomagnetic: 8, + road_condition: 'Влажная дорога', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654484400, + temp: 13, + pressure: 746, + wind_speed: 5, + wind_gust: 10, + wind_dir: 'СЗ', + precipitation: 0, + humidity: 'Утро', + summary: 'Пасмурно', + geomagnetic: 9, + road_condition: 'Влажная дорога', + pollen_birch: 1, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654506000, + temp: 18, + pressure: 746, + wind_speed: 6, + wind_gust: 10, + wind_dir: 'С', + precipitation: 0.4, + humidity: 'День', + summary: 'Облачно, небольшой дождь', + geomagnetic: 0, + road_condition: 'Влажная дорога', + pollen_birch: 1, + pollen_grass: 2, + pollen_ragweed: 0, + }, + { + dt: 1654527600, + temp: 17, + pressure: 746, + wind_speed: 6, + wind_gust: 8, + wind_dir: 'С', + precipitation: 0, + humidity: 'Вечер', + summary: 'Малооблачно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 1, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654549200, + temp: 12, + pressure: 746, + wind_speed: 4, + wind_gust: 11, + wind_dir: 'СЗ', + precipitation: 0, + humidity: 'Ночь', + summary: 'Ясно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654570800, + temp: 16, + pressure: 747, + wind_speed: 5, + wind_gust: 9, + wind_dir: 'СЗ', + precipitation: 0, + humidity: 'Утро', + summary: 'Малооблачно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654592400, + temp: 21, + pressure: 746, + wind_speed: 6, + wind_gust: 9, + wind_dir: 'СЗ', + precipitation: 0, + humidity: 'День', + summary: 'Малооблачно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654614000, + temp: 17, + pressure: 747, + wind_speed: 4, + wind_gust: 9, + wind_dir: 'СЗ', + precipitation: 0, + humidity: 'Вечер', + summary: 'Малооблачно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654635600, + temp: 13, + pressure: 747, + wind_speed: 4, + wind_gust: 6, + wind_dir: 'З', + precipitation: 0, + humidity: 'Ночь', + summary: 'Малооблачно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 0, + pollen_ragweed: 0, + }, + { + dt: 1654657200, + temp: 15, + pressure: 749, + wind_speed: 3, + wind_gust: 6, + wind_dir: 'СЗ', + precipitation: 0, + humidity: 'Утро', + summary: 'Малооблачно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 1, + pollen_grass: 2, + pollen_ragweed: 0, + }, + { + dt: 1654678800, + temp: 21, + pressure: 748, + wind_speed: 4, + wind_gust: 6, + wind_dir: 'СЗ', + precipitation: 0, + humidity: 'День', + summary: 'Пасмурно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 1, + pollen_grass: 2, + pollen_ragweed: 0, + }, + { + dt: 1654700400, + temp: 18, + pressure: 748, + wind_speed: 4, + wind_gust: 2, + wind_dir: 'С', + precipitation: 0, + humidity: 'Вечер', + summary: 'Малооблачно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654722000, + temp: 13, + pressure: 749, + wind_speed: 2, + wind_gust: 1, + wind_dir: 'СЗ', + precipitation: 0, + humidity: 'Ночь', + summary: 'Малооблачно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654743600, + temp: 16, + pressure: 750, + wind_speed: 2, + wind_gust: 2, + wind_dir: 'СВ', + precipitation: 0, + humidity: 'Утро', + summary: 'Пасмурно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 2, + pollen_ragweed: 0, + }, + { + dt: 1654765200, + temp: 22, + pressure: 750, + wind_speed: 3, + wind_gust: 3, + wind_dir: 'С', + precipitation: 0, + humidity: 'День', + summary: 'Пасмурно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 2, + pollen_ragweed: 0, + }, + { + dt: 1654786800, + temp: 19, + pressure: 752, + wind_speed: 3, + wind_gust: 6, + wind_dir: 'СВ', + precipitation: 0, + humidity: 'Вечер', + summary: 'Малооблачно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 2, + pollen_ragweed: 0, + }, + { + dt: 1654808400, + temp: 13, + pressure: 752, + wind_speed: 2, + wind_gust: 3, + wind_dir: 'В', + precipitation: 0, + humidity: 'Ночь', + summary: 'Пасмурно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654830000, + temp: 16, + pressure: 753, + wind_speed: 2, + wind_gust: 2, + wind_dir: 'ЮВ', + precipitation: 0, + humidity: 'Утро', + summary: 'Пасмурно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 2, + pollen_ragweed: 0, + }, + { + dt: 1654851600, + temp: 22, + pressure: 752, + wind_speed: 1, + wind_gust: 5, + wind_dir: 'ЮВ', + precipitation: 0, + humidity: 'День', + summary: 'Пасмурно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 2, + pollen_ragweed: 0, + }, + { + dt: 1654873200, + temp: 18, + pressure: 752, + wind_speed: 3, + wind_gust: 3, + wind_dir: 'В', + precipitation: 0, + humidity: 'Вечер', + summary: 'Малооблачно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 2, + pollen_ragweed: 0, + }, + { + dt: 1654894800, + temp: 13, + pressure: 753, + wind_speed: 2, + wind_gust: 2, + wind_dir: 'СВ', + precipitation: 0, + humidity: 'Ночь', + summary: 'Ясно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 1, + pollen_ragweed: 0, + }, + { + dt: 1654916400, + temp: 16, + pressure: 753, + wind_speed: 2, + wind_gust: 3, + wind_dir: 'В', + precipitation: 0, + humidity: 'Утро', + summary: 'Ясно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 3, + pollen_ragweed: 0, + }, + { + dt: 1654938000, + temp: 23, + pressure: 752, + wind_speed: 3, + wind_gust: 3, + wind_dir: 'Ю', + precipitation: 0, + humidity: 'День', + summary: 'Малооблачно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 2, + pollen_ragweed: 0, + }, + { + dt: 1654959600, + temp: 20, + pressure: 752, + wind_speed: 3, + wind_gust: 5, + wind_dir: 'В', + precipitation: 0, + humidity: 'Вечер', + summary: 'Малооблачно', + geomagnetic: 0, + road_condition: 'Сухая дорога', + pollen_birch: 0, + pollen_grass: 2, + pollen_ragweed: 0, + }, +] +``` + +
+ ### Two weeks 1-day forecast for two weeks diff --git a/src/common/constants.ts b/src/common/constants.ts index a0274c5..8f9cf75 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -6,6 +6,7 @@ export enum Endpoint { MONTH = 'month/', NOW = 'now/', TOMMOROW = 'tomorrow/', + TENDAYS = '3-days/', } export enum Unit { @@ -63,4 +64,5 @@ export enum Wildcard { ONEDAY_PRESSURE = 'div[data-stat-value*="pressure"] div.widget-row-chart-pressure div.value span.UNIT_PRESSURE', ONEDAY_HUMIDITY = 'div[data-stat-value*="humidity"] div.widget-items div.row-item', ONEDAY_GEOMAGNETIC = 'div[data-stat-value*="geomagnetic"] div.row-item div.item', + TENDAYS_TIME = 'div[data-stat-value*="weather"] div.widget-date-wrap a.item', } diff --git a/src/common/types.ts b/src/common/types.ts index 05ab9fa..fbd1679 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -64,5 +64,6 @@ export type GismeteoOneDay = { export type GismeteoToday = GismeteoOneDay export type GismeteoTomorrow = GismeteoOneDay +export type GismeteoTenDays = GismeteoOneDay export type CityUri = string diff --git a/src/gismeteo.ts b/src/gismeteo.ts index 543fe71..f6ba271 100644 --- a/src/gismeteo.ts +++ b/src/gismeteo.ts @@ -6,7 +6,7 @@ import is_number from 'is-number' import { Endpoint, Unit, Wildcard } from './common/constants' import { GismeteoCityError, GismeteoConnectionError } from './common/errors' -import { CityUri, GismeteoMonth, GismeteoNow, GismeteoOptions, GismeteoTwoWeeks, GismeteoOneDay } from './common/types' +import { CityUri, GismeteoMonth, GismeteoNow, GismeteoOptions, GismeteoTwoWeeks, GismeteoOneDay, GismeteoTenDays } from './common/types' export class Gismeteo { private _base_url: Endpoint @@ -239,6 +239,72 @@ export class Gismeteo { }) } + /** + * It takes a city name, gets the city URI, then makes a request to the Gismeteo site, parses the + * HTML, and returns an array of GismeteoTenDays + * @param {string} city - string - the name of the city you want to get the weather for + * @returns An array of GismeteoTenDays. + */ + public async getTenDays(city: string): Promise { + const city_uri = await this.getCityUri(city) + + return axios + .get(`${this._base_url}${city_uri}${Endpoint.TENDAYS}`, this._axios_config) + .then(({ data }) => { + const $ = load(this.prepareHtml(data)) + let out: Partial[] = [] + + out = this.parseDatesFromDaytime>($, Wildcard.TENDAYS_TIME) + out = this.mergeArray(out, 'temp', this.parseValue($, Wildcard.ONEDAY_TEMP)) + out = this.mergeArray(out, 'pressure', this.parseValue($, Wildcard.ONEDAY_PRESSURE)) + out = this.mergeArray(out, 'wind_speed', this.parseValue($, Wildcard.ONEDAY_WINDSPEED)) + out = this.mergeArray(out, 'wind_gust', this.parseValue($, Wildcard.ONEDAY_WINDGUST)) + out = this.mergeArray(out, 'wind_dir', this.parseValue($, Wildcard.ONEDAY_WINDDIR)) + out = this.mergeArray(out, 'precipitation', this.parseValue($, Wildcard.ONEDAY_PRECIPITATION)) + out = this.mergeArray(out, 'humidity', this.parseValue($, Wildcard.ONEDAY_HUMIDITY)) + out = this.mergeArray(out, 'summary', this.parseAttr($, Wildcard.ONEDAY_SUMMARY, 'data-text')) + out = this.mergeArray(out, 'geomagnetic', this.parseValue($, Wildcard.ONEDAY_GEOMAGNETIC)) + + if ($(Wildcard.ONEDAY_ROADS).length > 0) { + out = this.mergeArray(out, 'road_condition', this.parseValue($, Wildcard.ONEDAY_ROADS)) + } else { + out = this.mergeArray(out, 'road_condition', new Array(out.length).fill('unknown')) + } + if ($(Wildcard.ONEDAY_POLLEN_BIRCH).length > 0) { + out = this.mergeArray(out, 'pollen_birch', this.parseValue($, Wildcard.ONEDAY_POLLEN_BIRCH)) + } else { + out = this.mergeArray(out, 'pollen_birch', new Array(out.length).fill(0)) + } + if ($(Wildcard.ONEDAY_POLLEN_GRASS).length > 0) { + out = this.mergeArray(out, 'pollen_grass', this.parseValue($, Wildcard.ONEDAY_POLLEN_GRASS)) + } else { + out = this.mergeArray(out, 'pollen_grass', new Array(out.length).fill(0)) + } + if ($(Wildcard.ONEDAY_POLLEN_RAGWEED).length > 0) { + out = this.mergeArray(out, 'pollen_ragweed', this.parseValue($, Wildcard.ONEDAY_POLLEN_RAGWEED)) + } else { + out = this.mergeArray(out, 'pollen_ragweed', new Array(out.length).fill(0)) + } + + out.forEach((item, index) => { + if (item.geomagnetic === undefined) { + out[index].geomagnetic = 0 + } + }) + + console.log(out) + + return out as GismeteoTenDays[] + }) + .catch((err) => { + if (err instanceof GismeteoCityError) { + throw err + } else { + throw new GismeteoConnectionError(err) + } + }) + } + /** * "If the city is in the cache, return the city uri from the cache, otherwise, make a request to the * Gismeteo API to get the city uri and then cache it." @@ -296,6 +362,18 @@ export class Gismeteo { return out } + private parseDatesFromDaytime($: CheerioAPI, wildcard: Wildcard): T[] { + const search = $(wildcard) + const start_date = moment(search.first().text().trim().split(', ')[1] + moment().format('YYYY'), 'DD MMMYYYY', 'ru') + const out: T[] = [] + + for (let i = 0; i < search.length * 4; i++) { + out.push({ dt: start_date.add(i > 0 ? 6 : 0, 'hour').unix() } as unknown as T) + } + + return out + } + private parseValue($: CheerioAPI, wildcard: Wildcard): T[] { const out: T[] = [] const search = $(this.unitToWildcard(wildcard)) diff --git a/test/gismeteo.test.ts b/test/gismeteo.test.ts index 7deb233..50ec6d3 100644 --- a/test/gismeteo.test.ts +++ b/test/gismeteo.test.ts @@ -1,5 +1,5 @@ import { Gismeteo } from '../src/gismeteo' -import { GismeteoTomorrow, GismeteoTwoWeeks, GismeteoMonth, GismeteoNow, GismeteoToday } from '../src/common/types' +import { GismeteoTomorrow, GismeteoTwoWeeks, GismeteoMonth, GismeteoNow, GismeteoToday, GismeteoTenDays } from '../src/common/types' jest.setTimeout(15000) @@ -54,6 +54,22 @@ describe('Gismeteo', () => { }) }) + describe('getTenDays', () => { + let result: GismeteoTenDays[] + + beforeAll(async () => { + result = await gismeteo.getTenDays('Moscow') + }) + + test('should contain 40 items', () => { + expect(result.length).toBe(40) + }) + + test('should not contain any undefined values', () => { + expect(undefInArray(result)).toBeFalsy() + }) + }) + describe('getTwoWeeks', () => { let result: GismeteoTwoWeeks[]