<jupyter_start><jupyter_text>Property Price Guide FetcherThis script allows you to find the price range for a given property listed on [Domain.com.au](https://www.domain.com.au/) where there is no price provided by the agent.It does this by retrieving a property's details then performing a series of searches for different price ranges until it finds the upper and lower limits.See [Medium post](https://medium.com/@alexdambra/how-to-get-aussie-property-price-guides-using-python-the-domain-api-afe871efac96).*Developed by [<NAME>](https://www.linkedin.com/in/alexdambra/)*--- Import required libraries<jupyter_code>import json
import requests # this library is awesome: http://docs.python-requests.org/en/master/
import re, string, timeit
import time<jupyter_output><empty_output><jupyter_text>**Setup your parameters**1.   Set your property ID. You can grab from end of the listing's URL.      *eg. https://www.domain.com.au/132a-prince-edward-avenue-earlwood-nsw-2206-2014925785*2.   Set your starting lower bound eg. 500k starting max price. The starting min price will default to your lower bound plus 400k, or you can set this manually. This will reduce the amount of API calls required.3.   Set your increment value. This will increase/decrease the starting prices by this amount until a hit is made. eg. 50k. Smaller increments might be more accurate but increase API calls. Most agents would probably set guides in $50-100k increments one would assume anyway (can you tell I live in Sydney...)<jupyter_code># setup
property_id="2014925785"
starting_max_price=1000000
increment=50000
# when starting min price is zero we'll just use the lower bound plus 400k later on
starting_min_price=0<jupyter_output><empty_output><jupyter_text>Provide your client credentials as per your [Domain](https://developer.domain.com.au) developer account.Required: `client_id` and `client_secret`Make a POST request to receive token.<jupyter_code># POST request for token
response = requests.post('https://auth.domain.com.au/v1/connect/token', data = {'client_id':'your_client_id',"client_secret":"your_client_secret","grant_type":"client_credentials","scope":"api_listings_read","Content-Type":"text/json"})
token=response.json()
access_token=token["access_token"]<jupyter_output><empty_output><jupyter_text>Make a GET request to the listings endpoint to retrieve listing info for your selected property.<jupyter_code># GET Request for ID
url = "https://api.domain.com.au/v1/listings/"+property_id
auth = {"Authorization":"Bearer "+access_token}
request = requests.get(url,headers=auth)
r=request.json()<jupyter_output><empty_output><jupyter_text>Extract property details<jupyter_code>#get details
da=r['addressParts']
postcode=da['postcode']
suburb=da['suburb']
bathrooms=r['bathrooms']
bedrooms=r['bedrooms']
carspaces=r['carspaces']
property_type=r['propertyTypes']
print(property_type,postcode, suburb, bedrooms, bathrooms,  carspaces)

# the below puts all relevant property types into a single string. eg. a property listing can be a 'house' and a 'townhouse'
n=0
property_type_str=""
for p in r['propertyTypes']:
  property_type_str=property_type_str+(r['propertyTypes'][int(n)])
  n=n+1
print(property_type_str)<jupyter_output>['house'] 2206 Earlwood 4.0 3.0 3.0
house<jupyter_text>Now loop through a series of POST requests that search for your property starting with your starting max price, increasing by your increment each time until you get a result. We achieve this by using a `do while` loop. After receiving a response we put the list of property IDs into a Python list and then check if our original property_id is in that list.<jupyter_code>max_price=starting_max_price
searching_for_price=True
# Start your loop
while searching_for_price:
    
    url = "https://api.domain.com.au/v1/listings/residential/_search" # Set destination URL here
    post_fields ={
      "listingType":"Sale",
        "maxPrice":max_price,
        "pageSize":100,
      "propertyTypes":property_type,
      "minBedrooms":bedrooms,
        "maxBedrooms":bedrooms,
      "minBathrooms":bathrooms,
        "maxBathrooms":bathrooms,
      "locations":[
        {
          "state":"",
          "region":"",
          "area":"",
          "suburb":suburb,
          "postCode":postcode,
          "includeSurroundingSuburbs":False
        }
      ]
    }

    request = requests.post(url,headers=auth,json=post_fields)

    l=request.json()
    listings = []
    for listing in l:
        listings.append(listing["listing"]["id"])
    listings

    if int(property_id) in listings:
            max_price=max_price-increment
            print("Lower bound found: ", max_price)
            searching_for_price=False
    else:
        max_price=max_price+increment
        print("Not found. Increasing max price to ",max_price)
        time.sleep(0.1)  # sleep a bit so you don't make too many API calls too quickly<jupyter_output>Not found. Increasing max price to  1050000
Not found. Increasing max price to  1100000
Not found. Increasing max price to  1150000
Not found. Increasing max price to  1200000
Not found. Increasing max price to  1250000
Not found. Increasing max price to  1300000
Not found. Increasing max price to  1350000
Not found. Increasing max price to  1400000
Not found. Increasing max price to  1450000
Not found. Increasing max price to  1500000
Not found. Increasing max price to  1550000
Not found. Increasing max price to  1600000
Not found. Increasing max price to  1650000
Not found. Increasing max price to  1700000
Not found. Increasing max price to  1750000
Not found. Increasing max price to  1800000
Lower bound found:  1750000<jupyter_text>Now do the same but from the upper end begining with your starting min price and decreasing by your increment. This will get us an upper bound.<jupyter_code>searching_for_price=True
if starting_min_price>0:
  min_price=starting_min_price
else:  
  min_price=max_price+400000  
while searching_for_price:
    
    url = "https://api.domain.com.au/v1/listings/residential/_search" # Set destination URL here
    post_fields ={
      "listingType":"Sale",
        "minPrice":min_price,
        "pageSize":100,
      "propertyTypes":property_type,
      "minBedrooms":bedrooms,
        "maxBedrooms":bedrooms,
      "minBathrooms":bathrooms,
        "maxBathrooms":bathrooms,
      "locations":[
        {
          "state":"",
          "region":"",
          "area":"",
          "suburb":suburb,
          "postCode":postcode,
          "includeSurroundingSuburbs":False
        }
      ]
    }

    request = requests.post(url,headers=auth,json=post_fields)

    l=request.json()
    listings = []
    for listing in l:
        listings.append(listing["listing"]["id"])
    listings

    if int(property_id) in listings:
            min_price=min_price+increment
            print("Upper bound found: ", min_price)
            searching_for_price=False
    else:
        min_price=min_price-increment
        print("Not found. Decreasing min price to ",min_price)
        time.sleep(0.1)  # sleep a bit so you don't make too many API calls too quickly<jupyter_output>Not found. Decreasing min price to  2100000
Not found. Decreasing min price to  2050000
Not found. Decreasing min price to  2000000
Not found. Decreasing min price to  1950000
Not found. Decreasing min price to  1900000
Not found. Decreasing min price to  1850000
Not found. Decreasing min price to  1800000
Upper bound found:  1850000<jupyter_text>Format your numbers for your final string.<jupyter_code>if max_price<1000000:
  lower=max_price/1000
  upper=min_price/1000
  denom="k"
else: 
  lower=max_price/1000000
  upper=min_price/1000000
  denom="m"<jupyter_output><empty_output><jupyter_text>Print your results!<jupyter_code># Print the results
print(da['displayAddress'])
print(r['headline'])
print("Property Type:",property_type_str)
print("Details: ",int(bedrooms),"bedroom,",int(bathrooms),"bathroom,",int(carspaces),"carspace")
print("Display price:",r['priceDetails']['displayPrice'])      
if max_price==min_price:
  print("Price guide:","$",lower,denom)
else:
  print("Price range:","$",lower,"-","$",upper,denom)
print("URL:",r['seoUrl'])<jupyter_output>132a Prince Edward Avenue, Earlwood NSW 2206
Perfecting the art of modern family life
Property Type: house
Details:  4 bedroom, 3 bathroom, 3 carspace
Display price: Contact Agent
Price range: $ 1.75 - $ 1.85 m
URL: https://www.domain.com.au/132a-prince-edward-avenue-earlwood-nsw-2206-2014925785
{'fraction_non_alphanumeric': 0.10140148392415499, 'fraction_numerical': 0.039335767283005536, 'mean_word_length': 4.297567061759201, 'pattern_counts': {'":': 35, '<': 35, '<?xml version=': 0, '>': 35, 'https://': 10, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '250869', 'license': 'Apache-2.0', 'n_tokens_mistral': 2867, 'n_tokens_neox': 2556, 'n_words': 775, 'path': 'Property_Price_Checker_1_0.ipynb', 'repo_name': 'bashallc/IBM-Data-Science-Professional-Certificate', 'size': '8497'}