coddingtonbear / python-myfitnesspal

Access your meal tracking data stored in MyFitnessPal programatically
MIT License
789 stars 138 forks source link

IndexError when searching food #135

Closed obsidian33 closed 1 year ago

obsidian33 commented 2 years ago

I was trying to search for a specific type of food and received this error:

>>> food_items = client.get_food_search_results("timber wolf keto seeds bread")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python310\lib\site-packages\myfitnesspal-1.16.6-py3.10.egg\myfitnesspal\client.py", line 726, in get_food_search_results
    return self._get_food_search_results(document)
  File "C:\Python310\lib\site-packages\myfitnesspal-1.16.6-py3.10.egg\myfitnesspal\client.py", line 743, in _get_food_search_results
    item_div.xpath(".//p[@class='search-nutritional-info']")[0]
IndexError: list index out of range
>>> food_items = client.get_food_search_results("timber wolf keto")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python310\lib\site-packages\myfitnesspal-1.16.6-py3.10.egg\myfitnesspal\client.py", line 726, in get_food_search_results
    return self._get_food_search_results(document)
  File "C:\Python310\lib\site-packages\myfitnesspal-1.16.6-py3.10.egg\myfitnesspal\client.py", line 743, in _get_food_search_results
    item_div.xpath(".//p[@class='search-nutritional-info']")[0]
IndexError: list index out of range

Searching using this string in the browser does seem to work: image

If I slowly add words to the search string I can find it with just "timber wolf" but as soon as I try "timber wolf keto" I get the exception (I shortened the results):

>>> food_items = client.get_food_search_results("timber wolf")
>>> food_items
[<keto seed bread -- timber wolf>, <Timber Wolf Keto Seeds Bread -- Bread Company>, <inked keto -- timber wolf keto seeds>, <Timber -- Timber>, <keto seeds inked keto -- ever timber wolf>]
>>> food_items = client.get_food_search_results("timber wolf keto")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python310\lib\site-packages\myfitnesspal-1.16.6-py3.10.egg\myfitnesspal\client.py", line 726, in get_food_search_results
    return self._get_food_search_results(document)
  File "C:\Python310\lib\site-packages\myfitnesspal-1.16.6-py3.10.egg\myfitnesspal\client.py", line 743, in _get_food_search_results
    item_div.xpath(".//p[@class='search-nutritional-info']")[0]
IndexError: list index out of range
obsidian33 commented 2 years ago

If anyone stumbles across this. I found that the item it was finding was one of my saved meals. If you have saved meals you'll get the above error as the HTML document doesn't have a paragraph element with the class='search-nutritional-info'.

I updated my local copy of the source code to skip items where the anchor element has an attribute of 'data-food-type'='1'. Once I've ironed out all my use cases I will perform a pull request on this repo.

Here is the updated code in client.py:

    def _get_food_search_results(self, document) -> List[FoodItem]:
        item_divs = document.xpath("//li[@class='matched-food']")

        items = []
        for item_div in item_divs:
            # get mfp info from search results
            a = item_div.xpath(".//div[@class='search-title-container']/a")[0]
            # if it is a meal, skip it
            if a.get("data-food-type") == '1': continue
hannahburkhardt commented 2 years ago

@obsidian33 is it the right thing to do to skip these entries? I think it would be nice to include them. These items don't seem to have a tag with class search-nutritional-info, so we could just leave nutrition info blank for these items (that seems to be what the website does too).