Finding Products on a Product Page
Products on a product page can be searched for using the find_product and
find_products methods of the ProductPage class. These methods allow
you to filter products based on their attributes, properties, and custom
constraints.
The two methods differ in the number of products they return. find_product
returns the first product that matches the specified criteria, or None if
no product is found. find_products returns a list of all products that match
the specified criteria.
Assuming we have a ProductPage instance named page, let’s explore how
to search for products using the find_product and find_products methods.
Searching Using Attributes and Properties
Searching for a product with its attributes and properties is straightforward. You can specify the attributes and properties you want to search for as keyword arguments in the method call.
For example, to search for a product by its name, specify the name argument
in a find_product method call:
cola = page.find_product(name='Harboe Cola')
if cola is None:
print('Harboe Cola not found.')
else:
print(f'Harboe Cola quantity is {cola.quantity}.')
This code snippet searches for a product named “Harboe Cola” and prints its quantity if the product is found.
Or if, for example, you want to find all desserts that are currently available,
you can specify the category and the is_available arguments
simultaneously in a single call to the find_products method:
desserts = page.find_products(category='Dezerty, snídaně', is_available=True)
print(f'{len(desserts)} desserts are currently available.')
This code snippet searches for all products in the “Dezerty, snídaně” category with quantity greater than zero and prints the number of products found.
Warning
Matching Product attributes and properties requires an exact match.
This means that the search is case-sensitive and diacritics-sensitive.
For example, searching for name='harboe cola' or name='Cola'
will not match a product named “Harboe Cola”.
Complete Example
import asyncio
from freshpointsync import ProductPage
async def main():
async with ProductPage(location_id=296) as page:
await page.update(silent=True)
cola = page.find_product(name='Harboe Cola')
if cola is None:
print('Harboe Cola not found.')
else:
print(f'Harboe Cola quantity is {cola.quantity}.')
desserts = page.find_products(
category='Dezerty, snídaně', is_available=True
)
print(f'{len(desserts)} desserts are currently available.')
if __name__ == '__main__':
asyncio.run(main())
Searching using Custom Constraints
In case your search query is more complex, you can pass a callable object to
the constraint parameter of any of the search methods. The callable
object should accept a single argument, which is a Product instance, and
return a boolean value indicating whether the product matches the criteria.
products = page.find_products(
constraint=lambda product: (
'sendvice' in product.category_lowercase_ascii and
product.is_available and
product.price_curr < 100
)
)
if products:
print('Sendvices available for less than 100 CZK:')
for product in products:
print(f'- {product.name} ({product.price_curr} CZK)')
else:
print('No sendvices available for less than 100 CZK.')
In the example above, a lambda function is used to search for all products,
the category of which contains the word “sendvice” that are available and cost
less than 100 CZK. The matching is case-insensitive and ignores diacritics.
Tip
While using lambda functions is a common approach, you can also define
a regular function and pass it to the constraint parameter. The only
requirement is that the function should accept a single argument and return
a boolean value.
Complete Example
import asyncio
from freshpointsync import ProductPage
async def main():
async with ProductPage(location_id=296) as page:
await page.update(silent=True)
products = page.find_products(
constraint=lambda product: (
'sendvice' in product.category_lowercase_ascii and
product.is_available and
product.price_curr < 100
)
)
if products:
print('Sendvices available for less than 100 CZK:')
for product in products:
print(f'- {product.name} ({product.price_curr} CZK)')
else:
print('No sendvices are available for less than 100 CZK.')
if __name__ == '__main__':
asyncio.run(main())
Case Study: Creating a Simple REPL Application
Let’s create a simple REPL application that finds a product by its name and prints its availability.
import asyncio
import time
from freshpointsync import ProductPage
LOCATION_ID = 296
def print_product_info(page: ProductPage, product_name: str) -> None:
product = page.find_product(
constraint=lambda p: product_name.casefold() in p.name_lowercase_ascii
) # case-insensitive search for a partial match
if product:
print(f'Product "{product.name}" quantity: {product.quantity} pcs.')
else:
print(f'Product "{product_name}" not found on the page.')
def get_user_input() -> str:
return input('Enter product name (or "exit" to quit): ')
async def prompt_forever(page: ProductPage, max_update_interval: float) -> None:
await page.update(silent=True)
timer = time.time()
while True:
product_name = get_user_input()
if product_name == 'exit':
break
if time.time() - timer > max_update_interval:
await page.update(silent=True)
timer = time.time()
print_product_info(page, product_name)
async def main() -> None:
page = ProductPage(location_id=LOCATION_ID)
try:
await page.start_session()
except Exception as e:
print(f'An error occurred while starting the session: {e}')
return
try:
await prompt_forever(page, max_update_interval=10.0)
except EOFError:
print() # print '\n' to handle Ctrl+C with no input (EOF)
except Exception as e:
print(f'An unexpected error occurred: {e}')
finally:
print('Exiting...')
await page.close_session()
if __name__ == '__main__':
try:
asyncio.run(main())
except KeyboardInterrupt:
pass
In the example above, a ProductPage instance is created in the main
function. The session is started and the initial data is fetched. The script
then enters an infinite loop under a try-finally block. The loop prompts
the user for a product name and prints the product quantity. The session is
closed when the user exits the loop.