From 86e0bc8e51be4dc919a1fcc5a9b987fcd6340dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Janek=20Hlavat=C3=BD?= Date: Sat, 21 Mar 2026 17:58:06 +0100 Subject: [PATCH] Screenshotter --- config/application.yml | 5 +++- experimenty/screenshotter.py | 10 ------- pyproject.toml | 1 + src/beaky/cli.py | 38 ++++++++++++++---------- src/beaky/config.py | 3 ++ src/beaky/scanner/scanner.py | 3 +- src/beaky/screenshotter/__init__.py | 0 src/beaky/screenshotter/config.py | 5 ++++ src/beaky/screenshotter/screenshotter.py | 26 ++++++++++++++++ 9 files changed, 63 insertions(+), 28 deletions(-) delete mode 100644 experimenty/screenshotter.py create mode 100644 src/beaky/screenshotter/__init__.py create mode 100644 src/beaky/screenshotter/config.py create mode 100644 src/beaky/screenshotter/screenshotter.py diff --git a/config/application.yml b/config/application.yml index 22e2237..dbd40c4 100644 --- a/config/application.yml +++ b/config/application.yml @@ -1 +1,4 @@ -path: data/odkazy.xlsx \ No newline at end of file +path: data/odkazy.xlsx + +screenshotter: + target_path: data/screenshots/ diff --git a/experimenty/screenshotter.py b/experimenty/screenshotter.py deleted file mode 100644 index 50831ae..0000000 --- a/experimenty/screenshotter.py +++ /dev/null @@ -1,10 +0,0 @@ -from playwright.sync_api import sync_playwright - -def capture_ticket(url, path, ticket_selector = ".ticket-detail-wrapper"): - with sync_playwright() as p: - browser = p.chromium.launch(headless=True) - page = browser.new_page() - page.goto(url) - page.wait_for_selector(ticket_selector) - page.locator(ticket_selector).screenshot(path=path) - browser.close() diff --git a/pyproject.toml b/pyproject.toml index 26138e2..e7af3d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,6 +13,7 @@ dependencies = [ "pandas==3.0.1", "openpyxl>=3.1.0", "PyYaml==6.0.3", + "playwright==1.58.0" ] [project.optional-dependencies] diff --git a/src/beaky/cli.py b/src/beaky/cli.py index 86ffdc6..cac19a0 100644 --- a/src/beaky/cli.py +++ b/src/beaky/cli.py @@ -1,32 +1,38 @@ import argparse - +from datetime import datetime import yaml from pydantic import ValidationError from beaky.config import Config -from beaky.scanner.scanner import Links +from beaky.scanner.scanner import Link +from beaky.screenshotter.screenshotter import Screenshotter -def main() -> None: - parser = argparse.ArgumentParser( - prog="beaky" - ) - parser.add_argument("--config", help="Path to config file.", default="config/application.yml") - args = parser.parse_args() - - with open(args.config) as f: +def load_config(path: str) -> Config | None: + with open(path) as f: config_dict = yaml.safe_load(f) try: - config = Config(**config_dict) + return Config(**config_dict) except ValidationError as e: - print("Bad arguments") + print("Bad config") print(e) + return None + +def main() -> None: + parser = argparse.ArgumentParser(prog="beaky") + parser.add_argument("--config", help="Path to config file.", default="config/application.yml") + parser.add_argument("mode", choices=["screenshotter"], help="Mode of operation.") + + args = parser.parse_args() + config = load_config(args.config) + if config is None: return - data = Links(config.path) - data.ret_links() - for link in data: - print(link) + if args.mode == "screenshotter": + screenshotter = Screenshotter(config) + screenshotter.capture_tickets([Link("1", +"https://applink.ifortuna.cz/ticketdetail?id=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJDRkUwUUJNNktDMzQyUjAwIiwicHJmIjoiUFVCTElDIiwiaXNzIjoiYmV0c2xpcC1zZXJ2aWNlIiwiaWF0IjoxNzcyODc2NTk0fQ.QGiBJRINDsSVKQn3WKRa7XDql5wiLDOG8R7QKc2bD-0&source=SB&deeplink=ftncz%3A%2F%2Fbetslip-history%2Fdetail%3Fid%3DeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJDRkUwUUJNNktDMzQyUjAwIiwicHJmIjoiUFVCTElDIiwiaXNzIjoiYmV0c2xpcC1zZXJ2aWNlIiwiaWF0IjoxNzcyODc2NTk0fQ.QGiBJRINDsSVKQn3WKRa7XDql5wiLDOG8R7QKc2bD-0%26source%3DSB", + datetime.now())]) if __name__ == "__main__": main() diff --git a/src/beaky/config.py b/src/beaky/config.py index 1470ba4..45dbe12 100644 --- a/src/beaky/config.py +++ b/src/beaky/config.py @@ -1,6 +1,9 @@ from pydantic.dataclasses import dataclass +from beaky.screenshotter.config import ScreenshotterConfig + @dataclass class Config: path: str + screenshotter: ScreenshotterConfig \ No newline at end of file diff --git a/src/beaky/scanner/scanner.py b/src/beaky/scanner/scanner.py index c44361a..a55de15 100644 --- a/src/beaky/scanner/scanner.py +++ b/src/beaky/scanner/scanner.py @@ -77,8 +77,9 @@ class Links: if id_idx is None or url_idx is None: # Required columns missing return [] - + print(rows) for row in rows: + print(row) try: raw_id = row[id_idx] if id_idx < len(row) else None raw_url = row[url_idx] if url_idx < len(row) else None diff --git a/src/beaky/screenshotter/__init__.py b/src/beaky/screenshotter/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/beaky/screenshotter/config.py b/src/beaky/screenshotter/config.py new file mode 100644 index 0000000..851852b --- /dev/null +++ b/src/beaky/screenshotter/config.py @@ -0,0 +1,5 @@ +from pydantic.dataclasses import dataclass + +@dataclass +class ScreenshotterConfig: + target_path: str \ No newline at end of file diff --git a/src/beaky/screenshotter/screenshotter.py b/src/beaky/screenshotter/screenshotter.py new file mode 100644 index 0000000..92912cf --- /dev/null +++ b/src/beaky/screenshotter/screenshotter.py @@ -0,0 +1,26 @@ +from pathlib import Path + +from beaky.config import Config +from playwright.sync_api import sync_playwright +from beaky.scanner.scanner import Link + +class Screenshotter: + def __init__(self, config: Config): + self.config = config + + + def capture_tickets(self, links: list[Link]): + for link in links: + print("capturing link:", link) + target_path = Path(self.config.screenshotter.target_path) / f"{link.id}.png" + self.capture_ticket(link.url, target_path) + + def capture_ticket(self, url, target_path, ticket_selector=".betslip-history-detail"): + with sync_playwright() as p: + browser = p.chromium.launch(headless=True) + page = browser.new_page() + page.goto(url, wait_until="domcontentloaded") + page.wait_for_selector(ticket_selector) + page.wait_for_load_state("networkidle") + page.locator(ticket_selector).screenshot(path=target_path) + browser.close()