|
3 | 3 | from typing import List |
4 | 4 |
|
5 | 5 | from selenium import webdriver |
| 6 | +from selenium.common.exceptions import TimeoutException |
6 | 7 | from selenium.webdriver.common.by import By |
7 | 8 | from selenium.webdriver.support import expected_conditions as Expected |
8 | 9 | from selenium.webdriver.support.wait import WebDriverWait |
@@ -39,6 +40,19 @@ def get_cookie_path(username: str, site: str) -> str: |
39 | 40 | return os.path.join(COOKIE_FOLDER, f"{username}@{site}.dat") |
40 | 41 |
|
41 | 42 |
|
| 43 | +def check_login(browser, site: str, timeout: int = 10) -> bool: |
| 44 | + try: |
| 45 | + if site == "leetcode": |
| 46 | + WebDriverWait(browser, timeout).until( |
| 47 | + Expected.presence_of_element_located((By.CSS_SELECTOR, 'img.avatar'))) |
| 48 | + else: # site == "leetcode-cn" |
| 49 | + WebDriverWait(browser, timeout).until( |
| 50 | + Expected.presence_of_element_located((By.CSS_SELECTOR, 'span.ant-avatar'))) |
| 51 | + return True |
| 52 | + except TimeoutException: |
| 53 | + return False |
| 54 | + |
| 55 | + |
42 | 56 | def update_cookie(username: str, site: str) -> None: |
43 | 57 | r"""Update the cookie for the LeetCode user.""" |
44 | 58 | browser = webdriver.Chrome() |
@@ -69,12 +83,8 @@ def update_cookie(username: str, site: str) -> None: |
69 | 83 | # elem = browser.find_element_by_css_selector('button[data-cy="sign-in-btn"]') |
70 | 84 | # browser.execute_script("arguments[0].click();", elem) |
71 | 85 |
|
72 | | - if site == "leetcode": |
73 | | - WebDriverWait(browser, 120).until( |
74 | | - Expected.presence_of_element_located((By.CSS_SELECTOR, 'img.avatar'))) |
75 | | - else: # site == "leetcode-cn" |
76 | | - WebDriverWait(browser, 120).until( |
77 | | - Expected.presence_of_element_located((By.CSS_SELECTOR, 'span.ant-avatar'))) |
| 86 | + if not check_login(browser, site, timeout=120): |
| 87 | + raise RuntimeError("Login failed!") |
78 | 88 |
|
79 | 89 | cookies = browser.get_cookies() |
80 | 90 | jar = http.cookiejar.LWPCookieJar() |
@@ -127,23 +137,31 @@ def get_problems(contest_url: str, site: str, cookie_path: str) -> List[Problem] |
127 | 137 | cookie_jar.load(ignore_discard=True, ignore_expires=True) |
128 | 138 | for c in cookie_jar: |
129 | 139 | browser.add_cookie({"name": c.name, 'value': c.value, 'path': c.path}) |
| 140 | + browser.get(contest_url) # visit again to refresh page with cookies added |
| 141 | + |
| 142 | + if not check_login(browser, site, timeout=10): |
| 143 | + browser.quit() |
| 144 | + print(f"Cookie '{cookie_path}' might have expired. Please try logging in again") |
| 145 | + exit(1) |
130 | 146 |
|
131 | 147 | elem = browser.find_element_by_css_selector("ul.contest-question-list") |
132 | 148 | links = elem.find_elements_by_tag_name("a") |
133 | 149 | problem_paths = [(link.get_attribute("href"), link.text) for link in links] |
134 | 150 | log(f"Found problems: {[name for _, name in problem_paths]!r}") |
135 | 151 |
|
136 | | - if site == "leetcode": |
137 | | - statement_css_selector = "div.question-content" |
138 | | - code_css_selector = "pre.CodeMirror-line" |
139 | | - else: # site == "leetcode-cn" |
140 | | - statement_css_selector = "div[data-key='description-content'] div.content__1Y2H" |
141 | | - code_css_selector = "div.monaco-scrollable-element div.view-line" |
142 | | - |
143 | 152 | parsed_problems = [] |
144 | 153 | for idx, (problem_url, problem_name) in enumerate(problem_paths): |
145 | 154 | browser.get(problem_url) |
146 | | - statement = browser.find_element_by_css_selector(statement_css_selector).text |
| 155 | + try: |
| 156 | + # Page during contest; editor located below statement. |
| 157 | + statement_css_selector = "div.question-content" |
| 158 | + code_css_selector = "pre.CodeMirror-line" |
| 159 | + statement = browser.find_element_by_css_selector(statement_css_selector).text |
| 160 | + except TimeoutException: |
| 161 | + # Page after contest; statement and editor in vertically split panes. |
| 162 | + statement_css_selector = "div[data-key='description-content'] div.content__1Y2H" |
| 163 | + code_css_selector = "div.monaco-scrollable-element div.view-line" |
| 164 | + statement = browser.find_element_by_css_selector(statement_css_selector).text |
147 | 165 | examples = [ |
148 | 166 | elem.text for elem in browser.find_elements_by_css_selector("pre:not([class])") if elem.text] |
149 | 167 | code = [elem.text for elem in browser.find_elements_by_css_selector(code_css_selector)] |
|
0 commit comments