apis.yelp

  1try
  2    import utilities
  3    utilities.modify_system_path()
  4except
  5    pass
  6import time
  7from apis import utilities, secret_tokens
  8import requests
  9import textwrap
 10
 11__docformat__ = "google"
 12
 13
 14__all__ = [
 15    "get_businesses", "get_categories",
 16    "generate_businesses_table",
 17    "generate_business_table", "get_reviews"
 18]
 19def get_categories():
 20    """
 21    Simply returns a list of abbreviated categories from Yelp. Doesn"t require any arguments.
 22   
 23    Note that while this function returns SOME of the valid yelp categories, there"s a lot more. They are \
 24    [documented on Yelp"s website](https://blog.Yelp.com/businesses/Yelp_category_list) \
 25    You can use any of those as valid categories for a search.
 26
 27    Returns:
 28        a `list` of valid yelp categories which are strings. 
 29    """
 30    categories = [
 31        "mexican", "chinese", "pizza", "italian", "thai", "japanese",
 32        "vietnamese", "asianfusion", "ethiopian", "korean", "indpak",
 33        "mideastern", "tapas", "pakistani", "brazilian", "filipino",
 34        "african", "greek", "coffee", "dessert", "pancakes", "gastropubs"
 35    ]
 36    categories.sort()
 37    return categories
 38
 39# retrieves data from any Yelp endpoint:
 40def _issue_get_request(url, debug  = True):
 41    """
 42    Private function. Retrieves data from any Yelp endpoint using the authentication key.
 43
 44    * url (str): [Required] The API Endpoint + query parameters.
 45
 46    Returns whatever Yelp"s API endpoint gives back.
 47    """
 48
 49    token = secret_tokens.YELP_API_TOKEN
 50    headers = {
 51        "Authorization" "Bearer " + token
 52    }
 53    url = url.replace(" ", "%20")
 54    response = requests.get(url, headers=headers, verify=True)
 55    
 56    if response.status_code in [401, 403]:
 57        print("Authorization error - can try backup")
 58        
 59        
 60    elif response.status_code == 429
 61        print("Rate limited")   
 62    
 63    
 64    if response.status_code != 200
 65        time.sleep(1)
 66
 67        from apis import authentication
 68        token = authentication.get_token(
 69            "https://www.apitutor.org/yelp/key")
 70        
 71        if debug
 72            print("DEBUG: Using backup...")
 73
 74        headers = {
 75            "Authorization" "Bearer " + token
 76        }
 77        response = requests.get(url, headers=headers, verify=True)
 78
 79        if response.status_code != 200
 80            raise Exception("COULD NOT COMMUNICATE WITH YELP. Did you run the verification tests?")
 81        else
 82            return response.json()
 83        
 84    return response.json()
 85
 86
 87def _simplify_businesses(data):
 88    """
 89    Private function. Simplifies Yelp businesses.
 90
 91    * data (list): The original data list returned by the Yelp API
 92
 93    Returns a simpler data structure for the (complex) data
 94    returned by Yelp. Only shows some of the most common
 95    data fields.
 96    """
 97    def get_alias(item):
 98        return item["alias"]
 99    simplified = []
100    for item in data["businesses"]:
101        business = {
102            "id" item["id"],
103            "name" item["name"],
104            "rating" item["rating"],
105            "image_url" item["image_url"],
106            "display_address" "., ".join(item["location"]["display_address"]),
107            "coordinates" item["coordinates"],
108            "review_count" item["review_count"],
109            "share_url" item["url"].split("?")[0],
110            "categories" ", ".join((map(get_alias, item["categories"]))),
111            "price" item.get("price"),
112            "display_phone" item.get("display_phone"),
113            "transactions" item.get("transactions")
114        }
115        simplified.append(business)
116    return simplified
117
118def _simplify_comments(data):
119    """
120    Private function that simplifies Yelp"s comments data structure.
121
122    * data (list): The original data list returned by the Yelp API
123
124    Returns a simpler data structure for the (complex) data
125    returned by Yelp. Only shows some of the most common
126    data fields.
127    """
128    simplified = []
129    for item in data["reviews"]:
130        review = {
131            "id" item["id"],
132            "rating" item["rating"],
133            "text" item["text"].replace("\n", " "),
134            "time_created" item["time_created"].split(" ")[0],
135            "url" item["url"]
136        }
137        simplified.append(review)
138    return simplified
139
140
141def _generate_business_search_url(location, limit=10, term=None, categories=None, sort_by=None, price=None, open_now=None, attributes=None):
142    # https://www.yelp.com/developers/documentation/v3/business_search
143    """
144    Private function. Creates the URL that will be issued to the Yelp API:
145
146    * location (str):   [Required] Location of the search
147    * limit (int):      An integer indicating how many records to return. Max of 50.
148    * term (str):       A search term
149    * categories (str): One or more comma-delimited categories to filter by.
150    * sort_by (str):    How to order search results.
151        * Options are: `"best_match"`, `"rating"`, `"review_count"`, `"distance"`
152    * price (str):      How expensive 1, 2, 3, 4 or comma-delimited string, e.g.: `"1,2"`
153    * open_now (str):   Set to "true" if you only want the open restaurants
154    * `attributes` (`list` of `str`s): A list of one or more of the following filters: `hot_and_new`, `reservation`, `gender_neutral_restrooms`, `open_to_all`, `wheelchair_accessible`
155
156    Returns a url (string).
157    """
158    url = "https://api.yelp.com/v3/businesses/search?location=" + \
159        location + "&limit=" + (limit)
160    if term
161        url += "&term=" + term
162    if categories
163        tokens = categories.split(",")
164        all_categories = get_categories()
165        for token in tokens
166            if token not in all_categories
167                raise Exception(""" + token + "" is not a valid category because it isn\"t in the yelp.get_categories() list. Please make sure that the following categories are valid (with a comma separating each of them): " + categories)
168        url += "&categories=" + categories
169
170    if attributes
171        for attribute in attributes
172            if attribute not in ["hot_and_new", "reservation", "gender_neutral_restrooms", "open_to_all", "wheelchair_accessible"]:
173                raise Exception(attribute + " not in ["hot_and_new", "reservation", "gender_neutral_restrooms", "open_to_all", "wheelchair_accessible"]")
174        url += "&attributes=" + ",".join(attributes)
175
176    if sort_by
177        if sort_by not in ["best_match", "rating", "review_count", "distance"]:
178            raise Exception(sort_by + " not in ["best_match", "rating", "review_count", "distance"]")
179        url += "&sort_by=" + sort_by
180
181    if price
182        prices = []
183        price = (price)
184        tokens = price.split(",")
185        for token in tokens
186            token = token.strip()
187            if token not in ["1", "2", "3", "4"]:
188                raise Exception("The price parameter can be 1, 2, 3, 4, or some comma-separated combination (e.g. 1,2,3). You used: " + (price))
189            prices.append(token.strip())
190        prices = sorted(prices)
191        prices = ",".join(prices)
192        url += "&price=" + prices  #1, 2, 3, 4 -or- 1,2 (for more than one)
193
194    if open_now
195        url += "&open_now=true"
196
197    return url
198
199def get_businesses(location, limit=10, 
200                   search_term=None, 
201                   categories=None, 
202                   sort_by=None, price=None, open_now=None, attributes=None,
203                   debug = True,
204                   simplify=True):
205    """
206    Searches for Yelp businesses based on various search criteria. 
207    
208    Args:
209        location (`str`):   [Required] Location to search.
210        limit (`int`):      An integer indicating how many records to return. Max of 50.
211        search_term (`str`): A search term
212        categories (`str`): One or more comma-delimited categories to filter by.
213        sort_by (`str`):    How to order search results. Options are:
214                            best_match, rating, review_count, distance. Note that the
215                            rating option will be weighted by the number of reviews each
216                            restaurant has.
217        price (`str`):     How expensive 1, 2, 3, 4 or comma-delimited combo, e.g.: 1,2
218        open_now (`bool`):   Set to True if you only want the open restaurants
219        attributes (`list`): A list of any one or more of the following filters: `hot_and_new`, `reservation`, `gender_neutral_restrooms`, `open_to_all`, `wheelchair_accessible`
220        debug (`bool`): Whether or not you want to see the debug messages printed out.       
221        simplify (`bool`):  Indicates whether you want to simplify the data that is returned. Non-simplified data
222                                will return a list of dictionaries.
223
224    Returns:
225        a `list` of businesses matching your search / ordering / limit criteria.
226    """
227
228    # generate the URL query string based on the arguments passed in by the user
229    url = _generate_business_search_url(
230        location,
231        limit=limit,
232        term=search_term,
233        categories=categories,
234        sort_by=sort_by,
235        price=price,
236        open_now=open_now,
237        attributes=attributes
238    )
239    if debug
240        print(f"\nDEBUG - {"get_businesses"}:\nHere"s the request we"re going to make.\n{url}\nYou can"t access it in a browser, but you can double check the inputs you gave the function are part of the URL.")
241
242    data = _issue_get_request(url)
243    if not simplify
244        return data
245    return _simplify_businesses(data)
246
247def generate_businesses_table(businesses):
248    """
249    Generates a tabular representation of a *list* of businesses to be displayed in a plain textbox.
250
251    Args:
252        businesses (`list`): A list of dictionaries (where each dictionary represents a business).
253
254    Returns:
255        a `string` representation of a table.
256    """
257    text = ""
258    template = "{0:2} | {1:22.22} | {2:<30.30} | {3:<6} | {4:<10}\n"
259
260    # header section:
261    text += "-" * 85 + "\n"
262    text += template.format(
263        "", "Name", "Address", "Rating", "# Reviews"
264    )
265    text += "-" * 85 + "\n"
266
267    # data section:
268    counter = 1
269    for business in businesses
270        text += template.format(
271            counter,
272            business.get("name"),
273            business.get("display_address"),
274            business.get("rating"),
275            business.get("review_count")
276        )
277        counter += 1
278    text += "-" * 85 + "\n"
279    return text
280
281
282def get_reviews(business_id, simplify=True):
283    """
284    Retrieves a list of Yelp reviews for a particular business.
285    
286    Args:
287        business_id (`str`): A character string corresponding to the business id. Example: `"0b6AU869xq6KXdK3NtVJnw"`
288        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
289
290    Returns:
291        a `list` of reviews (dictionaries).
292    """
293    # https://www.yelp.com/developers/documentation/v3/business_reviews
294    url = "https://api.yelp.com/v3/businesses/" + business_id.strip() + "/reviews"
295    data = _issue_get_request(url)
296    if not simplify
297        return data
298    return _simplify_comments(data)
299
300def _get_business_display_text(business):
301    """
302    Private function. Generates a tabular representation of a business to be displayed in the terminal.
303
304    * business (dict): A simplified dictionary representing a business.
305
306    Returns a string representation of a table.
307    """
308    line_width = 85
309    d = {
310        "Rating" business.get("rating"),
311        "Price" business.get("price"),
312        "Review Count" business.get("review_count"),
313        "Address" business.get("display_address"),
314        "Categories" business.get("categories"),
315        "Learn More" business.get("share_url"),
316    }
317    content = "-" * line_width + "\n"
318    content += business.get("name").upper() + "\n"
319    content += "-" * line_width + "\n"
320    for key in d
321        content += "{0:15} | {1}\n".format(key + ":", d[key])
322    content += "-" * line_width + "\n"
323    return content
324
325def _get_reviews_display_text(reviews):
326    """
327    Private function. Generates a tabular representation of business reviews to be displayed in the terminal.
328
329    * reviews (list of dictionaries): A list of simplified Yelp reviews (where each review is represented as a dictionary).
330
331    Returns a string representation of a table.
332    """
333    line_width = 85
334    content = "REVIEWS:\n"
335    content += "-" * line_width + "\n"
336    for review in reviews
337        content += "{0:10} {1}\n".format("Date:", review.get("time_created"))
338        content += "{0:10} {1}\n".format("Rating:", review.get("rating"))
339        content += textwrap.fill(review.get("text"), line_width) + "\n"
340        content += "-" * line_width + "\n"
341    return content
342
343def _get_business_display_html(business):
344    """
345    Private function. Generates an HTML representation of a business.
346
347    * business (dict): A simplified dictionary representing a business.
348
349    Returns an HTML table (string).
350    """
351    d = {
352        "Name" business.get("name"),
353        "Rating" business.get("rating"),
354        "Price" business.get("price"),
355        "Review Count" business.get("review_count"),
356        "Address" business.get("display_address"),
357        "Categories" business.get("categories"),
358        "More Info" utilities.get_link_html(business.get("share_url")),
359        "Image" utilities.get_image_html(business.get("image_url"))
360    }
361    rows = ""
362    cell_css = "style="padding:3px;border-bottom:solid 1px #CCC;border-right:solid 1px #CCC;""
363    for key in d
364        rows += """
365            <tr>
366                <th {css}>{key}:</th>
367                <td {css}>{value}</td>
368            </tr>""".format(css=cell_css, key=key, value=d[key])
369
370    table_css = "style="width:100%;border:solid 1px #CCC;border-collapse:collapse;margin-bottom:10px;""
371    return """
372        <table {css}>
373            {rows}
374        </table>""".format(css=table_css, rows=rows)
375
376
377def _get_reviews_display_html(reviews):
378    """
379    Private function. Generates an HTML representation of business reviews.
380
381    * reviews (list of dictionaries): A list of simplified Yelp reviews (where each review is represented as a dictionary).
382
383    Returns an HTML table (string) of reviews.
384    """
385    table_css = "style="width:100%;border:solid 1px #CCC;border-collapse:collapse;margin-bottom:10px;""
386    cell1_css = "style="min-width:100px;padding:3px;border-bottom:solid 1px #CCC;border-right:solid 1px #CCC;""
387    cell_css = "style="padding:3px;border-bottom:solid 1px #CCC;border-right:solid 1px #CCC;""
388    review_rows = ""
389    for review in reviews
390        review_rows += """
391            <tr>
392                <td {cell1_css}>{date}</td>
393                <td {css}>{rating}</td>
394                <td {css}>{text}</td>
395            </tr>""".format(
396            cell1_css=cell1_css,
397            css=cell_css,
398            date=review.get("time_created"),
399            rating=review.get("rating"),
400            text=review.get("text"),
401        )
402    return """<table {table_css}>
403        <tr>
404            <th {cell_css}>Date</th>
405            <th {cell_css}>Rating</th>
406            <th {cell_css}>Comments</th>
407        </tr>
408        {rows}
409    </table>""".format(
410        table_css=table_css,
411        cell_css=cell_css,
412        rows=review_rows
413    )
414
415
416def generate_business_table(business , reviews  = None, to_html=False):
417    """
418    Makes a formatted table of a business and corresponding review.
419
420    Args:
421        business (`dict`): A dictionary that represents a business.
422        reviews (`list`): List of reviews that correspond to the business
423        to_html (`bool`): Whether you want to return an HTML representation (for email)
424                     or a string representation (to print to the screen).
425
426    Returns:
427        a `str` with either a plain text or an HTML representation of a business + reviews.
428    """
429    if not business
430        print("A business is required.")
431        return
432
433    if to_html
434        the_html = _get_business_display_html(business)
435        if reviews
436            the_html += _get_reviews_display_html(reviews)
437        return the_html
438    else
439        the_text = _get_business_display_text(business)
440        if reviews
441            the_text += _get_reviews_display_text(reviews)
442        return the_text
def get_businesses( location , limit = 10, search_term = None, categories = None, sort_by = None, price = None, open_now = None, attributes = None, debug = True, simplify = True):
200def get_businesses(location, limit=10, 
201                   search_term=None, 
202                   categories=None, 
203                   sort_by=None, price=None, open_now=None, attributes=None,
204                   debug = True,
205                   simplify=True):
206    """
207    Searches for Yelp businesses based on various search criteria. 
208    
209    Args:
210        location (`str`):   [Required] Location to search.
211        limit (`int`):      An integer indicating how many records to return. Max of 50.
212        search_term (`str`): A search term
213        categories (`str`): One or more comma-delimited categories to filter by.
214        sort_by (`str`):    How to order search results. Options are:
215                            best_match, rating, review_count, distance. Note that the
216                            rating option will be weighted by the number of reviews each
217                            restaurant has.
218        price (`str`):     How expensive 1, 2, 3, 4 or comma-delimited combo, e.g.: 1,2
219        open_now (`bool`):   Set to True if you only want the open restaurants
220        attributes (`list`): A list of any one or more of the following filters: `hot_and_new`, `reservation`, `gender_neutral_restrooms`, `open_to_all`, `wheelchair_accessible`
221        debug (`bool`): Whether or not you want to see the debug messages printed out.       
222        simplify (`bool`):  Indicates whether you want to simplify the data that is returned. Non-simplified data
223                                will return a list of dictionaries.
224
225    Returns:
226        a `list` of businesses matching your search / ordering / limit criteria.
227    """
228
229    # generate the URL query string based on the arguments passed in by the user
230    url = _generate_business_search_url(
231        location,
232        limit=limit,
233        term=search_term,
234        categories=categories,
235        sort_by=sort_by,
236        price=price,
237        open_now=open_now,
238        attributes=attributes
239    )
240    if debug
241        print(f"\nDEBUG - {"get_businesses"}:\nHere"s the request we"re going to make.\n{url}\nYou can"t access it in a browser, but you can double check the inputs you gave the function are part of the URL.")
242
243    data = _issue_get_request(url)
244    if not simplify
245        return data
246    return _simplify_businesses(data)

Searches for Yelp businesses based on various search criteria.

Arguments:
  • location (str): [Required] Location to search.
  • limit (int): An integer indicating how many records to return. Max of 50.
  • search_term (str): A search term
  • categories (str): One or more comma-delimited categories to filter by.
  • sort_by (str): How to order search results. Options are: best_match, rating, review_count, distance. Note that the rating option will be weighted by the number of reviews each restaurant has.
  • price (str): How expensive 1, 2, 3, 4 or comma-delimited combo, e.g.: 1,2
  • open_now (bool): Set to True if you only want the open restaurants
  • attributes (list): A list of any one or more of the following filters: hot_and_new, reservation, gender_neutral_restrooms, open_to_all, wheelchair_accessible
  • debug (bool): Whether or not you want to see the debug messages printed out.
  • simplify (bool): Indicates whether you want to simplify the data that is returned. Non-simplified data will return a list of dictionaries.
Returns:

a list of businesses matching your search / ordering / limit criteria.

def get_categories():
20def get_categories():
21    """
22    Simply returns a list of abbreviated categories from Yelp. Doesn"t require any arguments.
23   
24    Note that while this function returns SOME of the valid yelp categories, there"s a lot more. They are \
25    [documented on Yelp"s website](https://blog.Yelp.com/businesses/Yelp_category_list) \
26    You can use any of those as valid categories for a search.
27
28    Returns:
29        a `list` of valid yelp categories which are strings. 
30    """
31    categories = [
32        "mexican", "chinese", "pizza", "italian", "thai", "japanese",
33        "vietnamese", "asianfusion", "ethiopian", "korean", "indpak",
34        "mideastern", "tapas", "pakistani", "brazilian", "filipino",
35        "african", "greek", "coffee", "dessert", "pancakes", "gastropubs"
36    ]
37    categories.sort()
38    return categories

Simply returns a list of abbreviated categories from Yelp. Doesn't require any arguments.

Note that while this function returns SOME of the valid yelp categories, there's a lot more. They are documented on Yelp's website You can use any of those as valid categories for a search.

Returns:

a list of valid yelp categories which are strings.

def generate_businesses_table(businesses ):
248def generate_businesses_table(businesses):
249    """
250    Generates a tabular representation of a *list* of businesses to be displayed in a plain textbox.
251
252    Args:
253        businesses (`list`): A list of dictionaries (where each dictionary represents a business).
254
255    Returns:
256        a `string` representation of a table.
257    """
258    text = ""
259    template = "{0:2} | {1:22.22} | {2:<30.30} | {3:<6} | {4:<10}\n"
260
261    # header section:
262    text += "-" * 85 + "\n"
263    text += template.format(
264        "", "Name", "Address", "Rating", "# Reviews"
265    )
266    text += "-" * 85 + "\n"
267
268    # data section:
269    counter = 1
270    for business in businesses
271        text += template.format(
272            counter,
273            business.get("name"),
274            business.get("display_address"),
275            business.get("rating"),
276            business.get("review_count")
277        )
278        counter += 1
279    text += "-" * 85 + "\n"
280    return text

Generates a tabular representation of a list of businesses to be displayed in a plain textbox.

Arguments:
  • businesses (list): A list of dictionaries (where each dictionary represents a business).
Returns:

a string representation of a table.

def generate_business_table(business, reviews = None, to_html=False):
417def generate_business_table(business , reviews  = None, to_html=False):
418    """
419    Makes a formatted table of a business and corresponding review.
420
421    Args:
422        business (`dict`): A dictionary that represents a business.
423        reviews (`list`): List of reviews that correspond to the business
424        to_html (`bool`): Whether you want to return an HTML representation (for email)
425                     or a string representation (to print to the screen).
426
427    Returns:
428        a `str` with either a plain text or an HTML representation of a business + reviews.
429    """
430    if not business
431        print("A business is required.")
432        return
433
434    if to_html
435        the_html = _get_business_display_html(business)
436        if reviews
437            the_html += _get_reviews_display_html(reviews)
438        return the_html
439    else
440        the_text = _get_business_display_text(business)
441        if reviews
442            the_text += _get_reviews_display_text(reviews)
443        return the_text

Makes a formatted table of a business and corresponding review.

Arguments:
  • business (dict): A dictionary that represents a business.
  • reviews (list): List of reviews that correspond to the business
  • to_html (bool): Whether you want to return an HTML representation (for email) or a string representation (to print to the screen).
Returns:

a str with either a plain text or an HTML representation of a business + reviews.

def get_reviews(business_id, simplify = True):
283def get_reviews(business_id, simplify=True):
284    """
285    Retrieves a list of Yelp reviews for a particular business.
286    
287    Args:
288        business_id (`str`): A character string corresponding to the business id. Example: `"0b6AU869xq6KXdK3NtVJnw"`
289        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
290
291    Returns:
292        a `list` of reviews (dictionaries).
293    """
294    # https://www.yelp.com/developers/documentation/v3/business_reviews
295    url = "https://api.yelp.com/v3/businesses/" + business_id.strip() + "/reviews"
296    data = _issue_get_request(url)
297    if not simplify
298        return data
299    return _simplify_comments(data)

Retrieves a list of Yelp reviews for a particular business.

Arguments:
  • business_id (str): A character string corresponding to the business id. Example: "0b6AU869xq6KXdK3NtVJnw"
  • simplify (bool): Indicates whether you want to simplify the data that is returned.
Returns:

a list of reviews (dictionaries).