Files
gallery/gallery/painting/gismeteo/parser.py

207 lines
6.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import datetime
import re
from typing import Iterable
import dateparser
from bs4 import Tag
from gallery.sketch.weather.model import (
Cloudness,
Precipitation,
Sky,
WindDirection,
WindDirectionDeg,
)
from .core import BaseWidgetParser, RowParser
ONE_DAY_PARSER = BaseWidgetParser(".widget.widget-oneday .widget-items")
DAYS_PARSER = BaseWidgetParser(".widget.widget-days .widget-items")
class LocationParser:
PATTERN = re.compile('{"ru":{"city":{"name":"(.*?)"')
def parse_location(self, data: str) -> str | None:
match = self.PATTERN.search(data)
if match:
return match.group(1)
return None
LOCATION_PARSER = LocationParser()
class DateParser(RowParser[datetime.datetime]):
KEY = "date"
def parse_row(self, tag: Tag) -> Iterable[datetime.datetime]:
datetime_date_tag = tag.select_one(
".widget-row.widget-row-datetime-date > .row-item"
)
if datetime_date_tag:
date_str = datetime_date_tag.find(text=True, recursive=False).text
date = dateparser.parse(date_str, languages=["ru"])
for item in tag.select(".widget-row.widget-row-datetime-time > .row-item"):
time_str = item.text
time = dateparser.parse(time_str, languages=["ru"])
time = time.replace(year=date.year, month=date.month, day=date.day)
yield time
else:
for item in tag.select(".widget-row.widget-row-date > .row-item"):
date_str = item.text
date = dateparser.parse(date_str, languages=["ru"])
yield date
class SkyParser(RowParser[Sky]):
KEY = "sky"
CLOUDNESS_MAP: dict[str, Cloudness] = {
"ясно": Cloudness.CLEAR,
"малооблачно": Cloudness.PARTLY_CLOUDY,
"облачно": Cloudness.CLOUDY,
"пасмурно": Cloudness.MAINLY_CLOUDY,
}
PRECIPITATION_MAP: dict[str, Precipitation] = {
"без осадков": Precipitation.NO,
"небольшой дождь": Precipitation.SMALL_RAIN,
"сильный дождь": Precipitation.HEAVY_RAIN,
"дождь": Precipitation.RAIN,
"ливень": Precipitation.SHOWER,
"снег": Precipitation.SNOW,
"небольшой снег": Precipitation.SNOW,
"сильный снег": Precipitation.HEAVY_SNOW,
"мокрый снег": Precipitation.SNOW,
"снег с дождём": Precipitation.SNOW,
"сильный снег с дождём": Precipitation.HEAVY_SNOW,
"небольшой снег с дождём": Precipitation.SNOW,
"небольшой мокрый снег": Precipitation.SNOW,
}
def parse_row(self, tag: Tag) -> Iterable[Sky]:
for item in tag.select(".widget-row[data-row=icon-tooltip] > .row-item"):
sky_str = item.attrs["data-tooltip"]
values = {item.strip().lower() for item in sky_str.split(",")}
cloudness = Cloudness.CLEAR
precipitation = Precipitation.NO
thunder = "гроза" in values
fog = "дымка" in values
for k, v in self.CLOUDNESS_MAP.items():
if k in values:
cloudness = v
break
for k, v in self.PRECIPITATION_MAP.items():
if k in values:
precipitation = v
break
yield Sky(
cloudness=cloudness,
precipitation=precipitation,
thunder=thunder,
fog=fog,
)
class TemperatureParser(RowParser[list[int]]):
KEY = "temperature"
def parse_row(self, tag: Tag) -> Iterable[list[int]]:
for item in tag.select(
".widget-row-chart[data-row=temperature-air] > .chart > .values > .value"
):
yield [
int(value.attrs["value"]) for value in item.select("temperature-value")
]
class WindSpeedParser(RowParser[int]):
KEY = "wind_speed"
def parse_row(self, tag: Tag) -> Iterable[int]:
for item in tag.select(
".widget-row-wind > .row-item > .wind-speed > speed-value"
):
yield int(item.attrs["value"])
class WindGustParser(RowParser[int]):
KEY = "wind_gust"
def parse_row(self, tag: Tag) -> Iterable[int]:
for item in tag.select(".widget-row-wind > .row-item > .wind-gust"):
value = item.select_one("speed-value")
yield int(value.attrs["value"]) if value else 0
class WindDirectionParser(RowParser[WindDirection]):
KEY = "wind_direction"
WIND_DIRECTION_MAP: dict[str, WindDirection] = {
"": WindDirection.CALM,
"штиль": WindDirection.CALM,
"с": WindDirection.N,
"св": WindDirection.NE,
"в": WindDirection.E,
"юв": WindDirection.SE,
"ю": WindDirection.S,
"юз": WindDirection.SW,
"з": WindDirection.W,
"сз": WindDirection.NW,
}
def parse_row(self, tag: Tag) -> Iterable[float]:
for item in tag.select(
".widget-row-wind > .row-item > .wind-speed > .wind-direction"
):
wind_direction_str = item.text.lower().strip()
yield WindDirectionDeg.from_direction(
self.WIND_DIRECTION_MAP[wind_direction_str]
).value
class PrecipitationParser(RowParser[float]):
KEY = "precipitation"
def parse_row(self, tag: Tag) -> Iterable[float]:
for item in tag.select(
".widget-row[data-row=precipitation-bars] > .row-item > .item-unit"
):
yield float(item.text.replace(",", "."))
class PressureParser(RowParser[list[int]]):
KEY = "pressure"
def parse_row(self, tag: Tag) -> Iterable[list[int]]:
for item in tag.select(
".widget-row-chart[data-row=pressure] > .chart > .values > .value"
):
yield [int(value.attrs["value"]) for value in item.select("pressure-value")]
class HumidityParser(RowParser[int]):
KEY = "humidity"
def parse_row(self, tag: Tag) -> Iterable[int]:
for item in tag.select(
".widget-row[data-row=humidity] > .row-item, .widget-row[data-row=humidity-avg] > .row-item"
):
yield int(item.text)
ROW_PARSERS: list[RowParser] = [
DateParser(),
SkyParser(),
TemperatureParser(),
WindSpeedParser(),
WindGustParser(),
WindDirectionParser(),
PrecipitationParser(),
PressureParser(),
HumidityParser(),
]
ROW_PARSERS_MAP: dict[str, RowParser] = {parser.KEY: parser for parser in ROW_PARSERS}