feat(parser): use ParserError in parsers

This commit is contained in:
2026-09-23 16:12:13 +03:00
parent 73df7a2b5d
commit 829a12612e
6 changed files with 30 additions and 26 deletions
+1 -1
View File
@@ -66,7 +66,7 @@ https://api.shmyga.ru/api/schedule/{provider}/{channel_id}/{date}
| Provider | Site | API sample | | Provider | Site | API sample |
| :- | :- | :- | | :- | :- | :- |
| matchtv | https://matchtv.ru/tvguide | https://api.shmyga.ru/api/schedule/matchtv/igra/today | | matchtv | https://matchtv.ru/tvguide | https://api.shmyga.ru/api/schedule/matchtv/igra/today |
| yandex | https://tv.yandex.ru | https://api.shmyga.ru/api/schedule/yandex/146/today | | yandex | https://tv.yandex.ru | https://api.shmyga.ru/api/schedule/yandex/start-103/today |
## Demo ## Demo
+1 -4
View File
@@ -1,5 +1,4 @@
import datetime import datetime
import logging
import re import re
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any, Literal from typing import Any, Literal
@@ -24,8 +23,6 @@ from gallery.sketch.weather.util import fix_dates_sequence, merge_weather_values
from . import PROVIDER from . import PROVIDER
logger = logging.getLogger(PROVIDER)
class LocationNameParser(Parser[str, str]): class LocationNameParser(Parser[str, str]):
PATTERN = re.compile('{"ru":{"city":{"name":"(.*?)"') PATTERN = re.compile('{"ru":{"city":{"name":"(.*?)"')
@@ -112,7 +109,7 @@ class SkyParser(TableValueParser[Sky]):
values.remove(k) values.remove(k)
break break
if values: if values:
logger.warning("unknown sky values: %s:", values) raise ParseError("Unknown sky values", values)
return Sky( return Sky(
cloudness=cloudness, cloudness=cloudness,
precipitation=precipitation, precipitation=precipitation,
+2 -1
View File
@@ -10,6 +10,7 @@ from gallery.sketch.weather.model import (
from gallery.sketch.weather.parse.wind import WIND_DIRECTION_PARSER from gallery.sketch.weather.parse.wind import WIND_DIRECTION_PARSER
from gallery.sketch.weather.util import convert_hPa_to_mmHg from gallery.sketch.weather.util import convert_hPa_to_mmHg
from . import PROVIDER
from .openweather import Forecast, ForecastItem from .openweather import Forecast, ForecastItem
from .openweather import Location as OpenWeatherLocation from .openweather import Location as OpenWeatherLocation
@@ -71,7 +72,7 @@ class OpenWeatherLocationParser(Parser[list[OpenWeatherLocation], list[Location]
Location( Location(
id=f"{item.lat}:{item.lon}", id=f"{item.lat}:{item.lon}",
name=item.name, name=item.name,
provider="openweather", provider=PROVIDER,
lat=item.lat, lat=item.lat,
lon=item.lon, lon=item.lon,
country=item.country, country=item.country,
+5
View File
@@ -3,6 +3,7 @@ import re
from bs4 import Tag from bs4 import Tag
from gallery.sketch.parse.core import ParseError
from gallery.sketch.parse.date import DATE_PARSER from gallery.sketch.parse.date import DATE_PARSER
from gallery.sketch.parse.html import ( from gallery.sketch.parse.html import (
HTMLParser, HTMLParser,
@@ -72,6 +73,8 @@ class CloudnessParser(TableValueParser[Cloudness]):
def extract(self, data: Tag) -> Cloudness: def extract(self, data: Tag) -> Cloudness:
onmouseover = data.select_one(".cc_0").next_element.attrs["onmouseover"] onmouseover = data.select_one(".cc_0").next_element.attrs["onmouseover"]
cloudness_str = re.compile("<b>(.*?)</b>").search(onmouseover).group(1).strip() cloudness_str = re.compile("<b>(.*?)</b>").search(onmouseover).group(1).strip()
if cloudness_str not in self.CLOUDNESS_MAP:
raise ParseError("Unknown cloudness value", cloudness_str)
return self.CLOUDNESS_MAP[cloudness_str] return self.CLOUDNESS_MAP[cloudness_str]
@@ -95,6 +98,8 @@ class PrecipitationParser(TableValueParser[tuple[Precipitation, float]]):
precipitation_value = float(precipitation_value_matched.group(1)) * 6 precipitation_value = float(precipitation_value_matched.group(1)) * 6
if " (" in precipitation_str: if " (" in precipitation_str:
precipitation_str = precipitation_str.split(" (")[0] precipitation_str = precipitation_str.split(" (")[0]
if precipitation_str not in self.PRECIPITATION_MAP:
raise ParseError("Unknown precipitation value", precipitation_str)
return self.PRECIPITATION_MAP[precipitation_str], precipitation_value return self.PRECIPITATION_MAP[precipitation_str], precipitation_value
+2 -2
View File
@@ -4,7 +4,7 @@ from typing import Any
from bs4 import Tag from bs4 import Tag
from gallery.sketch.parse.core import ParsedContext from gallery.sketch.parse.core import ParsedContext, ParseError
from gallery.sketch.parse.json import JSONParser from gallery.sketch.parse.json import JSONParser
from gallery.sketch.schedule.model import Channel, Schedule, ScheduleValue from gallery.sketch.schedule.model import Channel, Schedule, ScheduleValue
@@ -22,7 +22,7 @@ class ScheduleData:
class YandexTVScheduleParser(HTMLContextParser[ScheduleData, Schedule]): class YandexTVScheduleParser(HTMLContextParser[ScheduleData, Schedule]):
def extract(self, data: ParsedContext[ScheduleData, Tag]) -> Schedule: def extract(self, data: ParsedContext[ScheduleData, Tag]) -> Schedule:
if data.data.select_one(".CheckboxCaptcha") is not None: if data.data.select_one(".CheckboxCaptcha") is not None:
raise RuntimeError("Captcha") raise ParseError("Captcha")
values = [] values = []
channel_name = data.data.select_one(".channel-header__text").text.strip() channel_name = data.data.select_one(".channel-header__text").text.strip()
current_day = datetime.datetime.combine(data.context.date, datetime.datetime.min.time()) current_day = datetime.datetime.combine(data.context.date, datetime.datetime.min.time())
+19 -18
View File
@@ -1,9 +1,9 @@
import datetime import datetime
import logging
from typing import Any from typing import Any
from bs4 import Tag from bs4 import Tag
from gallery.sketch.parse.core import ParseError
from gallery.sketch.parse.date import DATE_PARSER from gallery.sketch.parse.date import DATE_PARSER
from gallery.sketch.parse.html import ( from gallery.sketch.parse.html import (
HTMLParser, HTMLParser,
@@ -25,8 +25,6 @@ from gallery.sketch.weather.parse.wind import WIND_DIRECTION_PARSER
from . import PROVIDER from . import PROVIDER
logger = logging.getLogger(PROVIDER)
class LocationNameParser(TagParser[str]): class LocationNameParser(TagParser[str]):
selector = "[class^=Suggest_placeholder]" selector = "[class^=Suggest_placeholder]"
@@ -70,28 +68,31 @@ class SkyParser(TableValueParser[Sky]):
selector = "[style$='-text']" selector = "[style$='-text']"
model_key = "sky" model_key = "sky"
CLOUDNESS_MAP = {
"ясно": Cloudness.CLEAR,
"облачно с прояснениями": Cloudness.CLOUDY,
"малооблачно": Cloudness.CLOUDY,
"пасмурно": Cloudness.MAINLY_CLOUDY,
}
PRECIPITATION_MAP = {
"небольшой дождь": Precipitation.SMALL_RAIN,
"дождь": Precipitation.RAIN,
"ливень": Precipitation.SHOWER,
}
def extract(self, data: Tag) -> Sky: def extract(self, data: Tag) -> Sky:
sky = data.text.strip() sky = data.text.strip()
cloudness = Cloudness.CLEAR cloudness = Cloudness.CLEAR
precipitation = Precipitation.NO precipitation = Precipitation.NO
thunder = False thunder = False
fog = False fog = False
if sky == "ясно": if sky in self.CLOUDNESS_MAP:
pass cloudness = self.CLOUDNESS_MAP[sky]
elif sky == "облачно с прояснениями": elif sky in self.PRECIPITATION_MAP:
cloudness = Cloudness.PARTLY_CLOUDY precipitation = self.PRECIPITATION_MAP[sky]
elif sky == "малооблачно":
cloudness = Cloudness.CLOUDY
elif sky == "пасмурно":
cloudness = Cloudness.MAINLY_CLOUDY
elif sky == "небольшой дождь":
precipitation = Precipitation.SMALL_RAIN
elif sky == "дождь":
precipitation = Precipitation.RAIN
elif sky == "ливень":
precipitation = Precipitation.SHOWER
else: else:
logger.warning("unknown sky value: %s", sky) raise ParseError("Unknown sky value", sky)
return Sky( return Sky(
cloudness=cloudness, cloudness=cloudness,
precipitation=precipitation, precipitation=precipitation,