update for new parsing url swp_
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import logging
|
||||
import urllib.request
|
||||
import re
|
||||
import time
|
||||
import json
|
||||
|
||||
|
||||
class SWP_Webspeiseplan_API:
|
||||
def __init__(self):
|
||||
logging.basicConfig()
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.url_base = "https://swp.webspeiseplan.de"
|
||||
self.__parse_token()
|
||||
params = {
|
||||
"token": self.proxy_token,
|
||||
"model": "outlet",
|
||||
"location": "",
|
||||
"languagetype": "",
|
||||
"_": int(time.time() * 1000),
|
||||
}
|
||||
|
||||
self.outlets = {outlet["name"]: outlet for outlet in self.__parse_model(params)}
|
||||
self.menus = {}
|
||||
self.meal_categories = {}
|
||||
for outlet in self.outlets.values():
|
||||
params["model"] = "menu"
|
||||
params["location"] = outlet["standortID"]
|
||||
params["languagetype"] = 2
|
||||
params["_"] = int(time.time() * 1000)
|
||||
menu = self.__parse_model(params)
|
||||
self.menus[outlet["name"]] = menu
|
||||
|
||||
params["model"] = "mealCategory"
|
||||
params["_"] = int(time.time() * 1000)
|
||||
categories = self.__parse_model(params)
|
||||
id2cat = {item["gerichtkategorieID"]: item for item in categories}
|
||||
self.meal_categories[outlet["name"]] = id2cat
|
||||
|
||||
def __parse_token(self):
|
||||
req = urllib.request.Request(self.url_base)
|
||||
with urllib.request.urlopen(req) as resp:
|
||||
txt = resp.read().decode("utf-8")
|
||||
match = re.findall(r"/main.[0-9a-f]+.js", txt)[0]
|
||||
self.logger.debug(f"__parse_token: downloading script {match}")
|
||||
req = urllib.request.Request(f"{self.url_base}{match}")
|
||||
with urllib.request.urlopen(req) as resp:
|
||||
txt = resp.read().decode("utf-8")
|
||||
self.proxy_token = re.findall(r"PROXY_TOKEN:\"([0-9a-f]+)\"", txt)[0]
|
||||
self.logger.debug(f"__parse_token: PROXY_TOKEN {self.proxy_token}")
|
||||
|
||||
def __spoof_req_headers(req: urllib.request.Request):
|
||||
req.add_header("Accept", "application/json, text/javascript, */*; q=0.01")
|
||||
req.add_header("Accept-Language", "en-US,en;q=0.9")
|
||||
req.add_header("Connection", "keep-alive")
|
||||
req.add_header("Host", "swp.webspeiseplan.de")
|
||||
req.add_header("Referer", "https://swp.webspeiseplan.de/InitialConfig")
|
||||
req.add_header(
|
||||
"Sec-Ch-Ua",
|
||||
'"Not/A)Brand";v="99", "Google Chrome";v="115", "Chromium";v="115"',
|
||||
)
|
||||
req.add_header("Sec-Ch-Ua-Mobile", "?0")
|
||||
req.add_header("Sec-Ch-Ua-Platform", "Linux")
|
||||
req.add_header("Sec-Fetch-Dest", "empty")
|
||||
req.add_header("Sec-Fetch-Mode", "cors")
|
||||
req.add_header("Sec-Fetch-Site", "same-origin")
|
||||
req.add_header(
|
||||
"User-Agent",
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36",
|
||||
)
|
||||
req.add_header("X-Requested-With", "XMLHttpRequest")
|
||||
|
||||
def __parse_model(self, params: dict):
|
||||
url = f"{self.url_base}/index.php?" + "&".join(
|
||||
[f"{k}={v}" for k, v in params.items()]
|
||||
)
|
||||
self.logger.debug(f"__parse_model: {url}")
|
||||
req = urllib.request.Request(url)
|
||||
SWP_Webspeiseplan_API.__spoof_req_headers(req)
|
||||
with urllib.request.urlopen(req) as resp:
|
||||
data = resp.read()
|
||||
return json.loads(data)["content"]
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import logging
|
||||
from pyopenmensa.feed import LazyBuilder
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class SWP_Webspeiseplan_Parser:
|
||||
def __init__(
|
||||
self, menu_data: list[dict], meal_categories: list[dict], outlet_data: dict
|
||||
):
|
||||
logging.basicConfig()
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.menu_data = menu_data
|
||||
self.meal_categories = meal_categories
|
||||
self.outlet_data = outlet_data
|
||||
self.canteen = None
|
||||
self.__parse_canteen(outlet_data)
|
||||
self.__parse_meals()
|
||||
|
||||
def __parse_canteen(self, outlet: dict):
|
||||
builder = LazyBuilder()
|
||||
builder.name = outlet["name"]
|
||||
builder.address = outlet["addressInfo"]["street"]
|
||||
builder.city = (
|
||||
f'{outlet["addressInfo"]["postalCode"]} {outlet["addressInfo"]["city"]}'
|
||||
)
|
||||
builder.phone = outlet["contactInfo"][0]["phone"]
|
||||
builder.email = outlet["contactInfo"][0]["email"]
|
||||
if outlet["positionInfo"]:
|
||||
builder.location(
|
||||
str(outlet["positionInfo"]["longitude"]),
|
||||
str(outlet["positionInfo"]["latitude"]),
|
||||
)
|
||||
|
||||
builder.availability = f"Montag: {outlet['moZeit1']}, {outlet['moZeit2']}\n"
|
||||
builder.availability += f"Dienstag: {outlet['diZeit1']}, {outlet['diZeit2']}\n"
|
||||
builder.availability += f"Mittwoch: {outlet['miZeit1']}, {outlet['miZeit2']}\n"
|
||||
builder.availability += (
|
||||
f"Donnerstag: {outlet['doZeit1']}, {outlet['doZeit2']}\n"
|
||||
)
|
||||
builder.availability += f"Freitag: {outlet['frZeit1']}, {outlet['frZeit2']}\n"
|
||||
builder.availability += f"Samstag: {outlet['saZeit1']}, {outlet['saZeit2']}\n"
|
||||
builder.availability += f"Sonntag: {outlet['soZeit1']}, {outlet['soZeit2']}"
|
||||
builder.availability = (
|
||||
builder.availability.replace("None, None", "")
|
||||
.replace("None,", "")
|
||||
.replace(", None", "")
|
||||
)
|
||||
|
||||
self.canteen = builder
|
||||
|
||||
def __parse_meals(self):
|
||||
for menu in self.menu_data:
|
||||
for meal in menu["speiseplanGerichtData"]:
|
||||
info = meal["speiseplanAdvancedGericht"]
|
||||
date = datetime.fromisoformat(info["datum"]).date()
|
||||
|
||||
additional_info = meal["zusatzinformationen"]
|
||||
self.canteen.addMeal(
|
||||
date=date,
|
||||
category=self.meal_categories[info["gerichtkategorieID"]]["name"],
|
||||
name=info["gerichtname"],
|
||||
prices={
|
||||
"employee": f'{additional_info["mitarbeiterpreisDecimal2"]:.2f}',
|
||||
"other": f'{additional_info["gaestepreisDecimal2"]:.2f}',
|
||||
},
|
||||
)
|
||||
|
||||
@property
|
||||
def xml_feed(self):
|
||||
return self.canteen.toXMLFeed()
|
||||
@@ -11,6 +11,8 @@ from flask.logging import create_logger
|
||||
from stw_potsdam import feed
|
||||
from stw_potsdam.config import read_canteen_config
|
||||
from stw_potsdam.canteen_api import MenuParams, download_menu
|
||||
from stw_potsdam.swp_webspeiseplan_api import SWP_Webspeiseplan_API
|
||||
from stw_potsdam.swp_webspeiseplan_parser import SWP_Webspeiseplan_Parser
|
||||
|
||||
CACHE_TIMEOUT = 45 * 60
|
||||
|
||||
@@ -32,6 +34,7 @@ if 'BASE_URL' in os.environ: # pragma: no cover
|
||||
|
||||
cache = ct.TTLCache(maxsize=30, ttl=CACHE_TIMEOUT)
|
||||
|
||||
swp_api = SWP_Webspeiseplan_API()
|
||||
|
||||
def canteen_not_found(config, canteen_name):
|
||||
log.warning('Canteen %s not found', canteen_name)
|
||||
@@ -90,8 +93,12 @@ def canteen_menu_feed(canteen_name):
|
||||
return canteen_not_found(config, canteen_name)
|
||||
|
||||
canteen = config[canteen_name]
|
||||
menu = get_menu(canteen)
|
||||
return canteen_menu_feed_xml(menu)
|
||||
swp_parser = SWP_Webspeiseplan_Parser(
|
||||
swp_api.menus[canteen.name],
|
||||
swp_api.meal_categories[canteen.name],
|
||||
swp_api.outlets[canteen.name],
|
||||
)
|
||||
return _canteen_feed_xml(swp_parser.xml_feed)
|
||||
|
||||
|
||||
@app.route('/')
|
||||
|
||||
Reference in New Issue
Block a user