├── .gitignore ├── README.md ├── app.py ├── modules └── scrap.py ├── requirements.txt └── vercel.json /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | .vercel 3 | .venv 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

Unofficial GFG API

4 |

An unofficial API for GeeksForGeeks for developers to make cool stuff using GFG profile data.

5 |

6 | 7 |

8 | 9 | 10 |

11 | 12 | --- 13 | 14 | ## Functionalities 15 | - [x] Has all the relevant data from the GFG profile page. 16 | - [x] Has the count of all the problems solved based on difficulties. 17 | - [x] Has the links & names of all the problems solved by the user segregated based on difficulties. 18 | - [x] Methods supported - `GET` 19 | 20 | --- 21 | 22 | ## Endpoints 23 | 24 | To access the API, there is only 1 endpoint, *https://geeks-for-geeks-api.vercel.app/yourGeeksForGeeksUsername* 25 | 26 | `Sample URL` - https://geeks-for-geeks-api.vercel.app/arnoob16 27 | 28 | ## How was it built: 29 | The API was built using Web Scraping the profile page and a server deployed on web. 30 | 31 |

32 | 33 | 34 | 35 |

36 | 37 | --- 38 | 39 | ## Instructions to run on your local system 40 | 41 | * Pre-requisites: 42 | - Python 3.x 43 | - Install all the required libraries using the *requirements.txt* file. 44 | 45 | ``` pip install requirements.txt ``` 46 | 47 | * Directions to execute 48 | - ``` python app.py``` or ``` py app.py``` 49 | - Open the browser of your choice and visit your localhost, either *http://127.0.0.1:5000/yourGeeksForGeeksUsername* or *http://localhost:5000/yourGeeksForGeeksUsername* 50 | - See the API Response, understand it and build something with it. 51 | 52 | --- 53 | 54 | ### Sample API Responses 55 | #### Success Response 56 | ``` 57 | { 58 | "info": { 59 | "userName": "arnoob16", 60 | "profilePicture": "https://media.geeksforgeeks.org/img-practice/user_web-1598433228.svg", 61 | "instituteRank": "415", 62 | "currentStreak": "00", 63 | "maxStreak": "929", 64 | "institution": "SRM Institute of Science and Technology ", 65 | "languagesUsed": "Java, C++, Python", 66 | "codingScore": "224", 67 | "totalProblemsSolved": "95", 68 | "monthlyCodingScore": "" 69 | }, 70 | "solvedStats": { 71 | "school": { 72 | "count": 0, 73 | "questions": [] 74 | }, 75 | "basic": { 76 | "count": 16, 77 | "questions": [ 78 | { 79 | "question": "Cyclically rotate an array by one", 80 | "questionUrl": "https://practice.geeksforgeeks.org/problems/cyclically-rotate-an-array-by-one2614/0" 81 | }, 82 | { 83 | "question": "Union of two arrays", 84 | "questionUrl": "https://practice.geeksforgeeks.org/problems/union-of-two-arrays3538/0" 85 | }, 86 | { 87 | "question": "Middle of Three", 88 | "questionUrl": "https://practice.geeksforgeeks.org/problems/middle-of-three2926/0" 89 | } 90 | ] 91 | }, 92 | "hard": { 93 | "count": 2, 94 | "questions": [ 95 | { 96 | "question": "Merge Without Extra Space", 97 | "questionUrl": "https://practice.geeksforgeeks.org/problems/merge-two-sorted-arrays5135/0" 98 | }, 99 | { 100 | "question": "Return two prime numbers", 101 | "questionUrl": "https://practice.geeksforgeeks.org/problems/return-two-prime-numbers2509/0" 102 | } 103 | ] 104 | } 105 | } 106 | } 107 | ``` 108 | 109 | #### Failure Response 110 | ``` 111 | { 112 | "error": "Profile Not Found" 113 | } 114 | ``` 115 | --- 116 | 117 | #### Notes 118 | 119 | - If you are using this, do mention about this repository in your readme, I'll also mention your project here in this repository. 120 | - A star to the repository would be massive boost to a NOOB like me. 121 | 122 | 123 |

124 | 125 |

126 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | from flask_restful import Api, Resource 3 | from modules.scrap import scrap 4 | 5 | app = Flask(__name__) 6 | api = Api(app) 7 | 8 | class geeksforgeeksAPI(Resource): 9 | def get(self, username): 10 | scrapper = scrap(username) 11 | return scrapper.fetchResponse() 12 | 13 | 14 | api.add_resource(geeksforgeeksAPI, "/") 15 | 16 | if __name__ == "__main__": 17 | app.run(host="0.0.0.0", port=5000, debug=True) -------------------------------------------------------------------------------- /modules/scrap.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | from bs4 import BeautifulSoup as bs 4 | 5 | class scrap(): 6 | def __init__(self, username): 7 | self.username = username 8 | 9 | def fetchResponse(self): 10 | BASE_URL = f'https://auth.geeksforgeeks.org/user/{self.username}/practice/' 11 | 12 | headers = { 13 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" 14 | } 15 | 16 | profilePage = requests.get(BASE_URL, headers=headers) 17 | 18 | if profilePage.status_code != 200: 19 | return {"error": "Profile Not Found"} 20 | 21 | soup = bs(profilePage.content, 'html.parser') 22 | 23 | # Find the script tag containing JSON data 24 | script_tag = soup.find("script", id="__NEXT_DATA__", type="application/json") 25 | if not script_tag: 26 | return {"error": "Could not find user data"} 27 | 28 | # Parse the JSON data 29 | try: 30 | user_data = json.loads(script_tag.string) 31 | user_info = user_data["props"]["pageProps"]["userInfo"] 32 | user_submissions = user_data["props"]["pageProps"]["userSubmissionsInfo"] 33 | except (KeyError, json.JSONDecodeError): 34 | return {"error": "Failed to parse user data"} 35 | 36 | # Extract general information 37 | generalInfo = { 38 | "userName": self.username, 39 | "fullName": user_info.get("name", ""), 40 | "profilePicture": user_info.get("profile_image_url", ""), 41 | "institute": user_info.get("institute_name", ""), 42 | "instituteRank": user_info.get("institute_rank", ""), 43 | "currentStreak": user_info.get("pod_solved_longest_streak", "00"), 44 | "maxStreak": user_info.get("pod_solved_global_longest_streak", "00"), 45 | "codingScore": user_info.get("score", 0), 46 | "monthlyScore": user_info.get("monthly_score", 0), 47 | "totalProblemsSolved": user_info.get("total_problems_solved", 0), 48 | } 49 | 50 | # Extract solved questions by difficulty 51 | solvedStats = {} 52 | for difficulty, problems in user_submissions.items(): 53 | questions = [ 54 | { 55 | "question": details["pname"], 56 | "questionUrl": f"https://practice.geeksforgeeks.org/problems/{details['slug']}" 57 | } 58 | for details in problems.values() 59 | ] 60 | solvedStats[difficulty.lower()] = {"count": len(questions), "questions": questions} 61 | 62 | return { 63 | "info": generalInfo, 64 | "solvedStats": solvedStats 65 | } -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests==2.31.0 2 | Flask==2.3.1 3 | Flask_RESTful==0.3.10 4 | beautifulsoup4==4.12.3 -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "builds": [ 4 | { 5 | "src": "./app.py", 6 | "use": "@vercel/python" 7 | } 8 | ], 9 | "routes": [ 10 | { 11 | "src": "/(.*)", 12 | "dest": "app.py" 13 | } 14 | ] 15 | } --------------------------------------------------------------------------------