From 9b1cae051a822d88fa29ab0901346643c3eca876 Mon Sep 17 00:00:00 2001 From: Benedikt Ziemons Date: Sun, 28 Jan 2024 19:05:42 +0100 Subject: [PATCH] Add first revision of database interaction for recipe and information storage. --- Pipfile | 1 + Pipfile.lock | 122 ++++++- .../calculator/SatisfactoryCalculator.py | 305 ++++++++++++------ 3 files changed, 337 insertions(+), 91 deletions(-) diff --git a/Pipfile b/Pipfile index 4381c84..157e43a 100644 --- a/Pipfile +++ b/Pipfile @@ -6,6 +6,7 @@ name = "pypi" [packages] selenium = "*" click = "*" +sqlalchemy = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index 455fbf9..f84fc00 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "763880094219b49a3e429352d48f700c9965f22616711a5c42aa97d137dedadb" + "sha256": "45cb685b915b5e5bab1ba5339a033373d210e09d6f0b4d9ac9acbe8fe15b5402" }, "pipfile-spec": 6, "requires": { @@ -41,6 +41,70 @@ "markers": "python_version >= '3.7'", "version": "==8.1.7" }, + "greenlet": { + "hashes": [ + "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67", + "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6", + "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257", + "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4", + "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676", + "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61", + "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc", + "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca", + "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7", + "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728", + "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305", + "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6", + "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379", + "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414", + "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04", + "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a", + "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf", + "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491", + "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559", + "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e", + "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274", + "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb", + "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b", + "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9", + "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b", + "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be", + "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506", + "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405", + "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113", + "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f", + "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5", + "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230", + "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d", + "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f", + "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a", + "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e", + "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61", + "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6", + "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d", + "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71", + "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22", + "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2", + "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3", + "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067", + "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc", + "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881", + "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3", + "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e", + "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac", + "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53", + "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0", + "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b", + "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83", + "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41", + "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c", + "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf", + "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da", + "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33" + ], + "markers": "platform_machine == 'aarch64' or (platform_machine == 'ppc64le' or (platform_machine == 'x86_64' or (platform_machine == 'amd64' or (platform_machine == 'AMD64' or (platform_machine == 'win32' or platform_machine == 'WIN32')))))", + "version": "==3.0.3" + }, "h11": { "hashes": [ "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", @@ -97,6 +161,62 @@ ], "version": "==2.4.0" }, + "sqlalchemy": { + "hashes": [ + "sha256:0d3cab3076af2e4aa5693f89622bef7fa770c6fec967143e4da7508b3dceb9b9", + "sha256:0dacf67aee53b16f365c589ce72e766efaabd2b145f9de7c917777b575e3659d", + "sha256:10331f129982a19df4284ceac6fe87353ca3ca6b4ca77ff7d697209ae0a5915e", + "sha256:14a6f68e8fc96e5e8f5647ef6cda6250c780612a573d99e4d881581432ef1669", + "sha256:1b1180cda6df7af84fe72e4530f192231b1f29a7496951db4ff38dac1687202d", + "sha256:29049e2c299b5ace92cbed0c1610a7a236f3baf4c6b66eb9547c01179f638ec5", + "sha256:342d365988ba88ada8af320d43df4e0b13a694dbd75951f537b2d5e4cb5cd002", + "sha256:420362338681eec03f53467804541a854617faed7272fe71a1bfdb07336a381e", + "sha256:4344d059265cc8b1b1be351bfb88749294b87a8b2bbe21dfbe066c4199541ebd", + "sha256:4f7a7d7fcc675d3d85fbf3b3828ecd5990b8d61bd6de3f1b260080b3beccf215", + "sha256:555651adbb503ac7f4cb35834c5e4ae0819aab2cd24857a123370764dc7d7e24", + "sha256:59a21853f5daeb50412d459cfb13cb82c089ad4c04ec208cd14dddd99fc23b39", + "sha256:5fdd402169aa00df3142149940b3bf9ce7dde075928c1886d9a1df63d4b8de62", + "sha256:605b6b059f4b57b277f75ace81cc5bc6335efcbcc4ccb9066695e515dbdb3900", + "sha256:665f0a3954635b5b777a55111ababf44b4fc12b1f3ba0a435b602b6387ffd7cf", + "sha256:6f9e2e59cbcc6ba1488404aad43de005d05ca56e069477b33ff74e91b6319735", + "sha256:736ea78cd06de6c21ecba7416499e7236a22374561493b456a1f7ffbe3f6cdb4", + "sha256:74b080c897563f81062b74e44f5a72fa44c2b373741a9ade701d5f789a10ba23", + "sha256:75432b5b14dc2fff43c50435e248b45c7cdadef73388e5610852b95280ffd0e9", + "sha256:75f99202324383d613ddd1f7455ac908dca9c2dd729ec8584c9541dd41822a2c", + "sha256:790f533fa5c8901a62b6fef5811d48980adeb2f51f1290ade8b5e7ba990ba3de", + "sha256:798f717ae7c806d67145f6ae94dc7c342d3222d3b9a311a784f371a4333212c7", + "sha256:7c88f0c7dcc5f99bdb34b4fd9b69b93c89f893f454f40219fe923a3a2fd11625", + "sha256:7d505815ac340568fd03f719446a589162d55c52f08abd77ba8964fbb7eb5b5f", + "sha256:84daa0a2055df9ca0f148a64fdde12ac635e30edbca80e87df9b3aaf419e144a", + "sha256:87d91043ea0dc65ee583026cb18e1b458d8ec5fc0a93637126b5fc0bc3ea68c4", + "sha256:87f6e732bccd7dcf1741c00f1ecf33797383128bd1c90144ac8adc02cbb98643", + "sha256:884272dcd3ad97f47702965a0e902b540541890f468d24bd1d98bcfe41c3f018", + "sha256:8b8cb63d3ea63b29074dcd29da4dc6a97ad1349151f2d2949495418fd6e48db9", + "sha256:91f7d9d1c4dd1f4f6e092874c128c11165eafcf7c963128f79e28f8445de82d5", + "sha256:a2c69a7664fb2d54b8682dd774c3b54f67f84fa123cf84dda2a5f40dcaa04e08", + "sha256:a3be4987e3ee9d9a380b66393b77a4cd6d742480c951a1c56a23c335caca4ce3", + "sha256:a86b4240e67d4753dc3092d9511886795b3c2852abe599cffe108952f7af7ac3", + "sha256:aa9373708763ef46782d10e950b49d0235bfe58facebd76917d3f5cbf5971aed", + "sha256:b64b183d610b424a160b0d4d880995e935208fc043d0302dd29fee32d1ee3f95", + "sha256:b801154027107461ee992ff4b5c09aa7cc6ec91ddfe50d02bca344918c3265c6", + "sha256:bb209a73b8307f8fe4fe46f6ad5979649be01607f11af1eb94aa9e8a3aaf77f0", + "sha256:bc8b7dabe8e67c4832891a5d322cec6d44ef02f432b4588390017f5cec186a84", + "sha256:c51db269513917394faec5e5c00d6f83829742ba62e2ac4fa5c98d58be91662f", + "sha256:c55731c116806836a5d678a70c84cb13f2cedba920212ba7dcad53260997666d", + "sha256:cf18ff7fc9941b8fc23437cc3e68ed4ebeff3599eec6ef5eebf305f3d2e9a7c2", + "sha256:d24f571990c05f6b36a396218f251f3e0dda916e0c687ef6fdca5072743208f5", + "sha256:db854730a25db7c956423bb9fb4bdd1216c839a689bf9cc15fada0a7fb2f4570", + "sha256:dc55990143cbd853a5d038c05e79284baedf3e299661389654551bd02a6a68d7", + "sha256:e607cdd99cbf9bb80391f54446b86e16eea6ad309361942bf88318bcd452363c", + "sha256:ecf6d4cda1f9f6cb0b45803a01ea7f034e2f1aed9475e883410812d9f9e3cfcf", + "sha256:f2a159111a0f58fb034c93eeba211b4141137ec4b0a6e75789ab7a3ef3c7e7e3", + "sha256:f37c0caf14b9e9b9e8f6dbc81bc56db06acb4363eba5a633167781a48ef036ed", + "sha256:f5693145220517b5f42393e07a6898acdfe820e136c98663b971906120549da5" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==2.0.25" + }, "trio": { "hashes": [ "sha256:c3bd3a4e3e3025cd9a2241eae75637c43fe0b9e88b4c97b9161a55b9e54cd72c", diff --git a/factorygame/calculator/SatisfactoryCalculator.py b/factorygame/calculator/SatisfactoryCalculator.py index 1f77c18..f32b509 100644 --- a/factorygame/calculator/SatisfactoryCalculator.py +++ b/factorygame/calculator/SatisfactoryCalculator.py @@ -1,21 +1,211 @@ #!/usr/bin/env python3 -import time -from collections import namedtuple + +import datetime +from typing import Optional +from urllib.parse import urljoin import click +import sqlalchemy from selenium.webdriver import Firefox from selenium.webdriver.common.by import By from selenium.webdriver.firefox.options import Options +from selenium.webdriver.remote.webdriver import WebDriver +from sqlalchemy import String, create_engine, select, ForeignKey, Select, Table, Column +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, Session -Recipe = namedtuple("Recipe", ["result_count", "ingredients", "time"]) -Ingredient = namedtuple("Ingredient", ["count", "name"]) + +class Base(DeclarativeBase): + pass + + +class Resource(Base): + __tablename__ = "resources" + + id: Mapped[int] = mapped_column(primary_key=True) + label: Mapped[str] = mapped_column(String(127)) + wiki_url: Mapped[str] + recipes_populated_at: Mapped[Optional[datetime.datetime]] + flows: Mapped[list["ResourceFlow"]] = relationship(back_populates="resource") + + @classmethod + def by_label(cls, search: str) -> Select[tuple["Resource"]]: + return select(cls).where(cls.label.ilike(search)) + + +class Factory(Base): + __tablename__ = "factories" + + id: Mapped[int] = mapped_column(primary_key=True) + label: Mapped[str] = mapped_column(String(127)) + wiki_url: Mapped[str] + + @classmethod + def by_label(cls, search: str) -> Select[tuple["Factory"]]: + return select(cls).where(cls.label.ilike(search)) + + +ingredients_table = Table( + "recipe_ingredients", + Base.metadata, + Column("recipe_id", ForeignKey("recipes.id"), primary_key=True), + Column("resource_flow_id", ForeignKey("resource_flows.id"), primary_key=True), +) + + +results_table = Table( + "recipe_results", + Base.metadata, + Column("recipe_id", ForeignKey("recipes.id"), primary_key=True), + Column("resource_flow_id", ForeignKey("resource_flows.id"), primary_key=True), +) + + +class ResourceFlow(Base): + __tablename__ = "resource_flows" + + id: Mapped[int] = mapped_column(primary_key=True) + ingredient_in: Mapped[Optional["Recipe"]] = relationship(secondary=ingredients_table, back_populates="ingredients") + result_of: Mapped[Optional["Recipe"]] = relationship(secondary=results_table, back_populates="results") + resource_id: Mapped[int] = mapped_column(ForeignKey("resources.id")) + resource: Mapped["Resource"] = relationship(back_populates="flows") + amount: Mapped[str] + time: Mapped[str] + + +class Recipe(Base): + __tablename__ = "recipes" + + id: Mapped[int] = mapped_column(primary_key=True) + factory_id: Mapped[int] = mapped_column(ForeignKey("factories.id")) + factory: Mapped["Factory"] = relationship() + ingredients: Mapped[list["ResourceFlow"]] = relationship( + secondary=ingredients_table, back_populates="ingredient_in" + ) + results: Mapped[list["ResourceFlow"]] = relationship(secondary=results_table, back_populates="result_of") + + +def normalize_url(browser: WebDriver, href: str) -> str: + return urljoin(base=browser.current_url, url=href) + + +def populate_recipes(browser: WebDriver, engine: sqlalchemy.Engine, input_resource_label: str): + browser.find_element(By.CSS_SELECTOR, "button#\\3Ar1\\3A-tab-0").click() + + recipes_html_elems = browser.find_elements(By.CSS_SELECTOR, "#\\3Ar1\\3A-tabpanel-0 > div > div") + for recipe_idx in range(len(recipes_html_elems)): + recipe_html_elem = recipes_html_elems[recipe_idx] + factory_html_elem = recipe_html_elem.find_element(By.CSS_SELECTOR, ".flex-col > span > a") + factory_label = factory_html_elem.text + factory_url = urljoin(base=browser.current_url, url=factory_html_elem.get_attribute("href")) + print("recipe", recipe_idx, "produced in:", factory_label, factory_url) + + def extract_resource_flow(html_elem): + resource_img = html_elem.find_element(By.TAG_NAME, "img") + resource_label = resource_img.get_attribute("alt") + wiki_url = normalize_url( + browser=browser, + href=html_elem.find_element(By.TAG_NAME, "a").get_attribute("href"), + ) + kwargs = {} + if resource_label == input_resource_label: + kwargs['recipes_populated_at'] = datetime.datetime.utcnow() + resource = Resource(label=resource_label, wiki_url=wiki_url, **kwargs) + amount = html_elem.find_element(By.CSS_SELECTOR, ".text-xs:nth-child(2)").text + time = html_elem.find_element(By.CSS_SELECTOR, ".text-xs:nth-child(3)").text + return ResourceFlow(resource=resource, amount=amount, time=time) + + ingredient_html_elems = recipe_html_elem.find_elements( + By.CSS_SELECTOR, f".flex-row > div:nth-child(1) > div:has(> a)" + ) + ingredients: list[ResourceFlow] = [] + for ingredient_idx in range(len(ingredient_html_elems)): + resource_flow = extract_resource_flow(ingredient_html_elems[ingredient_idx]) + ingredients.append(resource_flow) + print( + "recipe", + recipe_idx, + "ingredient", + ingredient_idx, + "name:", + resource_flow.resource.label, + ) + print( + "recipe", + recipe_idx, + "ingredient", + ingredient_idx, + "count:", + resource_flow.amount, + ) + print( + "recipe", + recipe_idx, + "ingredient", + ingredient_idx, + "time:", + resource_flow.time, + ) + result_html_elems = recipe_html_elem.find_elements( + By.CSS_SELECTOR, f".flex-row > div:nth-child(3) > div:has(> a)" + ) + results: list[ResourceFlow] = [] + for result_idx in range(len(result_html_elems)): + resource_flow = extract_resource_flow(result_html_elems[result_idx]) + results.append(resource_flow) + print( + "recipe", + recipe_idx, + "result", + result_idx, + "name:", + resource_flow.resource.label, + ) + print( + "recipe", + recipe_idx, + "result", + result_idx, + "count:", + resource_flow.amount, + ) + print( + "recipe", + recipe_idx, + "result", + result_idx, + "time:", + resource_flow.time, + ) + + with Session(engine, autoflush=False) as session: + factory = session.scalars(Factory.by_label(factory_label)).one_or_none() + if not factory: + factory = Factory(label=factory_label, wiki_url=factory_url) + session.add(factory) + for flow in ingredients + results: + res = session.scalars(Resource.by_label(flow.resource.label)).one_or_none() + if res: + flow.resource = res + else: + session.add(flow.resource) + session.add(flow) + recipe = Recipe(factory=factory, ingredients=ingredients, results=results) + session.add(recipe) + session.commit() @click.command() -@click.option("--result", type=str, required=True) -@click.option("--debug", is_flag=True, default=False, required=False) -def main(result: str, debug: bool): - if result: +@click.option("--result", is_flag=True) +@click.option("--debug", is_flag=True) +@click.argument("search") +def main(result: bool, debug: bool, search: str): + engine = create_engine("sqlite:///file.db", echo=debug) + Base.metadata.create_all(bind=engine) + if result and search: + with Session(engine) as session: + for obj in session.scalars(Resource.by_label(search)): + print(obj) + firefox_options = Options() if not debug: firefox_options.add_argument("--headless") @@ -23,107 +213,42 @@ def main(result: str, debug: bool): try: browser.get("https://wiki.kyrium.space/") browser.set_window_size(1600, 1015) - search_bar = browser.find_element( - By.CSS_SELECTOR, "nav input[placeholder='Search for an item...']" - ) + search_bar = browser.find_element(By.CSS_SELECTOR, "nav input[placeholder='Search for an item...']") search_bar.click() - search_bar.send_keys(result) + search_bar.send_keys(search) search_button = browser.find_element(By.CSS_SELECTOR, "nav button[type='submit']") search_button.click() - browser.implicitly_wait(3) - choices = browser.find_elements( - By.CSS_SELECTOR, "body > div > .container:nth-child(1) a.items-center" - ) + browser.implicitly_wait(5) + choices = browser.find_elements(By.CSS_SELECTOR, "body > div > .container:nth-child(1) a.items-center") if not choices: print("No wiki entries found for this result") return elif len(choices) > 1: default_choice = 1 + choice_names: list[str] = [] for choice_idx in range(1, len(choices) + 1): recipe_choice = choices[choice_idx - 1] name = recipe_choice.find_element(By.TAG_NAME, "img").get_attribute("alt") - if name.casefold() == result.casefold(): + choice_names.append(name) + if name.casefold() == search.casefold(): default_choice = choice_idx print(f"{choice_idx}: {name}") - user_choice = input(f"Chose a recipe to continue… (default: {default_choice}) ") + user_choice = click.prompt("Chose a recipe to continue…", default=default_choice) if not user_choice: user_choice = default_choice else: user_choice = int(user_choice) - choices[user_choice - 1].click() + + link_html_elem = choices[user_choice - 1] else: - choices[0].click() + link_html_elem = choices[0] - browser.find_element(By.CSS_SELECTOR, "button#\\3Ar1\\3A-tab-0").click() - - recipes = browser.find_elements(By.CSS_SELECTOR, "#\\3Ar1\\3A-tabpanel-0 > div > div") - for recipe_idx in range(len(recipes)): - recipe = recipes[recipe_idx] - print( - "recipe", - recipe_idx, - "produced in:", - recipe.find_element(By.CSS_SELECTOR, ".flex-col > span > a").text, - ) - - ingredients = recipe.find_elements( - By.CSS_SELECTOR, f".flex-row > div:nth-child(1) > div:has(> a)" - ) - for ingredient_idx in range(len(ingredients)): - ingredient = ingredients[ingredient_idx] - print( - "recipe", - recipe_idx, - "ingredient", - ingredient_idx, - "name:", - ingredient.find_element(By.TAG_NAME, "img").get_attribute("alt"), - ) - print( - "recipe", - recipe_idx, - "ingredient", - ingredient_idx, - "count:", - ingredient.find_element(By.CSS_SELECTOR, ".text-xs:nth-child(2)").text, - ) - print( - "recipe", - recipe_idx, - "ingredient", - ingredient_idx, - "time:", - ingredient.find_element(By.CSS_SELECTOR, ".text-xs:nth-child(3)").text, - ) - results = recipe.find_elements( - By.CSS_SELECTOR, f".flex-row > div:nth-child(3) > div:has(> a)" - ) - for result_idx in range(len(results)): - result = results[result_idx] - print( - "recipe", - recipe_idx, - "result", - result_idx, - "name:", - result.find_element(By.TAG_NAME, "img").get_attribute("alt"), - ) - print( - "recipe", - recipe_idx, - "result", - result_idx, - "count:", - result.find_element(By.CSS_SELECTOR, ".text-xs:nth-child(2)").text, - ) - print( - "recipe", - recipe_idx, - "result", - result_idx, - "time:", - result.find_element(By.CSS_SELECTOR, ".text-xs:nth-child(3)").text, - ) + resource_label = link_html_elem.find_element(By.TAG_NAME, "img").get_attribute("alt") + # FIXME: check if resource_label is in database + if debug: + print("resource_label:", resource_label) + link_html_elem.click() + populate_recipes(browser=browser, engine=engine, input_resource_label=resource_label) finally: if not debug: browser.quit()