├── .gitignore ├── DriverNavigator.py ├── PageHandler ├── CompanyProblemPageHandler.py ├── Helper.py ├── LoginPageHandler.py ├── MainTableHandler.py ├── ProblemPageHandler.py ├── StudyPlanPageHandler.py └── __init__.py ├── README.md ├── driver └── chromedriver.exe ├── main.py ├── requirements.txt └── urls ├── companyUrls.txt ├── problemUrls.txt └── problemsetUrls.txt /.gitignore: -------------------------------------------------------------------------------- 1 | LeetcodeScrapper/* 2 | __pycache__/ 3 | PageHandler/__pycache__/ 4 | *.pyc 5 | Leetcode Scrapper Output/* -------------------------------------------------------------------------------- /DriverNavigator.py: -------------------------------------------------------------------------------- 1 | 2 | import time 3 | from selenium.webdriver.common.by import By 4 | import random 5 | import os 6 | from PageHandler.Helper import PATH_MANAGER, NoCredentialsError 7 | from difflib import SequenceMatcher 8 | 9 | 10 | class DriverNavigator(): 11 | def __init__(self, driver, stack, require_login) -> None: 12 | self.require_login = require_login 13 | self.driver = driver 14 | self.url_handlers = {} 15 | self.stack = stack 16 | self.fail_url = [] 17 | self.login_url = "https://leetcode.com/accounts/login/" 18 | 19 | def add_url_handlers(self, url, handler): 20 | self.url_handlers[url] = handler 21 | 22 | def process_page(self): 23 | url = self.driver.current_url 24 | for i in self.url_handlers: 25 | if i in url: 26 | handler = self.url_handlers[i] 27 | try: 28 | handler.process_page() 29 | self.handle_success(handler, url) 30 | return 31 | except NoCredentialsError: 32 | url = self.stack.pop() 33 | print(url + " require login but no credetials passed") 34 | return 35 | except Exception as e: 36 | print(url, e) 37 | self.handle_fail(url) 38 | return 39 | print("invalid url") 40 | self.stack.pop() 41 | 42 | 43 | def handle_success(self, handler, url): 44 | if(is_same_link(url1=url, url2=self.stack[-1])): 45 | self.stack.pop() 46 | handler.log_data() 47 | 48 | def handle_fail(self, url): 49 | self.fail_url.append(url) 50 | if(is_same_link(url1=url, url2=self.stack[-1])): 51 | self.stack.pop() 52 | 53 | def need_to_relogin(self): 54 | is_logged_out = self.driver.find_elements(By.ID, "navbar_sign_in_button") 55 | login_url_is_not_queued = self.login_url not in self.driver.current_url 56 | is_need_to_authenticate = self.require_login 57 | return is_logged_out and login_url_is_not_queued and is_need_to_authenticate 58 | 59 | 60 | def run(self): 61 | while len(self.stack) > 0: 62 | print("Queue: " + str(len(self.stack))) 63 | self.driver.get(self.stack[-1]) 64 | if (self.need_to_relogin()): 65 | self.stack.append(self.login_url) 66 | continue 67 | time.sleep(random.randint(1,5)) 68 | self.process_page() 69 | self.log_failed_urls() 70 | 71 | def log_failed_urls(self): 72 | if(len(self.fail_url) ==0): 73 | return 74 | with open(os.path.join(PATH_MANAGER.target_path, 'fail_urls.txt'), 'w') as f: 75 | for line in self.fail_url: 76 | f.write(f"{line}\n") 77 | 78 | 79 | def is_same_link(url1, url2): 80 | return SequenceMatcher(None, url1, url2).ratio() > 0.9 81 | -------------------------------------------------------------------------------- /PageHandler/CompanyProblemPageHandler.py: -------------------------------------------------------------------------------- 1 | 2 | from selenium.webdriver.common.by import By 3 | from selenium.webdriver.support.wait import WebDriverWait 4 | import time 5 | from urllib.parse import urlparse 6 | from PageHandler.Helper import log_data 7 | 8 | 9 | class CompanyProblemPageHandler(): 10 | def __init__(self, driver) -> None: 11 | self.driver = driver 12 | self.problem_lists = [] 13 | self.data = {} 14 | 15 | def clear_data(self): 16 | self.problem_lists = [] 17 | self.data = {} 18 | 19 | def log_data(self): 20 | url_data = urlparse(self.driver.current_url) 21 | folder_name = url_data.path.split("/")[1] 22 | file_name = url_data.path.split("/")[2] 23 | self.data["companyName"] = file_name.split() 24 | log_data(self.data, folder_name=folder_name, file_name= file_name) 25 | 26 | def process_page(self): 27 | self.clear_data() 28 | WebDriverWait(self.driver, timeout=100).until(lambda d: d.find_element(By.ID,"react-select-2--value-item")) 29 | options_id = ['0', '1', '2', '3'] 30 | for option_id in options_id: 31 | option_element_name = "react-select-2--option-" + option_id 32 | self.click_drop_down() 33 | time.sleep(1) 34 | if(self.is_option_exist(option_element_name)): 35 | self.driver.find_element(By.ID, option_element_name).click() 36 | time.sleep(1) 37 | data = self.get_table_data(duration=self.get_duration()) 38 | self.problem_lists.append(data) 39 | breakpoint() 40 | self.data["data"] = self.problem_lists 41 | 42 | def click_drop_down(self): 43 | time_drop_down = self.driver.find_element(By.ID, "react-select-2--value-item") 44 | time_drop_down.click() 45 | time.sleep(0.5) 46 | return time_drop_down.text 47 | 48 | def get_duration(self): 49 | return self.driver.find_element(By.ID, "react-select-2--value-item").text 50 | 51 | def is_option_exist(self, element_id): 52 | if len(self.driver.find_elements(By.ID, element_id)) == 0: 53 | self.click_drop_down() 54 | return False 55 | return True 56 | 57 | def get_table_data(self, duration): 58 | script = ''' 59 | const rows = document.getElementsByClassName('reactable-data')[0].children; 60 | const problems = []; 61 | for (const row of rows) { 62 | const problem = {} 63 | const cols = row.children; 64 | const tags = Array.from(cols[3].querySelectorAll('a')).map(t => t.innerText.trim()).join(', '); 65 | const frequency = parseFloat(row.getElementsByClassName('progress-bar')[0].style.width); 66 | const link = cols[2].querySelector('a').href; 67 | problem["problemId"] = cols[1].innerText.trim() 68 | problem["problemName"] = cols[2].innerText.trim() 69 | problem["acceptance"] = cols[3].innerText.trim() 70 | problem["difficulty"] = cols[4].innerText.trim() 71 | problem["frequency"] = frequency 72 | problem["url"] = link 73 | problems.push(problem) 74 | } 75 | return problems 76 | ''' 77 | companyProblemsData = self.driver.execute_script(script) 78 | data ={"duration": duration, "problemData":companyProblemsData } 79 | return data -------------------------------------------------------------------------------- /PageHandler/Helper.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | 4 | 5 | class PathManager(): 6 | def __init__(self) -> None: 7 | self.path = os.getcwd() 8 | self.target_path = self.create_parent_folder() 9 | 10 | def create_parent_folder(self): 11 | folder_name = "Leetcode Scrapper Output" 12 | target_path = os.path.join(os.curdir , folder_name) 13 | try: 14 | os.mkdir(target_path) 15 | except FileExistsError: 16 | pass 17 | return target_path 18 | 19 | def get_path(self): 20 | return self.target_path 21 | 22 | def create_folder(self, name): 23 | end_path = os.path.join(self.target_path, name) 24 | try: 25 | os.mkdir(end_path) 26 | except FileExistsError as e: 27 | pass 28 | return end_path 29 | 30 | def create_status_log(self): 31 | pass 32 | 33 | PATH_MANAGER = PathManager() 34 | 35 | def log_data(data, folder_name, file_name): 36 | file_name += ".json" 37 | folder = PATH_MANAGER.create_folder(folder_name) 38 | with open(os.path.join(folder,file_name), "w") as f: 39 | json.dump(data, f) 40 | 41 | 42 | class NoCredentialsError(Exception): 43 | def __init__(self, url): 44 | self.message = f"The page {url} require login but login credentials not passed" 45 | super().__init__(self.message) 46 | 47 | -------------------------------------------------------------------------------- /PageHandler/LoginPageHandler.py: -------------------------------------------------------------------------------- 1 | 2 | from selenium.webdriver.common.by import By 3 | from selenium.webdriver.support.wait import WebDriverWait 4 | import time 5 | from PageHandler.Helper import NoCredentialsError 6 | from selenium.common.exceptions import NoSuchElementException 7 | 8 | class LoginPageHandler(): 9 | def __init__(self, driver , username, password) -> None: 10 | self.driver = driver 11 | self.username = username 12 | self.password = password 13 | 14 | def log_data(self): 15 | pass 16 | 17 | def is_capcha_required(self): 18 | iframes = self.driver.find_elements(By.CSS_SELECTOR,"iframe") 19 | if len(iframes) ==4: 20 | print("Captcha required, press any key after solving captcha") 21 | self.driver.maximize_window() 22 | input() 23 | self.try_click_login_btn() 24 | 25 | 26 | def check_page(self): 27 | WebDriverWait(self.driver, timeout=100).until(lambda d: d.find_element(By.ID,"id_login")) 28 | 29 | def try_click_login_btn(self): 30 | try: 31 | self.driver.find_element(By.CLASS_NAME, "btn-content__2V4r").click() 32 | except NoSuchElementException: 33 | pass 34 | 35 | def process_page(self): 36 | self.check_page() 37 | if self.username == "" or self.username == None: 38 | raise NoCredentialsError(self.driver.current_url) 39 | time.sleep(1) 40 | self.driver.find_element(by = By.ID, value = "id_login").send_keys(self.username) 41 | self.driver.find_element(by = By.ID, value = "id_password").send_keys(self.password) 42 | self.try_click_login_btn() 43 | time.sleep(3) 44 | self.is_capcha_required() 45 | 46 | -------------------------------------------------------------------------------- /PageHandler/MainTableHandler.py: -------------------------------------------------------------------------------- 1 | from selenium.webdriver.common.by import By 2 | from selenium.webdriver.support.wait import WebDriverWait 3 | import time 4 | from PageHandler.Helper import log_data 5 | from urllib.parse import urlparse 6 | import re 7 | 8 | class MainTableHandler(): 9 | def __init__(self, driver) -> None: 10 | self.driver = driver 11 | self.data = {} 12 | 13 | def check_page(self): 14 | WebDriverWait(self.driver, timeout=100).until(lambda d: d.find_element(By.CSS_SELECTOR,"div[role='rowgroup']")) 15 | 16 | def log_data(self): 17 | url_data = urlparse(self.driver.current_url) 18 | file_name = url_data.query 19 | file_name = re.sub(r'[^\w]', ' ', file_name) 20 | self.data["page"] = file_name.split(" ")[-1] 21 | folder_name = url_data.path.split("/")[1] 22 | log_data(self.data, folder_name=folder_name, file_name=file_name) 23 | 24 | def process_page(self): 25 | self.check_page() 26 | time.sleep(1) 27 | table = self.driver.find_elements(by = By.CSS_SELECTOR, value = "div[role='rowgroup']")[0] 28 | rows = table.find_elements(by = By.CSS_SELECTOR, value = "div[role='row']") 29 | complete_data = [] 30 | for i in rows: 31 | row_data = self.get_row_data(i) 32 | complete_data.append(row_data) 33 | self.data["tableData"] = complete_data 34 | 35 | def get_current_page(self): 36 | return self.driver.current_url.split("=")[-1] 37 | 38 | def get_row_data(self, row): 39 | cells = row.find_elements(by = By.CSS_SELECTOR, value = "div[role='cell']") 40 | is_premium = (cells[0].find_elements(by = By.CLASS_NAME, value = "text-brand-orange") or None) != None 41 | problem_name = cells[1].text 42 | have_solution = len(cells[2].find_elements(by = By.TAG_NAME, value = "svg")) != 0 43 | solution_is_premium = len(cells[2].find_elements(by = By.CLASS_NAME, value = "text-purple")) != 0 44 | acceptence = cells[3].text 45 | difficulty = cells[4].text 46 | frequency = None 47 | if (cells[-1].find_elements(by = By.CLASS_NAME, value = "bg-brand-orange") or None != None): 48 | frequency = str(cells[-1].find_element(by = By.CLASS_NAME, value = "bg-brand-orange").get_attribute('style')).split(": ")[-1].replace(";", "") 49 | url = cells[1].find_element(by = By.TAG_NAME, value = "a").get_attribute('href') 50 | row_data = { 51 | "isPremium": is_premium, 52 | "problemName": problem_name, 53 | "haveSolution": have_solution, 54 | "isVideoSolution":solution_is_premium, 55 | "acceptance":acceptence, 56 | "difficulty": difficulty, 57 | "frequency":frequency, 58 | "url":url 59 | } 60 | return row_data 61 | 62 | -------------------------------------------------------------------------------- /PageHandler/ProblemPageHandler.py: -------------------------------------------------------------------------------- 1 | from selenium.webdriver.common.by import By 2 | from selenium.webdriver.support.wait import WebDriverWait 3 | import time 4 | from PageHandler.Helper import log_data, NoCredentialsError 5 | from urllib.parse import urlparse 6 | from selenium.common.exceptions import NoSuchElementException 7 | 8 | class ProblemPageHandler(): 9 | def __init__(self, driver) -> None: 10 | self.driver = driver 11 | self.data = {"tags":[], "problem": ""} 12 | 13 | def remove_on_focus_listener(self): 14 | script = ''' 15 | Object.defineProperty(window.document,'hidden',{get:function(){return false;},configurable:true}); 16 | Object.defineProperty(window.document,'visibilityState',{get:function(){return 'visible';},configurable:true}); 17 | window.document.dispatchEvent(new Event('visibilitychange')); 18 | ''' 19 | self.driver.execute_script(script) 20 | 21 | def get_problem_innerHTML(self): 22 | return self.driver.find_element(By.CLASS_NAME, "_1l1MA").get_attribute('innerHTML') 23 | 24 | def check_page(self): 25 | try: 26 | WebDriverWait(self.driver, timeout=10).until(lambda d: d.find_element(By.ID,"qd-content")) 27 | except Exception as e: 28 | if self.switch_to_new_version() == False: 29 | raise e 30 | 31 | def get_similar_questions(self): 32 | try: 33 | similar_question_tab = self.driver.find_elements(By.CLASS_NAME, "translate-y-0")[0] 34 | questions = similar_question_tab.find_elements(By.CLASS_NAME, "w-full") 35 | data = [] 36 | for question in questions: 37 | question_name = question.find_elements(By.TAG_NAME, "a")[0].text 38 | difficulty = question.find_elements(By.CLASS_NAME, "text-xs")[0].text 39 | question_data = {"questionName": question_name, "difficulty": difficulty} 40 | data.append(question_data) 41 | return data 42 | except Exception as e: 43 | return [] 44 | 45 | def open_all_lower_tab(self): 46 | tabs = self.driver.find_elements(By.CLASS_NAME, "py-3") 47 | for tab in tabs: 48 | pointers = tab.find_elements(By.CLASS_NAME, "cursor-pointer") 49 | if len(pointers) != 0: 50 | pointers[0].click() 51 | time.sleep(1.5) 52 | 53 | 54 | def get_related_topics(self): 55 | try: 56 | related_topic_tab = self.driver.find_elements(By.CLASS_NAME, "translate-y-0")[1] 57 | data = [] 58 | tags = related_topic_tab.find_elements(By.TAG_NAME, "a") 59 | for tag in tags: 60 | data.append(tag.text) 61 | return data 62 | except Exception as e: 63 | return [] 64 | 65 | 66 | def require_subscription(self): 67 | return len(self.driver.find_elements(By.CLASS_NAME, "text-2xl")) > 0 68 | 69 | def switch_to_new_version(self): 70 | new_btn = self.driver.find_elements(By.CLASS_NAME, "css-ly0btt-NewDiv") 71 | if len(new_btn) >0: 72 | new_btn[0].click() 73 | return True 74 | return False 75 | 76 | 77 | def get_companies_tags(self): 78 | try: 79 | row = self.driver.find_elements(By.CLASS_NAME, "flex-wrap")[0] 80 | row.find_elements(By.CLASS_NAME, "transition-colors")[-1].click() 81 | # time.sleep(1) 82 | WebDriverWait(self.driver, timeout=15).until(lambda d: d.find_element(By.CSS_SELECTOR,"div[role='dialog']")) 83 | dialog = self.driver.find_element(By.CSS_SELECTOR,"div[role='dialog']") 84 | tag_data = self.get_tag_data(dialog=dialog) 85 | return tag_data 86 | except Exception as e: 87 | self.data["isError"] = True 88 | print(self.driver.current_url) 89 | return [] 90 | 91 | 92 | def process_page(self): 93 | self.data = {"tags":[], "problem": ""} 94 | self.check_page() 95 | # self.remove_on_focus_listener() 96 | time.sleep(2) 97 | if self.require_subscription(): 98 | raise NoCredentialsError(self.driver.current_url) 99 | # self.open_all_lower_tab() 100 | self.data["relatedTopics"] = [] 101 | self.data["similarQuestions"] = [] 102 | self.data["problem"] = self.get_problem_innerHTML() 103 | self.data["tags"] = self.get_companies_tags() 104 | self.data["editorial"] = self. get_editorial() 105 | 106 | def get_editorial(self): 107 | try: 108 | self.driver.get(self.driver.current_url + "editorial") 109 | time.sleep(2) 110 | return self.driver.find_element(By.CLASS_NAME, "break-words").get_attribute('innerHTML') 111 | except: 112 | return "" 113 | 114 | 115 | def get_tag_data(self, dialog): 116 | buttons = dialog.find_element(By.CLASS_NAME, "space-x-9").find_elements(By.CLASS_NAME, "cursor-pointer") 117 | tag_data = [] 118 | for button in buttons: 119 | button.click() 120 | time.sleep(2) 121 | duration = button.text 122 | companies = [] 123 | datas = dialog.find_elements(By.CLASS_NAME, "mt-3") 124 | for data in datas: 125 | text = data.text 126 | companies.append([duration, text]) 127 | tag_data.append({"duration": duration, "companies": companies}) 128 | return tag_data 129 | 130 | def log_data(self): 131 | url_data = urlparse(self.driver.current_url) 132 | folder_name = url_data.path.split("/")[1] 133 | file_name = url_data.path.split("/")[2] 134 | self.data["problemName"] = file_name 135 | log_data(self.data, folder_name=folder_name, file_name=file_name) 136 | -------------------------------------------------------------------------------- /PageHandler/StudyPlanPageHandler.py: -------------------------------------------------------------------------------- 1 | 2 | from selenium.webdriver.common.by import By 3 | from selenium.webdriver.support.wait import WebDriverWait 4 | import time 5 | from PageHandler.Helper import NoCredentialsError 6 | from urllib.parse import urlparse 7 | from PageHandler.Helper import log_data 8 | from selenium.common.exceptions import NoSuchElementException 9 | 10 | 11 | class StudyPlanPageHandler(): 12 | def __init__(self, driver) -> None: 13 | self.driver = driver 14 | self.data = {} 15 | 16 | 17 | def log_data(self): 18 | url_data = urlparse(self.driver.current_url) 19 | folder_name = url_data.path.split("/")[1] 20 | file_name = url_data.path.split("/")[2] 21 | self.data["studyPlan"] = file_name 22 | log_data(self.data, folder_name=folder_name, file_name=file_name) 23 | 24 | def process_page(self): 25 | self.check_page() 26 | self.data = self.get_study_plan_data() 27 | 28 | def check_page(self): 29 | WebDriverWait(self.driver, timeout=100).until(lambda d: d.find_element(By.CLASS_NAME,"css-yw0m6t")) 30 | 31 | def get_study_plan_data(self): 32 | sections = self.driver.find_elements(By.CLASS_NAME, "css-yw0m6t") 33 | data = {} 34 | for i in sections: 35 | title = i.find_element(By.CLASS_NAME, "text-lc-text-primary").text 36 | problems = i.find_elements(By.CLASS_NAME, "truncate") 37 | problem_data = [] 38 | for problem in problems: 39 | problem_data.append(problem.text) 40 | data[title] = problem_data 41 | return data 42 | 43 | 44 | -------------------------------------------------------------------------------- /PageHandler/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Edwardsoen/LeetcodeScrapper/39b40dd4ac2030b7a818559d9940c7a5206dce3b/PageHandler/__init__.py -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Leetcode Scrapper

2 | LeetCode Scraper is a Selenium based Python script that scrapes information from Leetcode.com and stores the data in JSON format. 3 |
4 |
5 | 6 | 7 | 8 | > Note: if you just want to see company wise problems check out the subtree here , it is scraped in Febuary 2023. Alternatively you can checkout Leetcode Premium Unlocker browser extension, which will automatically inject premium data when you open the website. 9 | 10 |

Dependencies

11 | 12 | ``` 13 | selenium==4.8.0 14 | ``` 15 | 16 | 17 | 18 |

Currently Supported pages

19 |
  • https://leetcode.com/problemset/*
  • 20 |
  • https://leetcode.com/problem-list/*
  • 21 |
  • https://leetcode.com/company/
  • 22 | 23 | 24 |

    Usage

    25 | 26 | 27 | clone repo + install dependencies 28 | 29 | ``` 30 | git clone https://github.com/Edwardsoen/LeetcodeScrapper.git 31 | cd LeetcodeScrapper 32 | pip install -r requirements.txt 33 | ``` 34 | 35 | download chromedriver here and paste it to system path 36 | 37 | 38 | if you want to scrape single page, simply run 39 | ``` 40 | Python3 main.py {url} 41 | ``` 42 | but in most cases you probably want to scrape multiple pages, in which case you need to store the urls into seperate txt file (or you can use pre-scrapped urls here) and pass it like this 43 | ``` 44 | Python3 main.py {urlsfile.txt} 45 | ``` 46 | if you need to scrape premium data you can pass username and password like so 47 | ``` 48 | Python3 main.py -u {username} -p {password} {urls} 49 | ``` 50 | 51 | 52 |

    Sample output

    53 | 54 |

    Company Problem page

    55 | 56 | ``` 57 | 58 | { 59 | "data": [ 60 | { 61 | "duration": "All time", 62 | "problemData": [ 63 | { 64 | "acceptance": "73.6%", 65 | "difficulty": "Medium", 66 | "frequency": 0, 67 | "problemId": "2020", 68 | "problemName": "Number of Accounts That Did Not Stream", 69 | "url": "https://leetcode.com/problems/number-of-accounts-that-did-not-stream" 70 | } 71 | ] 72 | }, 73 | { 74 | "duration": "All time", 75 | "problemData": [ 76 | { 77 | "acceptance": "52.0%", 78 | "difficulty": "Medium", 79 | "frequency": 0, 80 | "problemId": "1990", 81 | "problemName": "Count the Number of Experiments", 82 | "url": "https://leetcode.com/problems/count-the-number-of-experiments" 83 | } 84 | ] 85 | }, 86 | { 87 | "duration": "All time", 88 | "problemData": [ 89 | { 90 | "acceptance": "72.7%", 91 | "difficulty": "Medium", 92 | "frequency": 0, 93 | "problemId": "1951", 94 | "problemName": "All the Pairs With the Maximum Number of Common Followers", 95 | "url": "https://leetcode.com/problems/all-the-pairs-with-the-maximum-number-of-common-followers" 96 | } 97 | ] 98 | } 99 | ], 100 | "companyName": [ 101 | "instagram" 102 | ] 103 | } 104 | 105 | ``` 106 | 107 | 108 |

    Front page

    109 | 110 | ``` 111 | { 112 | "tableData": [ 113 | { 114 | "isPremium": false, 115 | "problemName": "2551. Put Marbles in Bags", 116 | "haveSolution": false, 117 | "isVideoSolution": false, 118 | "acceptance": "51.5%", 119 | "difficulty": "Hard", 120 | "frequency": "10.7001%", 121 | "url": "https://leetcode.com/problems/put-marbles-in-bags/" 122 | }, 123 | { 124 | "isPremium": false, 125 | "problemName": "2552. Count Increasing Quadruplets", 126 | "haveSolution": false, 127 | "isVideoSolution": false, 128 | "acceptance": "31.5%", 129 | "difficulty": "Hard", 130 | "frequency": "7.09464%", 131 | "url": "https://leetcode.com/problems/count-increasing-quadruplets/" 132 | }, 133 | { 134 | "isPremium": false, 135 | "problemName": "2553. Separate the Digits in an Array", 136 | "haveSolution": false, 137 | "isVideoSolution": false, 138 | "acceptance": "78.1%", 139 | "difficulty": "Easy", 140 | "frequency": "0%", 141 | "url": "https://leetcode.com/problems/separate-the-digits-in-an-array/" 142 | }, 143 | { 144 | "isPremium": false, 145 | "problemName": "2554. Maximum Number of Integers to Choose From a Range I", 146 | "haveSolution": false, 147 | "isVideoSolution": false, 148 | "acceptance": "50.3%", 149 | "difficulty": "Medium", 150 | "frequency": "0%", 151 | "url": "https://leetcode.com/problems/maximum-number-of-integers-to-choose-from-a-range-i/" 152 | }, 153 | { 154 | "isPremium": false, 155 | "problemName": "2555. Maximize Win From Two Segments", 156 | "haveSolution": false, 157 | "isVideoSolution": false, 158 | "acceptance": "22.8%", 159 | "difficulty": "Medium", 160 | "frequency": "0.166546%", 161 | "url": "https://leetcode.com/problems/maximize-win-from-two-segments/" 162 | }, 163 | { 164 | "isPremium": false, 165 | "problemName": "2556. Disconnect Path in a Binary Matrix by at Most One Flip", 166 | "haveSolution": false, 167 | "isVideoSolution": false, 168 | "acceptance": "21.5%", 169 | "difficulty": "Medium", 170 | "frequency": "0%", 171 | "url": "https://leetcode.com/problems/disconnect-path-in-a-binary-matrix-by-at-most-one-flip/" 172 | }, 173 | { 174 | "isPremium": false, 175 | "problemName": "2557. Maximum Number of Integers to Choose From a Range II", 176 | "haveSolution": false, 177 | "isVideoSolution": false, 178 | "acceptance": "49.4%", 179 | "difficulty": "Medium", 180 | "frequency": "0%", 181 | "url": "https://leetcode.com/problems/maximum-number-of-integers-to-choose-from-a-range-ii/" 182 | }, 183 | { 184 | "isPremium": false, 185 | "problemName": "2558. Take Gifts From the Richest Pile", 186 | "haveSolution": false, 187 | "isVideoSolution": false, 188 | "acceptance": "63.6%", 189 | "difficulty": "Easy", 190 | "frequency": "0%", 191 | "url": "https://leetcode.com/problems/take-gifts-from-the-richest-pile/" 192 | }, 193 | { 194 | "isPremium": false, 195 | "problemName": "2559. Count Vowel Strings in Ranges", 196 | "haveSolution": false, 197 | "isVideoSolution": false, 198 | "acceptance": "47.9%", 199 | "difficulty": "Medium", 200 | "frequency": "0%", 201 | "url": "https://leetcode.com/problems/count-vowel-strings-in-ranges/" 202 | }, 203 | { 204 | "isPremium": false, 205 | "problemName": "2560. House Robber IV", 206 | "haveSolution": false, 207 | "isVideoSolution": false, 208 | "acceptance": "27.1%", 209 | "difficulty": "Medium", 210 | "frequency": "0%", 211 | "url": "https://leetcode.com/problems/house-robber-iv/" 212 | }, 213 | { 214 | "isPremium": false, 215 | "problemName": "2561. Rearranging Fruits", 216 | "haveSolution": false, 217 | "isVideoSolution": false, 218 | "acceptance": "25.6%", 219 | "difficulty": "Hard", 220 | "frequency": "0%", 221 | "url": "https://leetcode.com/problems/rearranging-fruits/" 222 | } 223 | ], 224 | "page": "52" 225 | } 226 | 227 | ``` 228 | 229 | 230 |

    Problem page

    231 | 232 | ``` 233 | { 234 | "tags": [ 235 | { 236 | "duration": "1 year - 2 years", 237 | "companies": [ 238 | [ 239 | "1 year - 2 years", 240 | "Amazon" 241 | ] 242 | ] 243 | } 244 | ], 245 | "problem": "

    You are given a 0-indexed integer array nums and a positive integer k.

    \n\n

    We call an index i k-big if the following conditions are satisfied:

    \n\n\n\n

    Return the number of k-big indices.

    \n\n

     

    \n

    Example 1:

    \n\n
    Input: nums = [2,3,6,5,2,3], k = 2\nOutput: 2\nExplanation: There are only two 2-big indices in nums:\n- i = 2 --> There are two valid idx1: 0 and 1. There are three valid idx2: 2, 3, and 4.\n- i = 3 --> There are two valid idx1: 0 and 1. There are two valid idx2: 3 and 4.\n
    \n\n

    Example 2:

    \n\n
    Input: nums = [1,1,1], k = 3\nOutput: 0\nExplanation: There are no 3-big indices in nums.\n
    \n\n

     

    \n

    Constraints:

    \n\n\n", 246 | "relatedTopics": [ 247 | "Array", 248 | "Binary Search", 249 | "Divide and Conquer", 250 | "Binary Indexed Tree", 251 | "Segment Tree", 252 | "Merge Sort", 253 | "Ordered Set" 254 | ], 255 | "similarQuestions": [ 256 | { 257 | "questionName": "Count of Smaller Numbers After Self", 258 | "difficulty": "Hard" 259 | }, 260 | { 261 | "questionName": "Find All Good Indices", 262 | "difficulty": "Medium" 263 | } 264 | ], 265 | "problemName": "count-the-number-of-k-big-indices" 266 | } 267 | ``` 268 | 269 |

    Contributions

    270 | If you have premium account and want to 'donate' data, feel free to open merge request (remember to force add the output folder, it is git-ignored by default). 271 | 272 | 273 | -------------------------------------------------------------------------------- /driver/chromedriver.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Edwardsoen/LeetcodeScrapper/39b40dd4ac2030b7a818559d9940c7a5206dce3b/driver/chromedriver.exe -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | from DriverNavigator import DriverNavigator 3 | from selenium import webdriver 4 | from PageHandler.CompanyProblemPageHandler import CompanyProblemPageHandler 5 | from PageHandler.MainTableHandler import MainTableHandler 6 | from PageHandler.LoginPageHandler import LoginPageHandler 7 | from PageHandler.ProblemPageHandler import ProblemPageHandler 8 | from PageHandler.StudyPlanPageHandler import StudyPlanPageHandler 9 | import sys 10 | from selenium.webdriver.chrome.options import Options 11 | from urllib.parse import urlparse 12 | 13 | def read_from_file(path, target_stack): 14 | with open(path, "r") as f: 15 | for i in f.readlines(): 16 | target_stack.append(i) 17 | 18 | def get_driver(): 19 | user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/60.0.3112.50 Safari/537.36" 20 | options = Options() 21 | options.add_argument(f'user-agent={user_agent}') 22 | # options.headless = True 23 | driver = webdriver.Chrome(options= options) 24 | return driver 25 | 26 | def run_scrapper(stack, username = "" , password = "", require_login = False): 27 | driver = get_driver() 28 | navigator = DriverNavigator(driver=driver, stack = stack, require_login = require_login) 29 | navigator.add_url_handlers("https://leetcode.com/problemset/all/", MainTableHandler(driver)) 30 | navigator.add_url_handlers("https://leetcode.com/problem-list/", MainTableHandler(driver)) 31 | navigator.add_url_handlers("https://leetcode.com/company/", CompanyProblemPageHandler(driver)) 32 | navigator.add_url_handlers("https://leetcode.com/accounts/login/", LoginPageHandler(driver, username , password)) 33 | navigator.add_url_handlers("https://leetcode.com/subscribe/", LoginPageHandler(driver, username , password)) 34 | navigator.add_url_handlers("https://leetcode.com/problems/",ProblemPageHandler(driver)) 35 | navigator.add_url_handlers("https://leetcode.com/studyplan/",StudyPlanPageHandler(driver)) 36 | input() 37 | navigator.run() 38 | 39 | if __name__ == "__main__": 40 | stack = [] 41 | parser = argparse.ArgumentParser() 42 | parser.add_argument("-u", "--username") 43 | parser.add_argument("-p", "--password") 44 | parser.add_argument("run", nargs= '*') 45 | args = parser.parse_args() 46 | 47 | if args.username == None and args.password != None or args.username != None and args.password == None : 48 | print('Username or password missing') 49 | sys.exit() 50 | 51 | for i in args.run: 52 | if ".txt" in i: 53 | read_from_file(i, stack) 54 | else: 55 | stack.append(i) 56 | 57 | credential_is_passed = (args.username != None) 58 | print("Running Scrapper") 59 | run_scrapper(stack= stack, username=args.username, password= args.password, require_login = credential_is_passed) 60 | 61 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | selenium==4.8.0 2 | -------------------------------------------------------------------------------- /urls/companyUrls.txt: -------------------------------------------------------------------------------- 1 | https://leetcode.com/company/amazon 2 | https://leetcode.com/company/google 3 | https://leetcode.com/company/microsoft 4 | https://leetcode.com/company/facebook 5 | https://leetcode.com/company/apple 6 | https://leetcode.com/company/bloomberg 7 | https://leetcode.com/company/adobe 8 | https://leetcode.com/company/uber 9 | https://leetcode.com/company/oracle 10 | https://leetcode.com/company/goldman-sachs 11 | https://leetcode.com/company/tiktok 12 | https://leetcode.com/company/bytedance 13 | https://leetcode.com/company/yahoo 14 | https://leetcode.com/company/linkedin 15 | https://leetcode.com/company/salesforce 16 | https://leetcode.com/company/snapchat 17 | https://leetcode.com/company/walmart-labs 18 | https://leetcode.com/company/vmware 19 | https://leetcode.com/company/ebay 20 | https://leetcode.com/company/twitter 21 | https://leetcode.com/company/expedia 22 | https://leetcode.com/company/paypal 23 | https://leetcode.com/company/cisco 24 | https://leetcode.com/company/doordash 25 | https://leetcode.com/company/yandex 26 | https://leetcode.com/company/intuit 27 | https://leetcode.com/company/jpmorgan 28 | https://leetcode.com/company/qualtrics 29 | https://leetcode.com/company/samsung 30 | https://leetcode.com/company/nvidia 31 | https://leetcode.com/company/visa 32 | https://leetcode.com/company/airbnb 33 | https://leetcode.com/company/infosys 34 | https://leetcode.com/company/citadel 35 | https://leetcode.com/company/flipkart 36 | https://leetcode.com/company/de-shaw 37 | https://leetcode.com/company/tcs 38 | https://leetcode.com/company/morgan-stanley 39 | https://leetcode.com/company/tesla 40 | https://leetcode.com/company/servicenow 41 | https://leetcode.com/company/zillow 42 | https://leetcode.com/company/square 43 | https://leetcode.com/company/wix 44 | https://leetcode.com/company/ibm 45 | https://leetcode.com/company/wayfair 46 | https://leetcode.com/company/intel 47 | https://leetcode.com/company/nutanix 48 | https://leetcode.com/company/qualcomm 49 | https://leetcode.com/company/splunk 50 | https://leetcode.com/company/atlassian 51 | https://leetcode.com/company/spotify 52 | https://leetcode.com/company/indeed 53 | https://leetcode.com/company/pinterest 54 | https://leetcode.com/company/arcesium 55 | https://leetcode.com/company/lyft 56 | https://leetcode.com/company/paytm 57 | https://leetcode.com/company/grab 58 | https://leetcode.com/company/twilio 59 | https://leetcode.com/company/wish 60 | https://leetcode.com/company/mathworks 61 | https://leetcode.com/company/yelp 62 | https://leetcode.com/company/capital-one 63 | https://leetcode.com/company/shopee 64 | https://leetcode.com/company/sap 65 | https://leetcode.com/company/twitch 66 | https://leetcode.com/company/american-express 67 | https://leetcode.com/company/rubrik 68 | https://leetcode.com/company/quora 69 | https://leetcode.com/company/roblox 70 | https://leetcode.com/company/palantir-technologies 71 | https://leetcode.com/company/zoho 72 | https://leetcode.com/company/dropbox 73 | https://leetcode.com/company/docusign 74 | https://leetcode.com/company/akuna-capital 75 | https://leetcode.com/company/hrt 76 | https://leetcode.com/company/zenefits 77 | https://leetcode.com/company/cruise-automation 78 | https://leetcode.com/company/sprinklr 79 | https://leetcode.com/company/medianet 80 | https://leetcode.com/company/swiggy 81 | https://leetcode.com/company/karat 82 | https://leetcode.com/company/phonepe 83 | https://leetcode.com/company/coupang 84 | https://leetcode.com/company/dunzo 85 | https://leetcode.com/company/makemytrip 86 | https://leetcode.com/company/c3-iot 87 | https://leetcode.com/company/databricks 88 | https://leetcode.com/company/zoom 89 | https://leetcode.com/company/bookingcom 90 | https://leetcode.com/company/tusimple 91 | https://leetcode.com/company/pocket-gems 92 | https://leetcode.com/company/reddit 93 | https://leetcode.com/company/two-sigma 94 | https://leetcode.com/company/nagarro 95 | https://leetcode.com/company/hbo 96 | https://leetcode.com/company/arista-networks 97 | https://leetcode.com/company/godaddy 98 | https://leetcode.com/company/accolite 99 | https://leetcode.com/company/accenture 100 | https://leetcode.com/company/robinhood 101 | https://leetcode.com/company/blackrock 102 | https://leetcode.com/company/netflix 103 | https://leetcode.com/company/hotstar 104 | https://leetcode.com/company/coinbase 105 | https://leetcode.com/company/audible 106 | https://leetcode.com/company/bolt 107 | https://leetcode.com/company/factset 108 | https://leetcode.com/company/epam-systems 109 | https://leetcode.com/company/sharechat 110 | https://leetcode.com/company/coursera 111 | https://leetcode.com/company/ixl 112 | https://leetcode.com/company/mindtickle 113 | https://leetcode.com/company/citrix 114 | https://leetcode.com/company/huawei 115 | https://leetcode.com/company/instacart 116 | https://leetcode.com/company/baidu 117 | https://leetcode.com/company/directi 118 | https://leetcode.com/company/deutsche-bank 119 | https://leetcode.com/company/dell 120 | https://leetcode.com/company/cognizant 121 | https://leetcode.com/company/codenation 122 | https://leetcode.com/company/sumologic 123 | https://leetcode.com/company/affirm 124 | https://leetcode.com/company/hulu 125 | https://leetcode.com/company/mckinsey 126 | https://leetcode.com/company/epic-systems 127 | https://leetcode.com/company/cohesity 128 | https://leetcode.com/company/hudson-river-trading 129 | https://leetcode.com/company/liveramp 130 | https://leetcode.com/company/virtu 131 | https://leetcode.com/company/myntra 132 | https://leetcode.com/company/ponyai 133 | https://leetcode.com/company/jane-street 134 | https://leetcode.com/company/zscaler 135 | https://leetcode.com/company/capgemini 136 | https://leetcode.com/company/mercari 137 | https://leetcode.com/company/redfin 138 | https://leetcode.com/company/duolingo 139 | https://leetcode.com/company/zynga 140 | https://leetcode.com/company/houzz 141 | https://leetcode.com/company/cloudera 142 | https://leetcode.com/company/groupon 143 | https://leetcode.com/company/drw 144 | https://leetcode.com/company/optum 145 | https://leetcode.com/company/zomato 146 | https://leetcode.com/company/alibaba 147 | https://leetcode.com/company/razorpay 148 | https://leetcode.com/company/toptal 149 | https://leetcode.com/company/asana 150 | https://leetcode.com/company/poshmark 151 | https://leetcode.com/company/tableau 152 | https://leetcode.com/company/juspay 153 | https://leetcode.com/company/opendoor 154 | https://leetcode.com/company/epifi 155 | https://leetcode.com/company/gsn-games 156 | https://leetcode.com/company/point72 157 | https://leetcode.com/company/akamai 158 | https://leetcode.com/company/alation 159 | https://leetcode.com/company/tencent 160 | https://leetcode.com/company/works-applications 161 | https://leetcode.com/company/dataminr 162 | https://leetcode.com/company/payu 163 | https://leetcode.com/company/athenahealth 164 | https://leetcode.com/company/clari 165 | https://leetcode.com/company/riot-games 166 | https://leetcode.com/company/box 167 | https://leetcode.com/company/appdynamics 168 | https://leetcode.com/company/deloitte 169 | https://leetcode.com/company/pure-storage 170 | https://leetcode.com/company/inmobi 171 | https://leetcode.com/company/united-health-group 172 | https://leetcode.com/company/siemens 173 | https://leetcode.com/company/airtel 174 | https://leetcode.com/company/persistent-systems 175 | https://leetcode.com/company/barclays 176 | https://leetcode.com/company/jump-trading 177 | https://leetcode.com/company/snapdeal 178 | https://leetcode.com/company/trilogy 179 | https://leetcode.com/company/commvault 180 | https://leetcode.com/company/didi 181 | https://leetcode.com/company/paypay 182 | https://leetcode.com/company/lucid 183 | https://leetcode.com/company/activision 184 | https://leetcode.com/company/quip 185 | https://leetcode.com/company/postmates 186 | https://leetcode.com/company/info-edge 187 | https://leetcode.com/company/softwire 188 | https://leetcode.com/company/zopsmart 189 | https://leetcode.com/company/societe-generale 190 | https://leetcode.com/company/tripadvisor 191 | https://leetcode.com/company/mindtree 192 | https://leetcode.com/company/lending-club 193 | https://leetcode.com/company/national-instruments 194 | https://leetcode.com/company/sapient 195 | https://leetcode.com/company/tiger-analytics 196 | https://leetcode.com/company/avalara 197 | https://leetcode.com/company/aqr-capital-management-llc 198 | https://leetcode.com/company/maq-software 199 | https://leetcode.com/company/canonical 200 | https://leetcode.com/company/cashfree 201 | https://leetcode.com/company/stripe 202 | https://leetcode.com/company/garena 203 | https://leetcode.com/company/netease 204 | https://leetcode.com/company/helix 205 | https://leetcode.com/company/machine-zone 206 | https://leetcode.com/company/honeywell 207 | https://leetcode.com/company/fleetx 208 | https://leetcode.com/company/wayve 209 | https://leetcode.com/company/kakao 210 | https://leetcode.com/company/veritas 211 | https://leetcode.com/company/soundhound 212 | https://leetcode.com/company/netsuite 213 | https://leetcode.com/company/thomson-reuters 214 | https://leetcode.com/company/lowe 215 | https://leetcode.com/company/analytics-quotient 216 | https://leetcode.com/company/electronic-arts 217 | https://leetcode.com/company/blizzard 218 | https://leetcode.com/company/aetion 219 | https://leetcode.com/company/rackspace 220 | https://leetcode.com/company/fallible 221 | https://leetcode.com/company/zappos 222 | https://leetcode.com/company/gilt-groupe 223 | https://leetcode.com/company/valve 224 | https://leetcode.com/company/poynt 225 | https://leetcode.com/company/ge-digital 226 | https://leetcode.com/company/triplebyte 227 | https://leetcode.com/company/yatra 228 | https://leetcode.com/company/radius 229 | https://leetcode.com/company/drawbridge 230 | https://leetcode.com/company/jingchi 231 | https://leetcode.com/company/forusall 232 | https://leetcode.com/company/iit-bombay 233 | https://leetcode.com/company/leap-motion 234 | https://leetcode.com/company/affinity 235 | https://leetcode.com/company/nextjump 236 | https://leetcode.com/company/edabit 237 | https://leetcode.com/company/allincall 238 | https://leetcode.com/company/general-electric 239 | https://leetcode.com/company/vimeo 240 | https://leetcode.com/company/codeagon 241 | https://leetcode.com/company/mobisy 242 | https://leetcode.com/company/quince 243 | https://leetcode.com/company/moengage 244 | https://leetcode.com/company/alphonso 245 | https://leetcode.com/company/xing 246 | https://leetcode.com/company/ge-healthcare 247 | https://leetcode.com/company/code-studio 248 | https://leetcode.com/company/tiaa 249 | https://leetcode.com/company/ascend 250 | https://leetcode.com/company/t-system 251 | https://leetcode.com/company/sony 252 | https://leetcode.com/company/jeavio 253 | https://leetcode.com/company/bitgo 254 | https://leetcode.com/company/mishipay 255 | https://leetcode.com/company/retailmenot 256 | https://leetcode.com/company/zeta-suite 257 | https://leetcode.com/company/fpt 258 | https://leetcode.com/company/t-mobiles 259 | https://leetcode.com/company/wealthfront 260 | https://leetcode.com/company/pickrr 261 | https://leetcode.com/company/opentext 262 | https://leetcode.com/company/discord 263 | https://leetcode.com/company/altimetrik 264 | https://leetcode.com/company/dailyhunt 265 | https://leetcode.com/company/fourkites 266 | https://leetcode.com/company/bridgewater-associates 267 | https://leetcode.com/company/unbxd 268 | https://leetcode.com/company/zendesk 269 | https://leetcode.com/company/machinezone 270 | https://leetcode.com/company/coderbyte 271 | https://leetcode.com/company/instagram 272 | https://leetcode.com/company/strava 273 | https://leetcode.com/company/warnermedia 274 | -------------------------------------------------------------------------------- /urls/problemUrls.txt: -------------------------------------------------------------------------------- 1 | https://leetcode.com/problems/two-sum/ 2 | https://leetcode.com/problems/add-two-numbers/ 3 | https://leetcode.com/problems/longest-substring-without-repeating-characters/ 4 | https://leetcode.com/problems/median-of-two-sorted-arrays/ 5 | -------------------------------------------------------------------------------- /urls/problemsetUrls.txt: -------------------------------------------------------------------------------- 1 | https://leetcode.com/problemset/all/?page=1 2 | https://leetcode.com/problemset/all/?page=2 3 | https://leetcode.com/problemset/all/?page=3 4 | https://leetcode.com/problemset/all/?page=4 5 | https://leetcode.com/problemset/all/?page=5 6 | https://leetcode.com/problemset/all/?page=6 7 | https://leetcode.com/problemset/all/?page=7 8 | https://leetcode.com/problemset/all/?page=8 9 | https://leetcode.com/problemset/all/?page=9 10 | https://leetcode.com/problemset/all/?page=10 11 | https://leetcode.com/problemset/all/?page=11 12 | https://leetcode.com/problemset/all/?page=12 13 | https://leetcode.com/problemset/all/?page=13 14 | https://leetcode.com/problemset/all/?page=14 15 | https://leetcode.com/problemset/all/?page=15 16 | https://leetcode.com/problemset/all/?page=16 17 | https://leetcode.com/problemset/all/?page=17 18 | https://leetcode.com/problemset/all/?page=18 19 | https://leetcode.com/problemset/all/?page=19 20 | https://leetcode.com/problemset/all/?page=20 21 | https://leetcode.com/problemset/all/?page=21 22 | https://leetcode.com/problemset/all/?page=22 23 | https://leetcode.com/problemset/all/?page=23 24 | https://leetcode.com/problemset/all/?page=24 25 | https://leetcode.com/problemset/all/?page=25 26 | https://leetcode.com/problemset/all/?page=26 27 | https://leetcode.com/problemset/all/?page=27 28 | https://leetcode.com/problemset/all/?page=28 29 | https://leetcode.com/problemset/all/?page=29 30 | https://leetcode.com/problemset/all/?page=30 31 | https://leetcode.com/problemset/all/?page=31 32 | https://leetcode.com/problemset/all/?page=32 33 | https://leetcode.com/problemset/all/?page=33 34 | https://leetcode.com/problemset/all/?page=34 35 | https://leetcode.com/problemset/all/?page=35 36 | https://leetcode.com/problemset/all/?page=36 37 | https://leetcode.com/problemset/all/?page=37 38 | https://leetcode.com/problemset/all/?page=38 39 | https://leetcode.com/problemset/all/?page=39 40 | https://leetcode.com/problemset/all/?page=40 41 | https://leetcode.com/problemset/all/?page=41 42 | https://leetcode.com/problemset/all/?page=42 43 | https://leetcode.com/problemset/all/?page=43 44 | https://leetcode.com/problemset/all/?page=44 45 | https://leetcode.com/problemset/all/?page=45 46 | https://leetcode.com/problemset/all/?page=46 47 | https://leetcode.com/problemset/all/?page=47 48 | https://leetcode.com/problemset/all/?page=48 49 | https://leetcode.com/problemset/all/?page=49 50 | https://leetcode.com/problemset/all/?page=50 51 | https://leetcode.com/problemset/all/?page=51 52 | https://leetcode.com/problemset/all/?page=52 53 | https://leetcode.com/problemset/all/?page=53 54 | https://leetcode.com/problemset/all/?page=54 55 | https://leetcode.com/problemset/all/?page=55 56 | https://leetcode.com/problemset/all/?page=56 57 | --------------------------------------------------------------------------------