From f7559a12367233f1885d89b24e32650745f6ff0c Mon Sep 17 00:00:00 2001 From: narugo1992 Date: Thu, 15 Dec 2022 16:05:52 +0800 Subject: [PATCH 01/11] dev(feat): add proxy support --- gppt/_selenium.py | 98 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 79 insertions(+), 19 deletions(-) diff --git a/gppt/_selenium.py b/gppt/_selenium.py index d649cf3..0394e60 100644 --- a/gppt/_selenium.py +++ b/gppt/_selenium.py @@ -7,17 +7,19 @@ import json import re +import urllib.request from base64 import urlsafe_b64encode from hashlib import sha256 from random import uniform from secrets import token_urlsafe from time import sleep -from typing import Any, cast +from typing import Any, cast, Optional from urllib.parse import urlencode import pyderman import requests from selenium import webdriver +from selenium.common import NoSuchElementException from selenium.webdriver.common.by import By from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.keys import Keys @@ -42,6 +44,32 @@ } +def _get_system_proxy(proxy_type: str = 'https') -> Optional[str]: + """ + Load proxy from system, such as `export ALL_PROXY=xxxx` in ~/.bashrc. + """ + _sys_proxies = urllib.request.getproxies() + if 'all' in _sys_proxies: + return _sys_proxies['all'] + else: + return _sys_proxies.get(proxy_type, None) + + +def _get_proxy(proxy: Optional[str] = None, proxy_type: str = 'https') -> Optional[str]: + """ + If `proxy` is given, just use this one, otherwise load proxy from system. + """ + return proxy or _get_system_proxy(proxy_type) + + +def _get_proxies_for_requests(proxy: Optional[str] = None, proxy_type: str = 'https') -> Optional[dict]: + """ + Load proxy to dict-formatted proxies for `requests` module. + """ + _proxy = _get_proxy(proxy, proxy_type) + return {'all': _proxy} if _proxy else None + + class GetPixivToken: def __init__(self) -> None: @@ -55,23 +83,22 @@ def login( headless: bool | None = False, user: str | None = None, pass_: str | None = None, + proxy: str | None = None, ) -> LoginInfo: self.headless, self.user, self.pass_ = headless, user, pass_ executable_path = pyderman.install(verbose=False, browser=pyderman.chrome) if type(executable_path) is not str: raise ValueError("Executable path is not str somehow.") if headless is not None and headless: - opts = self.__get_headless_option() - self.driver = webdriver.Chrome( - executable_path=executable_path, - options=opts, - desired_capabilities=self.caps, - ) - + opts = self.__get_headless_option(proxy) else: - self.driver = webdriver.Chrome( - executable_path=executable_path, desired_capabilities=self.caps - ) + opts = self.__get_option(proxy) + + self.driver = webdriver.Chrome( + executable_path=executable_path, + options=opts, + desired_capabilities=self.caps + ) code_verifier, code_challenge = self.__oauth_pkce() login_params = { @@ -110,13 +137,14 @@ def login( "app-os-version": "14.6", "app-os": "ios", }, + proxies=_get_proxies_for_requests(proxy, 'https'), **REQUESTS_KWARGS, ) return cast(LoginInfo, response.json()) @staticmethod - def refresh(refresh_token: str) -> LoginInfo: + def refresh(refresh_token: str, proxy: Optional[str] = None) -> LoginInfo: response = requests.post( AUTH_TOKEN_URL, data={ @@ -131,6 +159,7 @@ def refresh(refresh_token: str) -> LoginInfo: "app-os-version": "14.6", "app-os": "ios", }, + proxies=_get_proxies_for_requests(proxy, 'https'), **REQUESTS_KWARGS, ) return cast(LoginInfo, response.json()) @@ -152,12 +181,28 @@ def __slow_type(elm: Any, text: str) -> None: elm.send_keys(character) sleep(uniform(0.3, 0.7)) + # For the users in different language areas, this text will be different, + # so using `Login` directly may cause `NoSuchElementException`. + # The code here may also need to be supplemented with versions in other languages. + __LOGIN_TEXTS__ = ['Login', '登录'] + def __try_login(self) -> None: if self.headless: - el = self.driver.find_element( - By.XPATH, "//button[@type='submit'][contains(text(), 'Login')]" - ) - el.send_keys(Keys.ENTER) + el, lerr = None, None + for login_text in self.__LOGIN_TEXTS__: + try: + el = self.driver.find_element( + By.XPATH, f"//button[@type='submit'][contains(text(), {login_text!r})]" + ) + except NoSuchElementException as err: + lerr = err + else: + break + + if el: + el.send_keys(Keys.ENTER) + else: + raise lerr WebDriverWait(self.driver, 60).until_not( EC.presence_of_element_located((By.CLASS_NAME, "busy-container")), @@ -176,7 +221,16 @@ def __try_login(self) -> None: ) @staticmethod - def __get_headless_option() -> webdriver.chrome.options.Options: + def __get_option(proxy: Optional[str] = None) -> webdriver.chrome.options.Options: + options = webdriver.ChromeOptions() + proxy = _get_proxy(proxy) + if proxy: + options.add_argument(f'--proxy-server={proxy}') + + return options + + @staticmethod + def __get_headless_option(proxy: Optional[str] = None) -> webdriver.chrome.options.Options: options = webdriver.ChromeOptions() options.add_argument("--headless") options.add_argument("--disable-gpu") @@ -184,12 +238,18 @@ def __get_headless_option() -> webdriver.chrome.options.Options: options.add_argument("--disable-infobars") options.add_argument("--disable-dev-shm-usage") options.add_argument("--disable-browser-side-navigation") - options.add_argument('--proxy-server="direct://"') - options.add_argument("--proxy-bypass-list=*") options.add_argument("--start-maximized") options.add_argument("--no-sandbox") options.add_argument("--disable-dev-shm-usage") options.add_argument("--user-agent=" + USER_AGENT) + + proxy = _get_proxy(proxy) + if proxy: + options.add_argument(f'--proxy-server={proxy}') + else: + options.add_argument('--proxy-server="direct://"') + options.add_argument("--proxy-bypass-list=*") + options.add_experimental_option("excludeSwitches", ["enable-automation"]) options.add_experimental_option("useAutomationExtension", False) return options From d7d4ca245dd6d6e63adcc535cd40ab31648ffe33 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 15 Dec 2022 08:16:59 +0000 Subject: [PATCH 02/11] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- gppt/_selenium.py | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/gppt/_selenium.py b/gppt/_selenium.py index 0394e60..098f1e8 100644 --- a/gppt/_selenium.py +++ b/gppt/_selenium.py @@ -13,7 +13,7 @@ from random import uniform from secrets import token_urlsafe from time import sleep -from typing import Any, cast, Optional +from typing import Any, Optional, cast from urllib.parse import urlencode import pyderman @@ -44,30 +44,32 @@ } -def _get_system_proxy(proxy_type: str = 'https') -> Optional[str]: +def _get_system_proxy(proxy_type: str = "https") -> str | None: """ Load proxy from system, such as `export ALL_PROXY=xxxx` in ~/.bashrc. """ _sys_proxies = urllib.request.getproxies() - if 'all' in _sys_proxies: - return _sys_proxies['all'] + if "all" in _sys_proxies: + return _sys_proxies["all"] else: return _sys_proxies.get(proxy_type, None) -def _get_proxy(proxy: Optional[str] = None, proxy_type: str = 'https') -> Optional[str]: +def _get_proxy(proxy: str | None = None, proxy_type: str = "https") -> str | None: """ If `proxy` is given, just use this one, otherwise load proxy from system. """ return proxy or _get_system_proxy(proxy_type) -def _get_proxies_for_requests(proxy: Optional[str] = None, proxy_type: str = 'https') -> Optional[dict]: +def _get_proxies_for_requests( + proxy: str | None = None, proxy_type: str = "https" +) -> dict | None: """ Load proxy to dict-formatted proxies for `requests` module. """ _proxy = _get_proxy(proxy, proxy_type) - return {'all': _proxy} if _proxy else None + return {"all": _proxy} if _proxy else None class GetPixivToken: @@ -97,7 +99,7 @@ def login( self.driver = webdriver.Chrome( executable_path=executable_path, options=opts, - desired_capabilities=self.caps + desired_capabilities=self.caps, ) code_verifier, code_challenge = self.__oauth_pkce() @@ -137,14 +139,14 @@ def login( "app-os-version": "14.6", "app-os": "ios", }, - proxies=_get_proxies_for_requests(proxy, 'https'), + proxies=_get_proxies_for_requests(proxy, "https"), **REQUESTS_KWARGS, ) return cast(LoginInfo, response.json()) @staticmethod - def refresh(refresh_token: str, proxy: Optional[str] = None) -> LoginInfo: + def refresh(refresh_token: str, proxy: str | None = None) -> LoginInfo: response = requests.post( AUTH_TOKEN_URL, data={ @@ -159,7 +161,7 @@ def refresh(refresh_token: str, proxy: Optional[str] = None) -> LoginInfo: "app-os-version": "14.6", "app-os": "ios", }, - proxies=_get_proxies_for_requests(proxy, 'https'), + proxies=_get_proxies_for_requests(proxy, "https"), **REQUESTS_KWARGS, ) return cast(LoginInfo, response.json()) @@ -184,7 +186,7 @@ def __slow_type(elm: Any, text: str) -> None: # For the users in different language areas, this text will be different, # so using `Login` directly may cause `NoSuchElementException`. # The code here may also need to be supplemented with versions in other languages. - __LOGIN_TEXTS__ = ['Login', '登录'] + __LOGIN_TEXTS__ = ["Login", "登录"] def __try_login(self) -> None: if self.headless: @@ -192,7 +194,8 @@ def __try_login(self) -> None: for login_text in self.__LOGIN_TEXTS__: try: el = self.driver.find_element( - By.XPATH, f"//button[@type='submit'][contains(text(), {login_text!r})]" + By.XPATH, + f"//button[@type='submit'][contains(text(), {login_text!r})]", ) except NoSuchElementException as err: lerr = err @@ -221,16 +224,18 @@ def __try_login(self) -> None: ) @staticmethod - def __get_option(proxy: Optional[str] = None) -> webdriver.chrome.options.Options: + def __get_option(proxy: str | None = None) -> webdriver.chrome.options.Options: options = webdriver.ChromeOptions() proxy = _get_proxy(proxy) if proxy: - options.add_argument(f'--proxy-server={proxy}') + options.add_argument(f"--proxy-server={proxy}") return options @staticmethod - def __get_headless_option(proxy: Optional[str] = None) -> webdriver.chrome.options.Options: + def __get_headless_option( + proxy: str | None = None, + ) -> webdriver.chrome.options.Options: options = webdriver.ChromeOptions() options.add_argument("--headless") options.add_argument("--disable-gpu") @@ -245,7 +250,7 @@ def __get_headless_option(proxy: Optional[str] = None) -> webdriver.chrome.optio proxy = _get_proxy(proxy) if proxy: - options.add_argument(f'--proxy-server={proxy}') + options.add_argument(f"--proxy-server={proxy}") else: options.add_argument('--proxy-server="direct://"') options.add_argument("--proxy-bypass-list=*") From b57d5c92a672d3198f0a77829f36c30669cf194c Mon Sep 17 00:00:00 2001 From: narugo1992 Date: Thu, 15 Dec 2022 16:39:03 +0800 Subject: [PATCH 03/11] dev(style): try fix the style problem --- gppt/_selenium.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gppt/_selenium.py b/gppt/_selenium.py index 098f1e8..8c5daa2 100644 --- a/gppt/_selenium.py +++ b/gppt/_selenium.py @@ -13,13 +13,13 @@ from random import uniform from secrets import token_urlsafe from time import sleep -from typing import Any, Optional, cast +from typing import Any, cast from urllib.parse import urlencode import pyderman import requests from selenium import webdriver -from selenium.common import NoSuchElementException +from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.by import By from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.keys import Keys @@ -64,7 +64,7 @@ def _get_proxy(proxy: str | None = None, proxy_type: str = "https") -> str | Non def _get_proxies_for_requests( proxy: str | None = None, proxy_type: str = "https" -) -> dict | None: +): """ Load proxy to dict-formatted proxies for `requests` module. """ @@ -202,10 +202,10 @@ def __try_login(self) -> None: else: break - if el: - el.send_keys(Keys.ENTER) - else: + if isinstance(lerr, NoSuchElementException): raise lerr + else: + el.send_keys(Keys.ENTER) WebDriverWait(self.driver, 60).until_not( EC.presence_of_element_located((By.CLASS_NAME, "busy-container")), From 4df65d518b5f5c138d3efa9f990131151ff053a7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 15 Dec 2022 08:39:18 +0000 Subject: [PATCH 04/11] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- gppt/_selenium.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gppt/_selenium.py b/gppt/_selenium.py index 8c5daa2..13fa96e 100644 --- a/gppt/_selenium.py +++ b/gppt/_selenium.py @@ -62,9 +62,7 @@ def _get_proxy(proxy: str | None = None, proxy_type: str = "https") -> str | Non return proxy or _get_system_proxy(proxy_type) -def _get_proxies_for_requests( - proxy: str | None = None, proxy_type: str = "https" -): +def _get_proxies_for_requests(proxy: str | None = None, proxy_type: str = "https"): """ Load proxy to dict-formatted proxies for `requests` module. """ From 5b3add6d9950623c2847695a7103ce1b9b494a44 Mon Sep 17 00:00:00 2001 From: narugo1992 Date: Thu, 15 Dec 2022 16:42:49 +0800 Subject: [PATCH 05/11] dev(style): try fix the style problem --- gppt/_selenium.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/gppt/_selenium.py b/gppt/_selenium.py index 13fa96e..b40b8cd 100644 --- a/gppt/_selenium.py +++ b/gppt/_selenium.py @@ -23,6 +23,7 @@ from selenium.webdriver.common.by import By from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.keys import Keys +from selenium.webdriver.remote.webelement import WebElement from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait @@ -62,7 +63,7 @@ def _get_proxy(proxy: str | None = None, proxy_type: str = "https") -> str | Non return proxy or _get_system_proxy(proxy_type) -def _get_proxies_for_requests(proxy: str | None = None, proxy_type: str = "https"): +def _get_proxies_for_requests(proxy: str | None = None, proxy_type: str = "https") -> dict[str, str] | None: """ Load proxy to dict-formatted proxies for `requests` module. """ @@ -202,8 +203,10 @@ def __try_login(self) -> None: if isinstance(lerr, NoSuchElementException): raise lerr - else: + elif isinstance(el, WebElement): el.send_keys(Keys.ENTER) + else: + assert False, 'Should not reach here!' WebDriverWait(self.driver, 60).until_not( EC.presence_of_element_located((By.CLASS_NAME, "busy-container")), From c306f706abce99eaf87c0b0b92ab3a366f4d227a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 15 Dec 2022 08:43:39 +0000 Subject: [PATCH 06/11] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- gppt/_selenium.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gppt/_selenium.py b/gppt/_selenium.py index b40b8cd..64361db 100644 --- a/gppt/_selenium.py +++ b/gppt/_selenium.py @@ -63,7 +63,9 @@ def _get_proxy(proxy: str | None = None, proxy_type: str = "https") -> str | Non return proxy or _get_system_proxy(proxy_type) -def _get_proxies_for_requests(proxy: str | None = None, proxy_type: str = "https") -> dict[str, str] | None: +def _get_proxies_for_requests( + proxy: str | None = None, proxy_type: str = "https" +) -> dict[str, str] | None: """ Load proxy to dict-formatted proxies for `requests` module. """ @@ -206,7 +208,7 @@ def __try_login(self) -> None: elif isinstance(el, WebElement): el.send_keys(Keys.ENTER) else: - assert False, 'Should not reach here!' + assert False, "Should not reach here!" WebDriverWait(self.driver, 60).until_not( EC.presence_of_element_located((By.CLASS_NAME, "busy-container")), From c02166e30765357d8a99808972798ba393f2636a Mon Sep 17 00:00:00 2001 From: narugo1992 Date: Thu, 15 Dec 2022 16:44:26 +0800 Subject: [PATCH 07/11] dev(style): try fix the style problem --- gppt/_selenium.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gppt/_selenium.py b/gppt/_selenium.py index b40b8cd..77c6c30 100644 --- a/gppt/_selenium.py +++ b/gppt/_selenium.py @@ -201,10 +201,10 @@ def __try_login(self) -> None: else: break - if isinstance(lerr, NoSuchElementException): - raise lerr - elif isinstance(el, WebElement): + if isinstance(el, WebElement): el.send_keys(Keys.ENTER) + elif isinstance(lerr, NoSuchElementException): + raise lerr else: assert False, 'Should not reach here!' From c0aaab898050c24db3de978dda1505d2af0f42af Mon Sep 17 00:00:00 2001 From: eggplants Date: Fri, 23 Dec 2022 00:31:18 +0900 Subject: [PATCH 08/11] refactor and change pass_ -> password, user -> username --- gppt/__init__.py | 2 - gppt/_selenium.py | 176 +++++++++++++--------------------------------- gppt/auth.py | 4 +- gppt/main.py | 4 +- 4 files changed, 54 insertions(+), 132 deletions(-) diff --git a/gppt/__init__.py b/gppt/__init__.py index d983876..bf5a326 100644 --- a/gppt/__init__.py +++ b/gppt/__init__.py @@ -5,7 +5,6 @@ CLIENT_SECRET, LOGIN_URL, REDIRECT_URI, - REQUESTS_KWARGS, USER_AGENT, GetPixivToken, ) @@ -36,7 +35,6 @@ "CLIENT_SECRET", "LOGIN_URL", "REDIRECT_URI", - "REQUESTS_KWARGS", "USER_AGENT", "GetPixivToken", ] diff --git a/gppt/_selenium.py b/gppt/_selenium.py index 532c1be..92e2e37 100644 --- a/gppt/_selenium.py +++ b/gppt/_selenium.py @@ -7,7 +7,6 @@ import json import re -import urllib.request from base64 import urlsafe_b64encode from hashlib import sha256 from random import uniform @@ -15,15 +14,14 @@ from time import sleep from typing import Any, cast from urllib.parse import urlencode +from urllib.request import getproxies import pyderman import requests from selenium import webdriver -from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.by import By from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.keys import Keys -from selenium.webdriver.remote.webelement import WebElement from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait @@ -37,45 +35,13 @@ AUTH_TOKEN_URL = "https://oauth.secure.pixiv.net/auth/token" CLIENT_ID = "MOBrBDS8blbauoSck0ZfDbtuzpyT" CLIENT_SECRET = "lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj" -REQUESTS_KWARGS: dict[str, Any] = { - # 'proxies': { - # 'https': 'http://127.0.0.1:1087', - # }, - # 'verify': False -} - - -def _get_system_proxy(proxy_type: str = "https") -> str | None: - """ - Load proxy from system, such as `export ALL_PROXY=xxxx` in ~/.bashrc. - """ - _sys_proxies = urllib.request.getproxies() - if "all" in _sys_proxies: - return _sys_proxies["all"] - else: - return _sys_proxies.get(proxy_type, None) - - -def _get_proxy(proxy: str | None = None, proxy_type: str = "https") -> str | None: - """ - If `proxy` is given, just use this one, otherwise load proxy from system. - """ - return proxy or _get_system_proxy(proxy_type) - - -def _get_proxies_for_requests( - proxy: str | None = None, proxy_type: str = "https" -) -> dict[str, str] | None: - """ - Load proxy to dict-formatted proxies for `requests` module. - """ - _proxy = _get_proxy(proxy, proxy_type) - return {"all": _proxy} if _proxy else None +PROXIES = getproxies() + +OptionsType = webdriver.chrome.options.Options class GetPixivToken: def __init__(self) -> None: - self.caps = DesiredCapabilities.CHROME.copy() self.caps["goog:loggingPrefs"] = { "performance": "ALL" @@ -84,22 +50,20 @@ def __init__(self) -> None: def login( self, headless: bool | None = False, - user: str | None = None, - pass_: str | None = None, - proxy: str | None = None, + username: str | None = None, + password: str | None = None, ) -> LoginInfo: - self.headless, self.user, self.pass_ = headless, user, pass_ + self.headless = headless + self.username = username + self.password = password + executable_path = pyderman.install(verbose=False, browser=pyderman.chrome) if type(executable_path) is not str: raise ValueError("Executable path is not str somehow.") - if headless is not None and headless: - opts = self.__get_headless_option(proxy) - else: - opts = self.__get_option(proxy) self.driver = webdriver.Chrome( executable_path=executable_path, - options=opts, + options=self.__get_chrome_option(headless), desired_capabilities=self.caps, ) @@ -140,14 +104,13 @@ def login( "app-os-version": "14.6", "app-os": "ios", }, - proxies=_get_proxies_for_requests(proxy, "https"), - **REQUESTS_KWARGS, + proxies=PROXIES, ) return cast(LoginInfo, response.json()) @staticmethod - def refresh(refresh_token: str, proxy: str | None = None) -> LoginInfo: + def refresh(refresh_token: str) -> LoginInfo: response = requests.post( AUTH_TOKEN_URL, data={ @@ -162,21 +125,20 @@ def refresh(refresh_token: str, proxy: str | None = None) -> LoginInfo: "app-os-version": "14.6", "app-os": "ios", }, - proxies=_get_proxies_for_requests(proxy, "https"), - **REQUESTS_KWARGS, + proxies=PROXIES, ) return cast(LoginInfo, response.json()) def __fill_login_form(self) -> None: - if self.user is not None: + if self.username: el = self.driver.find_element(By.XPATH, "//input[@autocomplete='username']") - self.__slow_type(el, self.user) + self.__slow_type(el, self.username) - if self.pass_ is not None: + if self.password: el = self.driver.find_element( By.XPATH, "//input[@autocomplete='current-password']" ) - self.__slow_type(el, self.pass_) + self.__slow_type(el, self.password) @staticmethod def __slow_type(elm: Any, text: str) -> None: @@ -184,31 +146,16 @@ def __slow_type(elm: Any, text: str) -> None: elm.send_keys(character) sleep(uniform(0.3, 0.7)) - # For the users in different language areas, this text will be different, - # so using `Login` directly may cause `NoSuchElementException`. - # The code here may also need to be supplemented with versions in other languages. - __LOGIN_TEXTS__ = ["Login", "登录"] - def __try_login(self) -> None: if self.headless: - el, lerr = None, None - for login_text in self.__LOGIN_TEXTS__: - try: - el = self.driver.find_element( - By.XPATH, - f"//button[@type='submit'][contains(text(), {login_text!r})]", - ) - except NoSuchElementException as err: - lerr = err - else: - break - - if isinstance(el, WebElement): - el.send_keys(Keys.ENTER) - elif isinstance(lerr, NoSuchElementException): - raise lerr - else: - assert False, "Should not reach here!" + label_selectors = [ + f"contains(text(), '{label}')" + for label in ["ログイン", "Login", "登录", "로그인", "登入"] + ] + el = self.driver.find_element( + By.XPATH, f"//button[@type='submit'][{' or '.join(label_selectors)}]" + ) + el.send_keys(Keys.ENTER) WebDriverWait(self.driver, 60).until_not( EC.presence_of_element_located((By.CLASS_NAME, "busy-container")), @@ -227,39 +174,35 @@ def __try_login(self) -> None: ) @staticmethod - def __get_option(proxy: str | None = None) -> webdriver.chrome.options.Options: + def __get_chrome_option(headless: bool | None) -> OptionsType: options = webdriver.ChromeOptions() - proxy = _get_proxy(proxy) - if proxy: - options.add_argument(f"--proxy-server={proxy}") - return options - - @staticmethod - def __get_headless_option( - proxy: str | None = None, - ) -> webdriver.chrome.options.Options: - options = webdriver.ChromeOptions() - options.add_argument("--headless") - options.add_argument("--disable-gpu") - options.add_argument("--disable-extensions") - options.add_argument("--disable-infobars") - options.add_argument("--disable-dev-shm-usage") - options.add_argument("--disable-browser-side-navigation") - options.add_argument("--start-maximized") - options.add_argument("--no-sandbox") - options.add_argument("--disable-dev-shm-usage") - options.add_argument("--user-agent=" + USER_AGENT) - - proxy = _get_proxy(proxy) - if proxy: - options.add_argument(f"--proxy-server={proxy}") + if headless: + options.add_argument("--headless") + options.add_argument("--disable-gpu") + options.add_argument("--disable-extensions") + options.add_argument("--disable-infobars") + options.add_argument("--disable-dev-shm-usage") + options.add_argument("--disable-browser-side-navigation") + options.add_argument('--proxy-server="direct://"') + options.add_argument("--proxy-bypass-list=*") + options.add_argument("--start-maximized") + options.add_argument("--no-sandbox") + options.add_argument("--disable-dev-shm-usage") + options.add_argument("--user-agent=" + USER_AGENT) + options.add_experimental_option("excludeSwitches", ["enable-automation"]) + options.add_experimental_option("useAutomationExtension", False) + + if "all" in PROXIES: + options.add_argument(f"--proxy-server={PROXIES['all']}") + elif "https" in PROXIES: + options.add_argument(f"--proxy-server={PROXIES['https']}") + elif "http" in PROXIES: + options.add_argument(f"--proxy-server={PROXIES['http']}") else: options.add_argument('--proxy-server="direct://"') options.add_argument("--proxy-bypass-list=*") - options.add_experimental_option("excludeSwitches", ["enable-automation"]) - options.add_experimental_option("useAutomationExtension", False) return options @staticmethod @@ -297,24 +240,5 @@ def __parse_log(self) -> str | None: if url is not None and str(url).startswith("pixiv://"): m = re.search(r"code=([^&]*)", url) return None if m is None else str(m.group(1)) - return None - # Example of pref log: - # - # { - # 'level': 'INFO', - # 'message': '{ - # "message": - # { - # "method": "Network.loadingFinished", - # "params":{ - # "encodedDataLength": 0, - # "requestId": "B13E7DBAD4EB28AAD6B05EEA5D628CE5", - # "shouldReportCorbBlocking": false, - # "timestamp":105426.696689 - # } - # }, - # "webview": "9D08CF686401F5B87539217E751861DD" - # }', - # 'timestamp': 1653700994895 - # } + return None diff --git a/gppt/auth.py b/gppt/auth.py index 42161eb..c1f580a 100644 --- a/gppt/auth.py +++ b/gppt/auth.py @@ -38,7 +38,7 @@ def __auth(self, cnt: int) -> tuple[AppPixivAPI, LoginInfo]: print("\x1b[?25l[+]: Login...") login_info = aapi.auth(refresh_token=ref) elif login_cred is None or cnt > 0: - print("[+]: ID is mail address, userid, account name.") + print("[+]: ID is mail address, username, or account name.") stdin_login = ( pwinput.pwinput(prompt="[?]: ID: ", mask=" "), pwinput.pwinput(prompt="[?]: PW: ", mask=" "), @@ -55,7 +55,7 @@ def __auth(self, cnt: int) -> tuple[AppPixivAPI, LoginInfo]: @staticmethod def get_refresh_token(pixiv_id: str, pixiv_pass: str) -> str: g = GetPixivToken() - res = g.login(headless=True, user=pixiv_id, pass_=pixiv_pass) + res = g.login(headless=True, username=pixiv_id, password=pixiv_pass) return res["refresh_token"] def read_client_cred(self) -> LoginCred | None: diff --git a/gppt/main.py b/gppt/main.py index 78d0422..16d9d9a 100644 --- a/gppt/main.py +++ b/gppt/main.py @@ -40,7 +40,7 @@ def print_auth_token_response(res: LoginInfo, json: bool | None = False) -> None def func_login(ns: argparse.Namespace) -> None: g = GetPixivToken() print("[!]: Chrome browser will be launched. Please login.", file=stderr) - res = g.login(user=ns.username, pass_=ns.password) + res = g.login(username=ns.username, password=ns.password) print("[+]: Success!", file=stderr) print_auth_token_response(res, json=ns.json) @@ -54,7 +54,7 @@ def func_logini(ns: argparse.Namespace) -> None: def func_loginh(ns: argparse.Namespace) -> None: g = GetPixivToken() - res = g.login(headless=True, user=ns.username, pass_=ns.password) + res = g.login(headless=True, username=ns.username, password=ns.password) print("[+]: Success!", file=stderr) print_auth_token_response(res, json=ns.json) From 2242208b55f008bcef689d463d81dbb0fbf45361 Mon Sep 17 00:00:00 2001 From: eggplants Date: Fri, 23 Dec 2022 00:31:42 +0900 Subject: [PATCH 09/11] update: readme --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8b9ff3e..f39bfe9 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,10 @@ aapi.auth(refresh_token=REFRESH_TOKEN) ... ``` +## Enable Proxy + +Set `ALL_PROXY` or `HTTPS_PROXY` to your environment variables. + ### From Docker ```shellsession @@ -81,11 +85,12 @@ expires_in: 3600 ```python from gppt import GetPixivToken + g = GetPixivToken() -res = g.login(headless=True, user="...", pass_="...") +res = g.login(headless=True, username="...", password="...") ``` -- `res.response` returns +- `res.response` returns: ```json { From 279783258327d1bc36107d9022df11d14003edb4 Mon Sep 17 00:00:00 2001 From: eggplants Date: Fri, 23 Dec 2022 15:28:42 +0900 Subject: [PATCH 10/11] fix: remove useless lines --- gppt/_selenium.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/gppt/_selenium.py b/gppt/_selenium.py index 92e2e37..721f0c4 100644 --- a/gppt/_selenium.py +++ b/gppt/_selenium.py @@ -184,8 +184,6 @@ def __get_chrome_option(headless: bool | None) -> OptionsType: options.add_argument("--disable-infobars") options.add_argument("--disable-dev-shm-usage") options.add_argument("--disable-browser-side-navigation") - options.add_argument('--proxy-server="direct://"') - options.add_argument("--proxy-bypass-list=*") options.add_argument("--start-maximized") options.add_argument("--no-sandbox") options.add_argument("--disable-dev-shm-usage") From 1718e63a553af94c1c41816cc9baa6edd424a429 Mon Sep 17 00:00:00 2001 From: eggplants Date: Fri, 23 Dec 2022 15:31:17 +0900 Subject: [PATCH 11/11] fix: readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f39bfe9..5c5d719 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,10 @@ pip install gppt ``` +## Enable Proxy + +Set `ALL_PROXY` or `HTTPS_PROXY` to your environment variables. + ## Run Retrieved token can be used like below: @@ -41,10 +45,6 @@ aapi.auth(refresh_token=REFRESH_TOKEN) ... ``` -## Enable Proxy - -Set `ALL_PROXY` or `HTTPS_PROXY` to your environment variables. - ### From Docker ```shellsession