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
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.
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.
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.
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.
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).