├── .gitignore ├── app ├── _init_.py ├── config.py ├── google_sheets │ ├── __pycache__ │ │ └── sheet.cpython-312.pyc │ ├── _init_.py │ └── sheet.py ├── ml │ ├── __pycache__ │ │ └── model.cpython-312.pyc │ ├── _init_.py │ └── model.py ├── routes │ ├── __pycache__ │ │ ├── add_to_sheet.cpython-312.pyc │ │ ├── analyze.cpython-312.pyc │ │ └── scrape.cpython-312.pyc │ ├── _init_.py │ ├── add_to_sheet.py │ ├── analyze.py │ └── scrape.py └── scraping │ ├── __pycache__ │ └── scraper.cpython-312.pyc │ ├── _init_.py │ └── scraper.py ├── config.py ├── readme.md ├── requirements.txt ├── server.py └── tests ├── _init_.py ├── test_model.py ├── test_routes.py ├── test_scraper.py └── test_sheet.py /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | /venv -------------------------------------------------------------------------------- /app/_init_.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | def create_app(): 4 | app = Flask(__name__) 5 | app.config.from_object('config.Config') 6 | return app 7 | -------------------------------------------------------------------------------- /app/config.py: -------------------------------------------------------------------------------- 1 | class Config: 2 | SECRET_KEY = 'your_secret_key' 3 | GOOGLE_SHEET_ID = 'your_google_sheet_id' 4 | # Add other configuration variables if needed (e.g., API keys) 5 | -------------------------------------------------------------------------------- /app/google_sheets/__pycache__/sheet.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codev612/real-estate-assignment-python-server/c6ce83dbcf7e6749c4acff785087d130c0baddf6/app/google_sheets/__pycache__/sheet.cpython-312.pyc -------------------------------------------------------------------------------- /app/google_sheets/_init_.py: -------------------------------------------------------------------------------- 1 | # This file can be empty or used for importing Google Sheets functionality if needed. 2 | -------------------------------------------------------------------------------- /app/google_sheets/sheet.py: -------------------------------------------------------------------------------- 1 | import gspread 2 | from oauth2client.service_account import ServiceAccountCredentials 3 | 4 | def authenticate_google_sheets(): 5 | scope = ["https://spreadsheets.google.com/feeds", 'https://www.googleapis.com/auth/spreadsheets'] 6 | creds = ServiceAccountCredentials.from_json_keyfile_name('your-credentials.json', scope) 7 | client = gspread.authorize(creds) 8 | return client 9 | 10 | def append_to_sheet(price, link): 11 | client = authenticate_google_sheets() 12 | spreadsheet = client.open('Rental Listings').sheet1 13 | spreadsheet.append_row([price, link]) 14 | -------------------------------------------------------------------------------- /app/ml/__pycache__/model.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codev612/real-estate-assignment-python-server/c6ce83dbcf7e6749c4acff785087d130c0baddf6/app/ml/__pycache__/model.cpython-312.pyc -------------------------------------------------------------------------------- /app/ml/_init_.py: -------------------------------------------------------------------------------- 1 | # This file can be empty or used for importing ML functionality if needed. 2 | -------------------------------------------------------------------------------- /app/ml/model.py: -------------------------------------------------------------------------------- 1 | from sklearn.ensemble import RandomForestClassifier 2 | import pandas as pd 3 | 4 | def train_model(): 5 | # Training data (replace with actual data) 6 | data_df = pd.DataFrame({ 7 | 'price': [1500, 2000, 2500, 3000], 8 | 'projected_revenue': [3500, 2500, 5000, 4000], 9 | }) 10 | data_df['high_potential'] = data_df['projected_revenue'] > (2 * data_df['price']) 11 | 12 | model = RandomForestClassifier() 13 | model.fit(data_df[['price', 'projected_revenue']], data_df['high_potential']) 14 | return model 15 | 16 | def analyze_listing(model, price, projected_revenue): 17 | prediction = model.predict([[price, projected_revenue]]) 18 | return bool(prediction[0]) 19 | -------------------------------------------------------------------------------- /app/routes/__pycache__/add_to_sheet.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codev612/real-estate-assignment-python-server/c6ce83dbcf7e6749c4acff785087d130c0baddf6/app/routes/__pycache__/add_to_sheet.cpython-312.pyc -------------------------------------------------------------------------------- /app/routes/__pycache__/analyze.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codev612/real-estate-assignment-python-server/c6ce83dbcf7e6749c4acff785087d130c0baddf6/app/routes/__pycache__/analyze.cpython-312.pyc -------------------------------------------------------------------------------- /app/routes/__pycache__/scrape.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codev612/real-estate-assignment-python-server/c6ce83dbcf7e6749c4acff785087d130c0baddf6/app/routes/__pycache__/scrape.cpython-312.pyc -------------------------------------------------------------------------------- /app/routes/_init_.py: -------------------------------------------------------------------------------- 1 | # This file can be empty or used for importing routes functionality if needed. 2 | -------------------------------------------------------------------------------- /app/routes/add_to_sheet.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, request, jsonify 2 | from app.google_sheets.sheet import append_to_sheet 3 | 4 | add_to_sheet_bp = Blueprint('add_to_sheet', __name__) 5 | 6 | @add_to_sheet_bp.route('/add_to_sheet', methods=['POST']) 7 | def add_to_sheet(): 8 | data = request.json 9 | price = data['price'] 10 | link = data['link'] 11 | 12 | append_to_sheet(price, link) 13 | 14 | return jsonify({'status': 'success'}) 15 | -------------------------------------------------------------------------------- /app/routes/analyze.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, request, jsonify 2 | from app.ml.model import train_model, analyze_listing 3 | 4 | analyze_bp = Blueprint('analyze', __name__) 5 | 6 | @analyze_bp.route('/analyze', methods=['POST']) 7 | def analyze(): 8 | data = request.json 9 | price = data['price'] 10 | projected_revenue = data['projected_revenue'] 11 | 12 | model = train_model() 13 | result = analyze_listing(model, price, projected_revenue) 14 | 15 | return jsonify({'high_potential': result}) 16 | -------------------------------------------------------------------------------- /app/routes/scrape.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, jsonify 2 | from app.scraping.scraper import scrape_listings 3 | 4 | scrape_bp = Blueprint('scrape', __name__) 5 | 6 | @scrape_bp.route('/scrape', methods=['GET']) 7 | def scrape(): 8 | listings = scrape_listings() 9 | return jsonify(listings) 10 | -------------------------------------------------------------------------------- /app/scraping/__pycache__/scraper.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codev612/real-estate-assignment-python-server/c6ce83dbcf7e6749c4acff785087d130c0baddf6/app/scraping/__pycache__/scraper.cpython-312.pyc -------------------------------------------------------------------------------- /app/scraping/_init_.py: -------------------------------------------------------------------------------- 1 | # This file can be empty or used for importing scraping functionality if needed. 2 | -------------------------------------------------------------------------------- /app/scraping/scraper.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | from selenium.webdriver.chrome.service import Service 3 | from selenium.webdriver.common.by import By 4 | from selenium.webdriver.chrome.options import Options 5 | from webdriver_manager.chrome import ChromeDriverManager 6 | from selenium.webdriver.support.ui import WebDriverWait 7 | from selenium.webdriver.support import expected_conditions as EC 8 | import time 9 | 10 | def get_driver(): 11 | chrome_options = Options() 12 | chrome_options.binary_location = r"C:\chrome-win64\chrome.exe" 13 | # chrome_options.add_argument('--headless') # Run browser in headless mode 14 | driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options) 15 | print(driver) 16 | 17 | return driver 18 | 19 | def scrape_listings(): 20 | try: 21 | driver = get_driver() 22 | url = 'https://www.zillow.com/san-diego-ca/rentals/' 23 | driver.get(url) 24 | 25 | # Wait until the listings are loaded 26 | WebDriverWait(driver, 20).until( 27 | EC.presence_of_element_located((By.CLASS_NAME, "property-card-data")) 28 | ) 29 | 30 | listings = [] 31 | listings_elements = driver.find_elements(By.CLASS_NAME, "property-card-data") 32 | 33 | for item in listings_elements: 34 | try: 35 | price_element = item.find_element(By.CSS_SELECTOR, '[data-test="property-card-price"]') 36 | price = price_element.text.strip() if price_element else "N/A" 37 | 38 | link_element = item.find_element(By.CSS_SELECTOR, '[data-test="property-card-link"]') 39 | link = link_element.get_attribute('href') if link_element else "N/A" 40 | 41 | listings.append({'price': price, 'link': link}) 42 | except Exception as e: 43 | print(f"Error extracting details for item: {e}") 44 | continue 45 | 46 | driver.quit() 47 | print(listings) 48 | return listings 49 | except Exception as e: 50 | print(f"Error: {e}") 51 | driver.quit() 52 | return [] 53 | 54 | # Call the function to test 55 | scrape_listings() 56 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codev612/real-estate-assignment-python-server/c6ce83dbcf7e6749c4acff785087d130c0baddf6/config.py -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | install 2 | python -m venv venv 3 | source venv/bin/activate # On Windows: venv\Scripts\activate -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask>=2.2.3 2 | requests>=2.28.2 3 | beautifulsoup4>=4.11.1 4 | gspread>=5.0.1 5 | oauth2client>=4.1.3 6 | scikit-learn>=1.2.0 7 | pandas>=1.5.3 8 | selenium>=4.10.0 9 | webdriver-manager>=3.8.6 10 | -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | from app.routes.scrape import scrape_bp 3 | from app.routes.analyze import analyze_bp 4 | from app.routes.add_to_sheet import add_to_sheet_bp 5 | 6 | app = Flask(__name__) 7 | app.register_blueprint(scrape_bp) 8 | app.register_blueprint(analyze_bp) 9 | app.register_blueprint(add_to_sheet_bp) 10 | 11 | if __name__ == '__main__': 12 | app.run(debug=True) 13 | -------------------------------------------------------------------------------- /tests/_init_.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codev612/real-estate-assignment-python-server/c6ce83dbcf7e6749c4acff785087d130c0baddf6/tests/_init_.py -------------------------------------------------------------------------------- /tests/test_model.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codev612/real-estate-assignment-python-server/c6ce83dbcf7e6749c4acff785087d130c0baddf6/tests/test_model.py -------------------------------------------------------------------------------- /tests/test_routes.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codev612/real-estate-assignment-python-server/c6ce83dbcf7e6749c4acff785087d130c0baddf6/tests/test_routes.py -------------------------------------------------------------------------------- /tests/test_scraper.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codev612/real-estate-assignment-python-server/c6ce83dbcf7e6749c4acff785087d130c0baddf6/tests/test_scraper.py -------------------------------------------------------------------------------- /tests/test_sheet.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codev612/real-estate-assignment-python-server/c6ce83dbcf7e6749c4acff785087d130c0baddf6/tests/test_sheet.py --------------------------------------------------------------------------------