├── .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 | }
--------------------------------------------------------------------------------