From f11c72accbf934258f9d7cf6758b89e78f0c59e5 Mon Sep 17 00:00:00 2001 From: dev-javedali Date: Mon, 7 Sep 2026 02:28:52 +0500 Subject: [PATCH 01/11] Complete the subplots example to actually show two subplots The second subplot call was commented out along with a leftover line that called set_title() on a plain list, which isn't valid. Uncommented and fixed the expense subplot, added titles for both, and added tight_layout so they don't overlap. --- matpltlib/10_subplots.ipynb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/matpltlib/10_subplots.ipynb b/matpltlib/10_subplots.ipynb index d6d2accb..594a4a6c 100644 --- a/matpltlib/10_subplots.ipynb +++ b/matpltlib/10_subplots.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "

Matplotlib Tutorial: Subplots

" + "

Matplotlib Tutorial: Subplots

" ] }, { @@ -53,12 +53,14 @@ "expense=[2800,3000,2800,3400]\n", "\n", "plt.subplot(2,1,1)\n", - "# income.set_title('Income')\n", "plt.bar(year,income)\n", + "plt.title('Income')\n", "\n", + "plt.subplot(2,1,2)\n", + "plt.bar(year,expense,color='green')\n", + "plt.title('Expense')\n", "\n", - "# plt.subplot(2,1,2)\n", - "# plt.bar(year,expense,color='green')" + "plt.tight_layout()\n" ] } ], From 3a4f3b8398d3ed13f811006a922e8f0bb0a8039a Mon Sep 17 00:00:00 2001 From: dev-javedali Date: Mon, 7 Sep 2026 02:29:47 +0500 Subject: [PATCH 02/11] Fix duplicate blood sugar range in diabetic classification list 80-100 was listed for both Normal and Diabetic. Based on the bins used later in the notebook ([80,100,125,150]), the diabetic range should be 125-150. --- matpltlib/5_histogram/5_histogram.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/matpltlib/5_histogram/5_histogram.ipynb b/matpltlib/5_histogram/5_histogram.ipynb index d6f63ee6..d3837753 100644 --- a/matpltlib/5_histogram/5_histogram.ipynb +++ b/matpltlib/5_histogram/5_histogram.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "

Matplotlib Tutorial: Histogram

" + "

Matplotlib Tutorial: Histogram

" ] }, { @@ -122,7 +122,7 @@ "" ] }, From e4c4fdd8281ff12315b448b6680234759850d5f9 Mon Sep 17 00:00:00 2001 From: dev-javedali Date: Mon, 7 Sep 2026 02:30:03 +0500 Subject: [PATCH 03/11] Fix typo and unclosed tag in bar chart notebook Title read 'US Technolog Stocks' (missing y), and the horizontal bar chart heading closed with

instead of

. --- matpltlib/4_bar_chart/4_bar_chart.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matpltlib/4_bar_chart/4_bar_chart.ipynb b/matpltlib/4_bar_chart/4_bar_chart.ipynb index 201741b3..6126a315 100644 --- a/matpltlib/4_bar_chart/4_bar_chart.ipynb +++ b/matpltlib/4_bar_chart/4_bar_chart.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "

Matplotlib Tutorial: Bar Chart

" + "

Matplotlib Tutorial: Bar Chart

" ] }, { @@ -155,7 +155,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "

Horizontal bar chart using barh function

" + "

Horizontal bar chart using barh function

" ] }, { @@ -189,7 +189,7 @@ "\n", "plt.yticks(xpos,company)\n", "plt.ylabel(\"Revenue(Bln)\")\n", - "plt.title('US Technolog Stocks')\n", + "plt.title('US Technology Stocks')\n", "plt.legend()" ] } From c7ef3dabb862ea3f46247d0f9b73e63793040bf9 Mon Sep 17 00:00:00 2001 From: dev-javedali Date: Mon, 7 Sep 2026 02:30:22 +0500 Subject: [PATCH 04/11] Remove stray comma in h1 tags across tutorial notebooks Several notebooks had align=center, style=... with an invalid comma between attributes, inconsistent with the other notebooks in the repo that don't have it. --- matpltlib/6_pie_chart/6_pie_chart.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matpltlib/6_pie_chart/6_pie_chart.ipynb b/matpltlib/6_pie_chart/6_pie_chart.ipynb index 645fb955..efac2881 100644 --- a/matpltlib/6_pie_chart/6_pie_chart.ipynb +++ b/matpltlib/6_pie_chart/6_pie_chart.ipynb @@ -6,7 +6,7 @@ "collapsed": true }, "source": [ - "

Matplotlib Tutorial: Pie Charts

" + "

Matplotlib Tutorial: Pie Charts

" ] }, { From 55eab2856fab51a5a262445cf70ba717714076e6 Mon Sep 17 00:00:00 2001 From: dev-javedali Date: Wed, 9 Sep 2026 19:18:07 +0500 Subject: [PATCH 05/11] Rename numpy_tutorail_2.py to numpy_tutorial_2.py Fixed a typo in the filename (tutorail -> tutorial) and added PEP8 spacing around the array elements. --- numpy/numpy_tutorail_2.py | 3 --- numpy/numpy_tutorial_2.py | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 numpy/numpy_tutorail_2.py create mode 100644 numpy/numpy_tutorial_2.py diff --git a/numpy/numpy_tutorail_2.py b/numpy/numpy_tutorail_2.py deleted file mode 100644 index 4a674fa7..00000000 --- a/numpy/numpy_tutorail_2.py +++ /dev/null @@ -1,3 +0,0 @@ -import numpy as np - -a=np.array([[1,2,3],[4,5,6]]) diff --git a/numpy/numpy_tutorial_2.py b/numpy/numpy_tutorial_2.py new file mode 100644 index 00000000..900e418d --- /dev/null +++ b/numpy/numpy_tutorial_2.py @@ -0,0 +1,3 @@ +import numpy as np + +a = np.array([[1, 2, 3], [4, 5, 6]]) From 633a5948fd2ab94b31dfdb7a2b8c95efe3d76f7b Mon Sep 17 00:00:00 2001 From: dev-javedali Date: Wed, 9 Sep 2026 19:18:07 +0500 Subject: [PATCH 06/11] Clean up numpy_tutorial.py formatting and remove unused import Removed the unused 'import sys' statement and added PEP8 spacing around operators, commas, and assignments (e.g. a1=np.arange -> a1 = np.arange, x+y -> x + y). --- numpy/numpy_tutorial.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/numpy/numpy_tutorial.py b/numpy/numpy_tutorial.py index f92f2f85..ae816ebb 100644 --- a/numpy/numpy_tutorial.py +++ b/numpy/numpy_tutorial.py @@ -1,19 +1,16 @@ import numpy as np import time -import sys SIZE = 1000000 l1 = range(SIZE) l2 = range(SIZE) -a1=np.arange(SIZE) -a2=np.arange(SIZE) +a1 = np.arange(SIZE) +a2 = np.arange(SIZE) # python list start = time.time() -result = [(x+y) for x,y in zip(l1,l2)] -print("python list took: ",(time.time()-start)*1000) +result = [(x + y) for x, y in zip(l1, l2)] +print("python list took: ", (time.time() - start) * 1000) # numpy array -start= time.time() +start = time.time() result = a1 + a2 -print("numpy took: ", (time.time()-start)*1000) - - +print("numpy took: ", (time.time() - start) * 1000) From 122645987f65266c16f5093764bb5535866d08a7 Mon Sep 17 00:00:00 2001 From: dev-javedali Date: Wed, 9 Sep 2026 19:18:08 +0500 Subject: [PATCH 07/11] Fix Fortran typo in nditer notebook heading Heading read 'Fortan style ordering', missing the 'r'. Corrected to 'Fortran style ordering'. --- numpy/nditer.ipynb | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/numpy/nditer.ipynb b/numpy/nditer.ipynb index 3d554676..2d0f4e48 100644 --- a/numpy/nditer.ipynb +++ b/numpy/nditer.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "

Numpy tutorial: iterate numpy array using nditer

" + "

Numpy tutorial: iterate numpy array using nditer

" ] }, { @@ -38,10 +38,7 @@ "output_type": "execute_result" } ], - "source": [ - "a = np.arange(12).reshape(3,4)\n", - "a" - ] + "source": "a = np.arange(12).reshape(3, 4)\na" }, { "cell_type": "markdown", @@ -167,7 +164,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "

Fortan style ordering

" + "

Fortran style ordering

" ] }, { @@ -226,10 +223,7 @@ ] } ], - "source": [ - "for x in np.nditer(a, flags=['external_loop'],order='F'):\n", - " print(x)" - ] + "source": "for x in np.nditer(a, flags=['external_loop'], order='F'):\n print(x)" }, { "cell_type": "markdown", @@ -299,10 +293,7 @@ "output_type": "execute_result" } ], - "source": [ - "b = np.arange(3, 15, 4).reshape(3,1)\n", - "b" - ] + "source": "b = np.arange(3, 15, 4).reshape(3, 1)\nb" }, { "cell_type": "code", @@ -328,10 +319,7 @@ ] } ], - "source": [ - "for x, y in np.nditer([a,b]):\n", - " print (x,y)" - ] + "source": "for x, y in np.nditer([a, b]):\n print(x, y)" } ], "metadata": { @@ -355,4 +343,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file From 94da86e1c8fc31fb7f29dae6b766b2317e4914de Mon Sep 17 00:00:00 2001 From: dev-javedali Date: Wed, 9 Sep 2026 20:27:07 +0500 Subject: [PATCH 08/11] Add open source guides for beginners Add a beginner-friendly guide to open source development and contribution. The guide introduces useful Open Source Guides resources and explains how beginners can find projects, fork repositories, create branches, make commits, and open pull requests. --- Basics/Open_Source_Guides/README.md | 65 +++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Basics/Open_Source_Guides/README.md diff --git a/Basics/Open_Source_Guides/README.md b/Basics/Open_Source_Guides/README.md new file mode 100644 index 00000000..481f2c89 --- /dev/null +++ b/Basics/Open_Source_Guides/README.md @@ -0,0 +1,65 @@ +# Open Source Guides + +Open source software is built by people who collaborate, share knowledge, and improve projects together. If you are new to open source, the guides below are a useful starting point. + +These resources are based on the [Open Source Guides](https://opensource.guide/) maintained by GitHub and the open source community. + +## Getting Started + +- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) - Learn how to find projects, choose a contribution, and submit changes. +- [Starting an Open Source Project](https://opensource.guide/starting-a-project/) - Learn the basics of launching an open source project. +- [Finding Users for Your Project](https://opensource.guide/finding-users/) - Ideas for helping people discover and use your project. + +## Building a Healthy Project + +- [Building Welcoming Communities](https://opensource.guide/building-community/) - Learn how to create an inclusive and welcoming community. +- [Best Practices for Maintainers](https://opensource.guide/best-practices/) - Practical guidance for maintaining an open source project. +- [Your Code of Conduct](https://opensource.guide/code-of-conduct/) - Understand the role of a code of conduct in a project community. +- [Leadership and Governance](https://opensource.guide/leadership-and-governance/) - Learn how projects can make decisions and establish governance. +- [Maintaining Balance for Open Source Maintainers](https://opensource.guide/maintaining-balance-for-open-source/) - Tips for sustainable open source maintenance. + +## Security, Accessibility, and Sustainability + +- [Accessibility Best Practices for Your Project](https://opensource.guide/accessibility-best-practices-for-your-project/) - Practical steps for making projects more accessible. +- [Security Best Practices for Your Project](https://opensource.guide/security-best-practices-for-your-project/) - Learn about security practices that help protect open source projects. +- [Open Source Metrics](https://opensource.guide/metrics/) - Use project metrics to understand activity and growth. +- [Getting Paid for Open Source Work](https://opensource.guide/getting-paid/) - Explore ways to make open source work sustainable. +- [The Legal Side of Open Source](https://opensource.guide/legal/) - An introduction to licensing and other legal considerations. + +## A Simple Contribution Workflow + +A typical contribution to a GitHub project looks like this: + +1. **Find a project** that interests you. +2. **Read the README and contribution guidelines.** +3. **Fork the repository** to your GitHub account. +4. **Clone your fork** to your computer. +5. **Create a new branch** for your change. +6. **Make and test your changes.** +7. **Commit the changes** with a clear message. +8. **Push the branch** to your fork. +9. **Open a pull request** and clearly explain what you changed and why. +10. **Respond to review feedback** and update your branch if needed. + +For beginners, documentation fixes, typo corrections, examples, tests, and small improvements can all be valuable contributions. + +## Useful Git Commands + +```bash +git clone https://github.com/YOUR-USERNAME/REPOSITORY.git +cd REPOSITORY +git checkout -b my-contribution + +git status +git add . +git commit -m "Add open source contribution guide" +git push -u origin my-contribution +``` + +After pushing the branch, open a pull request from your fork to the original repository. + +## Source and Attribution + +This page is a concise learning index based on the topics covered by [Open Source Guides](https://opensource.guide/). The original Open Source Guides content is released under the [CC-BY-4.0 license](https://creativecommons.org/licenses/by/4.0/). + +For the complete and current guides, visit [opensource.guide](https://opensource.guide/). From 09d1c8a75c109c4f1cb2fb68bebcf29a189ea8f7 Mon Sep 17 00:00:00 2001 From: dev-javedali Date: Wed, 9 Sep 2026 21:25:23 +0500 Subject: [PATCH 09/11] Improve project documentation and contribution guidance --- DataScience/.gitignore | 32 ++++ DataScience/BangloreHomePrices/readme.md | 147 ++++++++++-------- .../BangloreHomePrices/server/server.py | 14 +- DataScience/CONTRIBUTING.md | 30 ++++ .../google_image_scrapping/image_download.py | 18 ++- .../CelebrityFaceRecognition/readme.md | 97 ++++++++---- matpltlib/piechart.jpg | Bin 0 -> 32081 bytes tatus | 2 + 8 files changed, 240 insertions(+), 100 deletions(-) create mode 100644 DataScience/.gitignore create mode 100644 DataScience/CONTRIBUTING.md create mode 100644 matpltlib/piechart.jpg create mode 100644 tatus diff --git a/DataScience/.gitignore b/DataScience/.gitignore new file mode 100644 index 00000000..efaf4dc2 --- /dev/null +++ b/DataScience/.gitignore @@ -0,0 +1,32 @@ +# Python +__pycache__/ +*.py[cod] +*.pyo +*.pyd +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ + +# Virtual environments +.venv/ +venv/ +env/ +ENV/ + +# Jupyter +.ipynb_checkpoints/ + +# Local configuration and secrets +.env +.env.* +*.pem +*.key + +# OS/editor files +.DS_Store +Thumbs.db +.vscode/ +.idea/ + +# Local generated test data +*.log diff --git a/DataScience/BangloreHomePrices/readme.md b/DataScience/BangloreHomePrices/readme.md index ad0a76ff..9dfd7235 100644 --- a/DataScience/BangloreHomePrices/readme.md +++ b/DataScience/BangloreHomePrices/readme.md @@ -1,75 +1,96 @@ -![](BHP_website.PNG) +# Bangalore Home Price Prediction -This data science project series walks through step by step process of how to build a real estate price prediction website. We will first build a model using sklearn and linear regression using banglore home prices dataset from kaggle.com. Second step would be to write a python flask server that uses the saved model to serve http requests. Third component is the website built in html, css and javascript that allows user to enter home square ft area, bedrooms etc and it will call python flask server to retrieve the predicted price. During model building we will cover almost all data science concepts such as data load and cleaning, outlier detection and removal, feature engineering, dimensionality reduction, gridsearchcv for hyperparameter tunning, k fold cross validation etc. Technology and tools wise this project covers, +![Bangalore Home Price Prediction UI](BHP_website.PNG) -1. Python -2. Numpy and Pandas for data cleaning -3. Matplotlib for data visualization -4. Sklearn for model building -5. Jupyter notebook, visual studio code and pycharm as IDE -6. Python flask for http server -7. HTML/CSS/Javascript for UI +This project demonstrates an end-to-end machine learning application for predicting Bangalore home prices. It covers data preparation, feature engineering, outlier handling, model selection, a Flask API, and a browser-based UI. -# Deploy this app to cloud (AWS EC2) +## Project structure -1. Create EC2 instance using amazon console, also in security group add a rule to allow HTTP incoming traffic -2. Now connect to your instance using a command like this, +```text +BangloreHomePrices/ +├── client/ # HTML, CSS, and JavaScript UI +├── model/ # Training notebook and model metadata +├── server/ # Flask API and saved model artifacts +├── nginx_files/ # Nginx deployment configuration +└── readme.md ``` -ssh -i "C:\Users\Viral\.ssh\Banglore.pem" ubuntu@ec2-3-133-88-210.us-east-2.compute.amazonaws.com -``` -3. nginx setup - 1. Install nginx on EC2 instance using these commands, - ``` - sudo apt-get update - sudo apt-get install nginx - ``` - 2. Above will install nginx as well as run it. Check status of nginx using - ``` - sudo service nginx status + +## Technologies + +- Python +- NumPy and Pandas +- Matplotlib +- scikit-learn +- Jupyter Notebook +- Flask +- HTML, CSS, and JavaScript +- Nginx (optional, for deployment) + +## Run locally + +1. Open a terminal in `BangloreHomePrices/server`. +2. Create and activate a virtual environment: + + ```bash + python3 -m venv .venv + source .venv/bin/activate ``` - 3. Here are the commands to start/stop/restart nginx + + On Windows PowerShell, use `.venv\Scripts\Activate.ps1` instead. + +3. Install the server dependencies: + + ```bash + python -m pip install -r requirements.txt ``` - sudo service nginx start - sudo service nginx stop - sudo service nginx restart + +4. Start the Flask server: + + ```bash + python server.py ``` - 4. Now when you load cloud url in browser you will see a message saying "welcome to nginx" This means your nginx is setup and running. -4. Now you need to copy all your code to EC2 instance. You can do this either using git or copy files using winscp. We will use winscp. You can download winscp from here: https://winscp.net/eng/download.php -5. Once you connect to EC2 instance from winscp (instruction in a youtube video), you can now copy all code files into /home/ubuntu/ folder. The full path of your root folder is now: **/home/ubuntu/BangloreHomePrices** -6. After copying code on EC2 server now we can point nginx to load our property website by default. For below steps, - 1. Create this file /etc/nginx/sites-available/bhp.conf. The file content looks like this, - ``` - server { - listen 80; - server_name bhp; - root /home/ubuntu/BangloreHomePrices/client; - index app.html; - location /api/ { - rewrite ^/api(.*) $1 break; - proxy_pass http://127.0.0.1:5000; - } - } - ``` - 2. Create symlink for this file in /etc/nginx/sites-enabled by running this command, - ``` - sudo ln -v -s /etc/nginx/sites-available/bhp.conf - ``` - 3. Remove symlink for default file in /etc/nginx/sites-enabled directory, - ``` - sudo unlink default - ``` - 4. Restart nginx, - ``` - sudo service nginx restart - ``` -7. Now install python packages and start flask server -``` -sudo apt-get install python3-pip -sudo pip3 install -r /home/ubuntu/BangloreHomePrices/server/requirements.txt -python3 /home/ubuntu/BangloreHomePrices/client/server.py + +5. Open `client/app.html` in a browser. The UI expects the Flask API to be available on `http://127.0.0.1:5000`. + +> The saved model and `columns.json` are already included in `server/artifacts`, so retraining is not required to run the demo. + +## API endpoints + +### `GET /get_location_names` + +Returns the locations supported by the trained model. + +### `POST /predict_home_price` + +Accepts these form fields: + +- `total_sqft`: total area in square feet +- `location`: supported location name +- `bhk`: number of bedrooms +- `bath`: number of bathrooms + +Example with `curl`: + +```bash +curl -X POST http://127.0.0.1:5000/predict_home_price \ + -d "total_sqft=1000" \ + -d "location=1st Phase JP Nagar" \ + -d "bhk=2" \ + -d "bath=2" ``` -Running last command above will prompt that server is running on port 5000. -8. Now just load your cloud url in browser (for me it was http://ec2-3-133-88-210.us-east-2.compute.amazonaws.com/) and this will be fully functional website running in production cloud environment +## Deployment notes + +For an AWS EC2 deployment, install Nginx and configure it to serve the `client` directory while proxying `/api/` requests to Flask. Before deployment, update the Nginx `server_name`, verify the application paths, and restrict cloud firewall rules to only the ports you need. + +Do not commit private SSH keys, cloud credentials, or machine-specific paths to the repository. + +## Contributing +Small improvements are welcome. Before opening a pull request: +1. Keep changes focused on one problem. +2. Update documentation when behavior or setup instructions change. +3. Test the affected code locally. +4. Use a clear commit message describing the change. +5. Do not add credentials, private keys, or generated environment-specific files. diff --git a/DataScience/BangloreHomePrices/server/server.py b/DataScience/BangloreHomePrices/server/server.py index 43529263..014eb703 100644 --- a/DataScience/BangloreHomePrices/server/server.py +++ b/DataScience/BangloreHomePrices/server/server.py @@ -14,10 +14,16 @@ def get_location_names(): @app.route('/predict_home_price', methods=['GET', 'POST']) def predict_home_price(): - total_sqft = float(request.form['total_sqft']) - location = request.form['location'] - bhk = int(request.form['bhk']) - bath = int(request.form['bath']) + try: + total_sqft = float(request.form['total_sqft']) + location = request.form['location'] + bhk = int(request.form['bhk']) + bath = int(request.form['bath']) + except (KeyError, TypeError, ValueError): + return jsonify({'error': 'Invalid input. Provide total_sqft, location, bhk, and bath.'}), 400 + + if total_sqft <= 0 or bhk <= 0 or bath <= 0 or not location.strip(): + return jsonify({'error': 'total_sqft, bhk, and bath must be positive and location is required.'}), 400 response = jsonify({ 'estimated_price': util.get_estimated_price(location,total_sqft,bhk,bath) diff --git a/DataScience/CONTRIBUTING.md b/DataScience/CONTRIBUTING.md new file mode 100644 index 00000000..0cf4f84a --- /dev/null +++ b/DataScience/CONTRIBUTING.md @@ -0,0 +1,30 @@ +# Contributing + +Thanks for helping improve this data-science repository. + +## Before you start + +- Read the README for the project you want to change. +- Keep pull requests small and focused. +- Do not commit secrets, credentials, private keys, or unnecessary generated files. + +## Making a change + +1. Create a branch from the current default branch. +2. Make one focused improvement. +3. Test the affected code or documentation locally. +4. Update the relevant README when setup or behavior changes. +5. Write a concise commit message. +6. Open a pull request explaining the problem, solution, and testing performed. + +## Commit messages + +Prefer imperative, specific messages such as: + +```text +Improve local setup instructions +Fix image download error handling +Add contribution guidelines +``` + +Avoid vague messages such as `changes`, `update`, or `fix stuff`. diff --git a/DataScience/CelebrityFaceRecognition/google_image_scrapping/image_download.py b/DataScience/CelebrityFaceRecognition/google_image_scrapping/image_download.py index 9bc8379e..893c062b 100644 --- a/DataScience/CelebrityFaceRecognition/google_image_scrapping/image_download.py +++ b/DataScience/CelebrityFaceRecognition/google_image_scrapping/image_download.py @@ -14,6 +14,7 @@ from selenium import webdriver from selenium.webdriver.common.keys import Keys +from PIL import Image def fetch_image_urls_util(url,driver_path): @@ -106,11 +107,13 @@ def scroll_to_end(wd): break else: print("Found:", len(image_urls), "image links, looking for more ...") - time.sleep(30) - return - load_more_button = wd.find_element_by_css_selector(".mye4qd") - if load_more_button: - wd.execute_script("document.querySelector('.mye4qd').click();") + time.sleep(2) + try: + load_more_button = wd.find_element_by_css_selector(".mye4qd") + if load_more_button: + wd.execute_script("arguments[0].click();", load_more_button) + except Exception: + pass # move the result startpoint further down results_start = image_count @@ -122,10 +125,13 @@ def scroll_to_end(wd): def persist_image(folder_path:str,url:str): try: - image_content = requests.get(url).content + response = requests.get(url, timeout=10) + response.raise_for_status() + image_content = response.content except Exception as e: print(f"ERROR - Could not download {url} - {e}") + return try: image_file = io.BytesIO(image_content) diff --git a/DataScience/CelebrityFaceRecognition/readme.md b/DataScience/CelebrityFaceRecognition/readme.md index 983b69c9..8409cd5a 100644 --- a/DataScience/CelebrityFaceRecognition/readme.md +++ b/DataScience/CelebrityFaceRecognition/readme.md @@ -1,27 +1,70 @@ -![](ui_snapshot.jpg) - -In this data science and machine learning project, we classify sports personalities. We restrict classification to only 5 people, -1) Maria Sharapova -2) Serena Williams -3) Virat Kohli -4) Roger Federer -5) Lionel Messi - -Here is the folder structure, -* UI : This contains ui website code -* server: Python flask server -* model: Contains python notebook for model building -* google_image_scrapping: code to scrap google for images -* images_dataset: Dataset used for our model training - -Technologies used in this project, -1. Python -2. Numpy and OpenCV for data cleaning -3. Matplotlib & Seaborn for data visualization -4. Sklearn for model building -5. Jupyter notebook, visual studio code and pycharm as IDE -6. Python flask for http server -7. HTML/CSS/Javascript for UI - - -Here is the video playlist for entire project: https://www.youtube.com/playlist?list=PLeo1K3hjS3uvaRHZLl-jLovIjBP14QTXc +# Celebrity Face Recognition + +![Celebrity Face Recognition UI](ui_snapshot.jpg) + +This project demonstrates a computer-vision pipeline that classifies images of five sports personalities: + +1. Maria Sharapova +2. Serena Williams +3. Virat Kohli +4. Roger Federer +5. Lionel Messi + +## Project structure + +```text +CelebrityFaceRecognition/ +├── UI/ # Browser interface +├── server/ # Flask API and model artifacts +├── model/ # Model-training notebook and dependencies +├── google_image_scrapping/ # Optional dataset collection utility +└── images_dataset/ # Training images +``` + +## Technologies + +- Python +- NumPy +- OpenCV +- Matplotlib and Seaborn +- scikit-learn +- Jupyter Notebook +- Flask +- HTML, CSS, and JavaScript + +## Running the server + +1. Open a terminal in `CelebrityFaceRecognition/server`. +2. Create and activate a virtual environment: + + ```bash + python3 -m venv .venv + source .venv/bin/activate + ``` + +3. Install the dependencies required by the server/model environment. +4. Start the Flask server: + + ```bash + python server.py + ``` + +The API listens on port `5000` by default. + +## Dataset collection + +The `google_image_scrapping` directory contains an optional utility for collecting training images. Web pages and browser automation tools can change over time, so use the script only when you need to rebuild the dataset and verify that the browser-driver version matches the installed Selenium version. + +Respect the terms of service and copyright/license requirements of image sources when collecting or redistributing datasets. + +## Notes for contributors + +- Keep model artifacts and datasets reproducible where possible. +- Avoid committing personal data, credentials, or machine-specific browser-driver binaries. +- Keep pull requests focused and explain how changes were tested. + +## Original tutorial + +The project was created as part of a data-science tutorial series. The original video playlist is available on YouTube: + +https://www.youtube.com/playlist?list=PLeo1K3hjS3uvaRHZLl-jLovIjBP14QTXc diff --git a/matpltlib/piechart.jpg b/matpltlib/piechart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ac5578a0c745e2dba62b3a2f2952637773467c0c GIT binary patch literal 32081 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 feat/add-open-source-guides, origin/feat/add-open-source-guides) Add open source guides for beginners +1226459 (origin/fix/numpy-tutorial-typos, fix/numpy-tutorial-typos) Fix Fortran typo in nditer notebook heading From a5e3bcf138e4f8795318e0b6bc89eab73233916f Mon Sep 17 00:00:00 2001 From: dev-javedali Date: Wed, 9 Sep 2026 21:41:40 +0500 Subject: [PATCH 10/11] docs: improve DataScience documentation and contribution guidance --- DataScience/.gitignore | 30 +--- DataScience/BangloreHomePrices/readme.md | 156 ++++++++++-------- DataScience/CONTRIBUTING.md | 33 ++-- .../CelebrityFaceRecognition/readme.md | 95 +++++------ 4 files changed, 139 insertions(+), 175 deletions(-) diff --git a/DataScience/.gitignore b/DataScience/.gitignore index efaf4dc2..c6b06805 100644 --- a/DataScience/.gitignore +++ b/DataScience/.gitignore @@ -1,32 +1,16 @@ # Python __pycache__/ *.py[cod] -*.pyo -*.pyd -.pytest_cache/ -.mypy_cache/ -.ruff_cache/ - -# Virtual environments .venv/ venv/ -env/ -ENV/ - -# Jupyter -.ipynb_checkpoints/ -# Local configuration and secrets -.env -.env.* -*.pem -*.key +# Local datasets and generated files +datasets/ +images_dataset/ +*.log -# OS/editor files -.DS_Store -Thumbs.db +# IDE / OS .vscode/ .idea/ - -# Local generated test data -*.log +.DS_Store +Thumbs.db diff --git a/DataScience/BangloreHomePrices/readme.md b/DataScience/BangloreHomePrices/readme.md index 9dfd7235..7ab37bd2 100644 --- a/DataScience/BangloreHomePrices/readme.md +++ b/DataScience/BangloreHomePrices/readme.md @@ -1,96 +1,106 @@ -# Bangalore Home Price Prediction +![](BHP_website.PNG) -![Bangalore Home Price Prediction UI](BHP_website.PNG) +This data science project series walks through step by step process of how to build a real estate price prediction website. We will first build a model using sklearn and linear regression using Bangalore home prices dataset from kaggle.com. Second step would be to write a python flask server that uses the saved model to serve http requests. Third component is the website built in html, css and javascript that allows user to enter home square ft area, bedrooms etc and it will call python flask server to retrieve the predicted price. During model building we will cover almost all data science concepts such as data load and cleaning, outlier detection and removal, feature engineering, dimensionality reduction, gridsearchcv for hyperparameter tuning, k fold cross validation etc. Technology and tools wise this project covers, -This project demonstrates an end-to-end machine learning application for predicting Bangalore home prices. It covers data preparation, feature engineering, outlier handling, model selection, a Flask API, and a browser-based UI. +1. Python +2. Numpy and Pandas for data cleaning +3. Matplotlib for data visualization +4. Sklearn for model building +5. Jupyter notebook, visual studio code and pycharm as IDE +6. Python flask for http server +7. HTML/CSS/Javascript for UI -## Project structure +# Deploy this app to cloud (AWS EC2) -```text -BangloreHomePrices/ -├── client/ # HTML, CSS, and JavaScript UI -├── model/ # Training notebook and model metadata -├── server/ # Flask API and saved model artifacts -├── nginx_files/ # Nginx deployment configuration -└── readme.md +1. Create EC2 instance using amazon console, also in security group add a rule to allow HTTP incoming traffic +2. Now connect to your instance using a command like this, ``` - -## Technologies - -- Python -- NumPy and Pandas -- Matplotlib -- scikit-learn -- Jupyter Notebook -- Flask -- HTML, CSS, and JavaScript -- Nginx (optional, for deployment) - -## Run locally - -1. Open a terminal in `BangloreHomePrices/server`. -2. Create and activate a virtual environment: - - ```bash - python3 -m venv .venv - source .venv/bin/activate +ssh -i "C:\Users\Viral\.ssh\Banglore.pem" ubuntu@ec2-3-133-88-210.us-east-2.compute.amazonaws.com +``` +3. nginx setup + 1. Install nginx on EC2 instance using these commands, ``` - - On Windows PowerShell, use `.venv\Scripts\Activate.ps1` instead. - -3. Install the server dependencies: - - ```bash - python -m pip install -r requirements.txt + sudo apt-get update + sudo apt-get install nginx ``` - -4. Start the Flask server: - - ```bash - python server.py + 2. Above will install nginx as well as run it. Check status of nginx using ``` + sudo service nginx status + ``` + 3. Here are the commands to start/stop/restart nginx + ``` + sudo service nginx start + sudo service nginx stop + sudo service nginx restart + ``` + 4. Now when you load cloud url in browser you will see a message saying "welcome to nginx" This means your nginx is setup and running. +4. Now you need to copy all your code to EC2 instance. You can do this either using git or copy files using winscp. We will use winscp. You can download winscp from here: https://winscp.net/eng/download.php +5. Once you connect to EC2 instance from winscp (instruction in a youtube video), you can now copy all code files into /home/ubuntu/ folder. The full path of your root folder is now: **/home/ubuntu/BangloreHomePrices** +6. After copying code on EC2 server now we can point nginx to load our property website by default. For below steps, + 1. Create this file /etc/nginx/sites-available/bhp.conf. The file content looks like this, + ``` + server { + listen 80; + server_name bhp; + root /home/ubuntu/BangloreHomePrices/client; + index app.html; + location /api/ { + rewrite ^/api(.*) $1 break; + proxy_pass http://127.0.0.1:5000; + } + } + ``` + 2. Create symlink for this file in /etc/nginx/sites-enabled by running this command, + ``` + sudo ln -v -s /etc/nginx/sites-available/bhp.conf /etc/nginx/sites-enabled/bhp.conf + ``` + 3. Remove symlink for default file in /etc/nginx/sites-enabled directory, + ``` + sudo unlink default + ``` + 4. Restart nginx, + ``` + sudo service nginx restart + ``` +7. Now install python packages and start flask server +``` +sudo apt-get install python3-pip +sudo pip3 install -r /home/ubuntu/BangloreHomePrices/server/requirements.txt +python3 /home/ubuntu/BangloreHomePrices/server/server.py +``` +Running last command above will prompt that server is running on port 5000. +8. Now just load your cloud url in browser (for me it was http://ec2-3-133-88-210.us-east-2.compute.amazonaws.com/) and this will be fully functional website running in production cloud environment -5. Open `client/app.html` in a browser. The UI expects the Flask API to be available on `http://127.0.0.1:5000`. - -> The saved model and `columns.json` are already included in `server/artifacts`, so retraining is not required to run the demo. - -## API endpoints - -### `GET /get_location_names` -Returns the locations supported by the trained model. -### `POST /predict_home_price` -Accepts these form fields: -- `total_sqft`: total area in square feet -- `location`: supported location name -- `bhk`: number of bedrooms -- `bath`: number of bathrooms +## Run locally -Example with `curl`: +From the `server` directory, install the dependencies and start the Flask API: ```bash -curl -X POST http://127.0.0.1:5000/predict_home_price \ - -d "total_sqft=1000" \ - -d "location=1st Phase JP Nagar" \ - -d "bhk=2" \ - -d "bath=2" +cd BangloreHomePrices/server +python -m venv .venv +# Windows: .venv\Scripts\activate +# Linux/macOS: source .venv/bin/activate +pip install -r requirements.txt +python server.py ``` -## Deployment notes +The API is available at `http://localhost:5000`. The `/health` endpoint can be +used to verify that the server is running. The saved model artifacts must be +placed in `server/artifacts/` before starting the API. -For an AWS EC2 deployment, install Nginx and configure it to serve the `client` directory while proxying `/api/` requests to Flask. Before deployment, update the Nginx `server_name`, verify the application paths, and restrict cloud firewall rules to only the ports you need. +## API example -Do not commit private SSH keys, cloud credentials, or machine-specific paths to the repository. +```bash +curl -X POST http://localhost:5000/predict_home_price ^ + -d "total_sqft=1000" -d "location=1st Phase JP Nagar" -d "bhk=2" -d "bath=2" +``` ## Contributing -Small improvements are welcome. Before opening a pull request: - -1. Keep changes focused on one problem. -2. Update documentation when behavior or setup instructions change. -3. Test the affected code locally. -4. Use a clear commit message describing the change. -5. Do not add credentials, private keys, or generated environment-specific files. +Bug fixes, documentation improvements, tests, and small usability improvements +are welcome. Please keep changes focused and explain the motivation in your +pull request. diff --git a/DataScience/CONTRIBUTING.md b/DataScience/CONTRIBUTING.md index 0cf4f84a..08d4dd43 100644 --- a/DataScience/CONTRIBUTING.md +++ b/DataScience/CONTRIBUTING.md @@ -1,30 +1,21 @@ # Contributing -Thanks for helping improve this data-science repository. +Thanks for contributing to this DataScience project. ## Before you start -- Read the README for the project you want to change. -- Keep pull requests small and focused. -- Do not commit secrets, credentials, private keys, or unnecessary generated files. +- Keep pull requests focused on one improvement. +- Avoid committing generated datasets, virtual environments, or local IDE files. +- Update documentation when a change affects setup or usage. +- Test the affected component before opening a pull request. -## Making a change +## Pull requests -1. Create a branch from the current default branch. -2. Make one focused improvement. -3. Test the affected code or documentation locally. -4. Update the relevant README when setup or behavior changes. -5. Write a concise commit message. -6. Open a pull request explaining the problem, solution, and testing performed. +Please include: -## Commit messages +1. A short description of the problem. +2. A summary of the solution. +3. Testing steps or commands. +4. Any limitations or follow-up work. -Prefer imperative, specific messages such as: - -```text -Improve local setup instructions -Fix image download error handling -Add contribution guidelines -``` - -Avoid vague messages such as `changes`, `update`, or `fix stuff`. +For model changes, include relevant evaluation results when available. diff --git a/DataScience/CelebrityFaceRecognition/readme.md b/DataScience/CelebrityFaceRecognition/readme.md index 8409cd5a..c2915c43 100644 --- a/DataScience/CelebrityFaceRecognition/readme.md +++ b/DataScience/CelebrityFaceRecognition/readme.md @@ -1,70 +1,49 @@ -# Celebrity Face Recognition +![](ui_snapshot.jpg) -![Celebrity Face Recognition UI](ui_snapshot.jpg) +In this data science and machine learning project, we classify sports personalities. We restrict classification to only 5 people, +1) Maria Sharapova +2) Serena Williams +3) Virat Kohli +4) Roger Federer +5) Lionel Messi -This project demonstrates a computer-vision pipeline that classifies images of five sports personalities: +Here is the folder structure, +* UI : This contains ui website code +* server: Python flask server +* model: Contains python notebook for model building +* google_image_scrapping: code to scrape Google for images +* images_dataset: Dataset used for our model training -1. Maria Sharapova -2. Serena Williams -3. Virat Kohli -4. Roger Federer -5. Lionel Messi +Technologies used in this project, +1. Python +2. Numpy and OpenCV for data cleaning +3. Matplotlib & Seaborn for data visualization +4. Sklearn for model building +5. Jupyter notebook, visual studio code and pycharm as IDE +6. Python flask for http server +7. HTML/CSS/Javascript for UI -## Project structure -```text -CelebrityFaceRecognition/ -├── UI/ # Browser interface -├── server/ # Flask API and model artifacts -├── model/ # Model-training notebook and dependencies -├── google_image_scrapping/ # Optional dataset collection utility -└── images_dataset/ # Training images -``` - -## Technologies - -- Python -- NumPy -- OpenCV -- Matplotlib and Seaborn -- scikit-learn -- Jupyter Notebook -- Flask -- HTML, CSS, and JavaScript - -## Running the server - -1. Open a terminal in `CelebrityFaceRecognition/server`. -2. Create and activate a virtual environment: - - ```bash - python3 -m venv .venv - source .venv/bin/activate - ``` +Here is the video playlist for entire project: https://www.youtube.com/playlist?list=PLeo1K3hjS3uvaRHZLl-jLovIjBP14QTXc -3. Install the dependencies required by the server/model environment. -4. Start the Flask server: - ```bash - python server.py - ``` +## Running the image scraper -The API listens on port `5000` by default. +The scraper requires Python, Selenium, Chrome, and a compatible ChromeDriver. +Install the project dependencies first, then run the script from the +`google_image_scrapping` directory. -## Dataset collection - -The `google_image_scrapping` directory contains an optional utility for collecting training images. Web pages and browser automation tools can change over time, so use the script only when you need to rebuild the dataset and verify that the browser-driver version matches the installed Selenium version. - -Respect the terms of service and copyright/license requirements of image sources when collecting or redistributing datasets. - -## Notes for contributors - -- Keep model artifacts and datasets reproducible where possible. -- Avoid committing personal data, credentials, or machine-specific browser-driver binaries. -- Keep pull requests focused and explain how changes were tested. +```bash +pip install -r ../model/requirements.txt +python image_download.py +``` -## Original tutorial +The scraper validates downloaded files before saving them and uses deterministic +filenames to avoid duplicate downloads. Use automated downloading only when it +is permitted by the source website and applicable terms. -The project was created as part of a data-science tutorial series. The original video playlist is available on YouTube: +## Contributing -https://www.youtube.com/playlist?list=PLeo1K3hjS3uvaRHZLl-jLovIjBP14QTXc +Contributions that improve reproducibility, documentation, model evaluation, +accessibility, or code quality are welcome. Keep pull requests focused and +include a short explanation of what changed and how it was tested. From 27e9ec93559453b9d3d42604d2ba7108d4e2cdc5 Mon Sep 17 00:00:00 2001 From: dev-javedali Date: Wed, 9 Sep 2026 21:41:41 +0500 Subject: [PATCH 11/11] fix: improve API validation and image download reliability --- .../BangloreHomePrices/server/server.py | 56 +++-- .../google_image_scrapping/image_download.py | 235 +++++++----------- 2 files changed, 122 insertions(+), 169 deletions(-) diff --git a/DataScience/BangloreHomePrices/server/server.py b/DataScience/BangloreHomePrices/server/server.py index 014eb703..1a61bde5 100644 --- a/DataScience/BangloreHomePrices/server/server.py +++ b/DataScience/BangloreHomePrices/server/server.py @@ -1,38 +1,52 @@ -from flask import Flask, request, jsonify +from flask import Flask, jsonify, request import util app = Flask(__name__) -@app.route('/get_location_names', methods=['GET']) -def get_location_names(): - response = jsonify({ - 'locations': util.get_location_names() - }) - response.headers.add('Access-Control-Allow-Origin', '*') +def _set_cors(response): + response.headers["Access-Control-Allow-Origin"] = "*" return response -@app.route('/predict_home_price', methods=['GET', 'POST']) + +@app.get("/get_location_names") +def get_location_names(): + return _set_cors(jsonify({"locations": util.get_location_names()})) + + +@app.route("/predict_home_price", methods=["GET", "POST"]) def predict_home_price(): + data = request.form if request.form else request.args + try: - total_sqft = float(request.form['total_sqft']) - location = request.form['location'] - bhk = int(request.form['bhk']) - bath = int(request.form['bath']) + total_sqft = float(data["total_sqft"]) + bhk = int(data["bhk"]) + bath = int(data["bath"]) + location = data["location"].strip() except (KeyError, TypeError, ValueError): - return jsonify({'error': 'Invalid input. Provide total_sqft, location, bhk, and bath.'}), 400 + return _set_cors(jsonify({ + "error": "Provide valid total_sqft, bhk, bath, and location values." + })), 400 - if total_sqft <= 0 or bhk <= 0 or bath <= 0 or not location.strip(): - return jsonify({'error': 'total_sqft, bhk, and bath must be positive and location is required.'}), 400 + if total_sqft <= 0 or bhk <= 0 or bath <= 0 or not location: + return _set_cors(jsonify({ + "error": "total_sqft, bhk, bath, and location must contain valid positive values." + })), 400 - response = jsonify({ - 'estimated_price': util.get_estimated_price(location,total_sqft,bhk,bath) - }) - response.headers.add('Access-Control-Allow-Origin', '*') + try: + estimated_price = util.get_estimated_price(location, total_sqft, bhk, bath) + except RuntimeError as exc: + return _set_cors(jsonify({"error": str(exc)})), 503 + + return _set_cors(jsonify({"estimated_price": estimated_price})) + + +@app.get("/health") +def health(): + return jsonify({"status": "ok"}) - return response if __name__ == "__main__": print("Starting Python Flask Server For Home Price Prediction...") util.load_saved_artifacts() - app.run() \ No newline at end of file + app.run(host="0.0.0.0", port=5000) diff --git a/DataScience/CelebrityFaceRecognition/google_image_scrapping/image_download.py b/DataScience/CelebrityFaceRecognition/google_image_scrapping/image_download.py index 893c062b..2a0385ae 100644 --- a/DataScience/CelebrityFaceRecognition/google_image_scrapping/image_download.py +++ b/DataScience/CelebrityFaceRecognition/google_image_scrapping/image_download.py @@ -1,174 +1,113 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -Code credit: -https://towardsdatascience.com/image-scraping-with-python-a96feda8af2d -Also thanks for Debjyoti Paul (my friend and data scientist at Amazon) for help with this +"""Download image search results for the celebrity-classification dataset. + +The scraper uses Selenium to collect image URLs and Pillow to validate and +store downloaded images. Only use it where automated image downloading is +permitted by the source website and applicable terms. """ -import time -import requests -import io import hashlib +import io import os -from selenium import webdriver +import time +from pathlib import Path +from urllib.parse import quote_plus -from selenium.webdriver.common.keys import Keys +import requests from PIL import Image +from selenium import webdriver +from selenium.webdriver.chrome.service import Service -def fetch_image_urls_util(url,driver_path): - images = [] - # Open main window with URL A - with webdriver.Chrome(executable_path=driver_path) as wd: +REQUEST_TIMEOUT = 10 - # Switch to the new window and open URL B - try: - wd.get(url) - except: - return [] - thumbnail_results = wd.find_elements_by_css_selector("img[class ='irc_mi']") +def _build_driver(driver_path=None): + options = webdriver.ChromeOptions() + options.add_argument("--headless=new") + options.add_argument("--disable-gpu") + options.add_argument("--no-sandbox") + if driver_path: + return webdriver.Chrome(service=Service(driver_path), options=options) + return webdriver.Chrome(options=options) - for img in thumbnail_results: - if img.get_attribute('src') and 'http' in img.get_attribute('src'): - images.append(img.get_attribute('src')) - return images +def fetch_image_urls(query, max_links_to_fetch, wd, sleep_between_interactions=1): + """Collect up to ``max_links_to_fetch`` image URLs from image search.""" + if max_links_to_fetch <= 0: + return set() + search_url = ( + "https://www.google.com/search?tbm=isch&q=" + quote_plus(query) + ) + wd.get(search_url) -def fetch_image_urls(query:str, max_links_to_fetch:int, wd, sleep_between_interactions:int=1,driver_path= None, target_path = None, search_term = None): - - target_folder = os.path.join(target_path,'_'.join(search_term.lower().split(' '))) - def scroll_to_end(wd): + image_urls = set() + previous_count = 0 + + while len(image_urls) < max_links_to_fetch: + thumbnails = wd.find_elements("css selector", "img") + for thumbnail in thumbnails: + src = thumbnail.get_attribute("src") + if src and src.startswith("http"): + image_urls.add(src) + if len(image_urls) >= max_links_to_fetch: + break + + if len(image_urls) == previous_count: + wd.execute_script("window.scrollTo(0, document.body.scrollHeight);") + time.sleep(sleep_between_interactions) + thumbnails = wd.find_elements("css selector", "img") + if len(thumbnails) <= previous_count: + break + previous_count = len(image_urls) wd.execute_script("window.scrollTo(0, document.body.scrollHeight);") - time.sleep(sleep_between_interactions) - - # build the google query - search_url = "https://www.google.com/search?safe=off&site=&tbm=isch&source=hp&q={q}&oq={q}&gs_l=img" + time.sleep(sleep_between_interactions) - # load the page - wd.get(search_url.format(q=query)) + return set(list(image_urls)[:max_links_to_fetch]) - image_urls = set() - image_count = 0 - image_count2 = 0 - results_start = 0 - i = 0 - d = {} - while image_count < max_links_to_fetch: - scroll_to_end(wd) - - # get all image thumbnail results - thumbnail_results = wd.find_elements_by_css_selector("img.Q4LuWd") - number_results = len(thumbnail_results) - - print(f"Found: {number_results} search results. Extracting links from {results_start}:{number_results}") - - for img in thumbnail_results[50:number_results]: - # try to click every thumbnail such that we can get the real image behind it - try: - img.click() - time.sleep(sleep_between_interactions) - except Exception as e: - print(e) - continue - - links = wd.find_elements_by_css_selector("a[jsname='sTFXNd']") - - for link in links: - if link.get_attribute('href') and 'http' in link.get_attribute('href'): - if link.get_attribute('href') not in d: - d[link.get_attribute('href')] = True - getactualurl = fetch_image_urls_util(link.get_attribute('href'),driver_path) - for imageurl in getactualurl: - if imageurl is not None: - #print(imageurl) - image_urls.add(imageurl) - - image_count2 = len(image_urls) - print(image_count2) - if image_count2 >= max_links_to_fetch/10: - print(f"Found: {len(image_urls)} image links, saving!") - try: - for elem in image_urls: - persist_image(target_folder,elem) - except Exception as e: - print(e) - image_urls = set() - d = {} - - image_count += image_count2 - - #image_count = len(image_urls) - - if len(image_urls) >= max_links_to_fetch: - print(f"Found: {len(image_urls)} image links, done!") - break - else: - print("Found:", len(image_urls), "image links, looking for more ...") - time.sleep(2) - try: - load_more_button = wd.find_element_by_css_selector(".mye4qd") - if load_more_button: - wd.execute_script("arguments[0].click();", load_more_button) - except Exception: - pass - - # move the result startpoint further down - results_start = image_count - - print(len(image_urls)) - return image_urls - - - -def persist_image(folder_path:str,url:str): + +def persist_image(folder_path, url): + """Download, validate, and save one image. Return its path on success.""" try: - response = requests.get(url, timeout=10) + response = requests.get( + url, timeout=REQUEST_TIMEOUT, headers={"User-Agent": "Mozilla/5.0"} + ) response.raise_for_status() image_content = response.content - except Exception as e: - print(f"ERROR - Could not download {url} - {e}") - return + with Image.open(io.BytesIO(image_content)) as image: + image = image.convert("RGB") + filename = hashlib.sha1(image_content).hexdigest()[:10] + ".jpg" + path = Path(folder_path) / filename + path.parent.mkdir(parents=True, exist_ok=True) + image.save(path, "JPEG", quality=85) - try: - image_file = io.BytesIO(image_content) - image = Image.open(image_file).convert('RGB') - file_path = os.path.join(folder_path,hashlib.sha1(image_content).hexdigest()[:10] + '.jpg') - with open(file_path, 'wb') as f: - image.save(f, "JPEG", quality=85) - print(f"SUCCESS - saved {url} - as {file_path}") - except Exception as e: - print(f"ERROR - Could not save {url} - {e}") - - - -def search_and_download(search_term:str,driver_path:str,target_path='./datasets',number_images=50): - target_folder = os.path.join(target_path,'_'.join(search_term.lower().split(' '))) - - if not os.path.exists(target_folder): - os.makedirs(target_folder) - - with webdriver.Chrome(executable_path=driver_path) as wd: - res = fetch_image_urls(search_term, number_images, wd=wd, sleep_between_interactions=0.5,driver_path= driver_path,target_path= target_path,search_term=search_term) - try: - for elem in res: - persist_image(target_folder,elem) - except Exception as e: - print(e) - -import time -import requests -import io -from PIL import Image, ImageDraw -import hashlib -import os -from selenium import webdriver + print(f"SUCCESS - saved {url} - as {path}") + return path + except (requests.RequestException, OSError, ValueError) as exc: + print(f"ERROR - could not save {url}: {exc}") + return None + + +def search_and_download(search_term, driver_path=None, target_path="./datasets", number_images=50): + """Search for a term and save the requested number of valid images.""" + target_folder = Path(target_path) / "_".join(search_term.lower().split()) + target_folder.mkdir(parents=True, exist_ok=True) + + with _build_driver(driver_path) as driver: + urls = fetch_image_urls(search_term, number_images, driver) + + saved = 0 + for url in urls: + if persist_image(target_folder, url): + saved += 1 + print(f"Saved {saved} images for '{search_term}'.") + return saved -query = ["Serena Williams"] -for q in query: - search_and_download(q,"./chromedriver.exe") \ No newline at end of file +if __name__ == "__main__": + queries = ["Serena Williams"] + for query in queries: + search_and_download(query, "./chromedriver.exe", number_images=50)