diff --git a/README.md b/README.md index 4e4d1ef..b8ecce2 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ A python script on selenium to automatically create Reddit accounts. - [TODO](#todo) - [Getting started](#getting-started) - [Script Installation](#script-installation) - - [Script Usage](#command-line-usage) + - [Script Usage](#script-usage) - [Package Installation](#package-installation) - - [Package Usage](#package-usage) + - [Package Usage](#package-usage-example) - [Requirements](#requirements) - [Contributing](#contributing) - [License](#license) @@ -23,22 +23,25 @@ A python script on selenium to automatically create Reddit accounts. ## Features - **Automatic captcha bypass**: The script automatically solves captchas during the account creation process. +- **Automatic email verification**: The script automatically verifies the email address used for the account. - **Proxy Support**: Since reddit allows you to create 1 account per IP every 10 minutes, this is very important. - **Resilience**: The script is able to handle most errors that may occur during the account creation process. ## Quick info -You still need to activate the accounts via email. But it doesn't take much time. - Firefox should be installed on your system for the script to work. It is recommended to use proxies, because you can only create 1 account per IP in 10 minutes. See file **proxies.txt** or run `python run_tor.py` +To access the auto-generated email, visit https://1secmail.com + +If you are not using your email, you should not show anyone the email address generated by the program. Having the address of this email, anyone can access it. + ## TODO: - [x] Add automatic browser driver download - [x] Add Tor support for easier proxy management - [x] Make this a python package -- [ ] Automatic email verification +- [x] Automatic email verification - [ ] Handle error when sub is not available # Getting started @@ -66,7 +69,7 @@ pip install -r requirements-cli.txt > **Note** **You need to use Tor (not browser) or proxy, because you can only create 1 account per IP in 10 minutes** -#### Using Tor (recommended) +#### Using Tor (recommended for beginners) Run this command and follow the instructions: ```shell python run_tor.py @@ -75,9 +78,11 @@ python run_tor.py #### Using proxies Add your proxies to the proxies.txt file -### Configuration +### Configuring -Open the `config.py` file and put your email to be used on your accounts. Other settings are optional. +Configuring is not needed. But if you want, you can change the settings in the [config.py](config.py) file. + +### Starting 1. Run the script: @@ -142,7 +147,7 @@ protect_account(username, password) ``` Using proxy: - + ```python from reddit_account_generator import create_account, protect_account, install_driver from reddit_account_generator.proxies import TorProxy diff --git a/config.py b/config.py index 87cfce5..62c096b 100644 --- a/config.py +++ b/config.py @@ -1,4 +1,5 @@ +# You can set here your email if you want, but in that case you need to manually verify account EMAIL = '' PROXIES_FILE = 'proxies.txt' @@ -10,7 +11,7 @@ HIDE_BROWSER = False MAX_RETRIES = 10 # Max retries for creating/protecting account # You can set to False if you have Firefox installed -BUILTIN_DRIVER = True +BUILTIN_DRIVER = False LOG_LEVEL = 'DEBUG' # DEBUG, INFO, WARNING, ERROR, CRITICAL # Tor proxy config @@ -20,6 +21,3 @@ TOR_CONTROL_PORT = 9051 TOR_PASSWORD = 'Passwort' TOR_DELAY = 5 - - -assert EMAIL != '', 'Please enter your email in config.py file' diff --git a/create_accounts.py b/create_accounts.py index a5dbd02..be838b3 100644 --- a/create_accounts.py +++ b/create_accounts.py @@ -2,7 +2,7 @@ from selenium.common.exceptions import NoSuchWindowException, WebDriverException -from reddit_account_generator import maker, protector, create_account, protect_account, install_driver +from reddit_account_generator import maker, protector, verifier, create_account, protect_account, verify_email, install_driver from reddit_account_generator.proxies import DefaultProxy, TorProxy, EmptyProxy from reddit_account_generator.utils import * from reddit_account_generator.exceptions import * @@ -26,12 +26,16 @@ logging.warning('Coloredlogs is not installed. Install it with "pip install coloredlogs" to get cool logs!') # Set config variables +# TODO: Make this better maker.PAGE_LOAD_TIMEOUT_S = PAGE_LOAD_TIMEOUT_S maker.DRIVER_TIMEOUT_S = DRIVER_TIMEOUT_S maker.MICRO_DELAY_S = MICRO_DELAY_S protector.PAGE_LOAD_TIMEOUT_S = PAGE_LOAD_TIMEOUT_S protector.DRIVER_TIMEOUT_S = DRIVER_TIMEOUT_S protector.MICRO_DELAY_S = MICRO_DELAY_S +verifier.PAGE_LOAD_TIMEOUT_S = PAGE_LOAD_TIMEOUT_S +verifier.DRIVER_TIMEOUT_S = DRIVER_TIMEOUT_S +verifier.MICRO_DELAY_S = MICRO_DELAY_S if BUILTIN_DRIVER: # Install firefox driver binary @@ -83,7 +87,11 @@ def save_account(email: str, username: str, password: str): while retries < MAX_RETRIES: try: - username, password = create_account(EMAIL, proxies=proxy_, hide_browser=HIDE_BROWSER) + email, username, password = create_account( + email=EMAIL or None, + proxies=proxy_, + hide_browser=HIDE_BROWSER + ) break except UsernameTakenException: @@ -117,14 +125,14 @@ def save_account(email: str, username: str, password: str): _logger.error('An error occurred during account creation. Exiting...') exit(1) - save_account(EMAIL, username, password) + save_account(email, username, password) _logger.info('Account created! Protecting account...') # Try to protect account for i in range(MAX_RETRIES): try: protect_account(username, password, hide_browser=HIDE_BROWSER) - _logger.info('Account protected!\n') + _logger.info('Account protected!') break except IncorrectUsernameOrPasswordException: @@ -136,4 +144,16 @@ def save_account(email: str, username: str, password: str): else: _logger.error('Account protection failed. Skipping...') + if not EMAIL: + for i in range(MAX_RETRIES): + try: + verify_email(email) + _logger.info('Email verified!\n') + break + except WebDriverException as e: + _logger.error(e) + _logger.error('An error occurred during email verification. Trying again... [%s/%s]', i+1, MAX_RETRIES) + else: + _logger.error('Email verification failed. Skipping...') + _logger.info('Done!') diff --git a/reddit_account_generator/__init__.py b/reddit_account_generator/__init__.py index 4faf7e7..793f46e 100644 --- a/reddit_account_generator/__init__.py +++ b/reddit_account_generator/__init__.py @@ -9,6 +9,7 @@ from .maker import create_account from .protector import protect_account +from .verifier import verify_email def install_driver(): diff --git a/reddit_account_generator/_version.py b/reddit_account_generator/_version.py index b3ddbc4..58d478a 100644 --- a/reddit_account_generator/_version.py +++ b/reddit_account_generator/_version.py @@ -1 +1 @@ -__version__ = '1.1.1' +__version__ = '1.2.0' diff --git a/reddit_account_generator/exceptions.py b/reddit_account_generator/exceptions.py index dc32943..9ff3c03 100644 --- a/reddit_account_generator/exceptions.py +++ b/reddit_account_generator/exceptions.py @@ -23,4 +23,7 @@ class SessionExpiredException(Exception): class IncorrectUsernameOrPasswordException(Exception): pass +class EmailVerificationException(Exception): + pass + NetworkException = (RecaptchaException, IPCooldownException, TimeoutException) diff --git a/reddit_account_generator/maker.py b/reddit_account_generator/maker.py index 5c39112..bda6138 100644 --- a/reddit_account_generator/maker.py +++ b/reddit_account_generator/maker.py @@ -1,6 +1,7 @@ import time import logging +from tempmail import EMail from selenium.common.exceptions import TimeoutException, WebDriverException, NoSuchElementException, ElementClickInterceptedException from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait @@ -17,8 +18,8 @@ _logger = logging.getLogger(__name__) -def create_account(email: str, username: str | None = None, password: str | None = None, - proxies: dict[str, str] | None = None, hide_browser: bool = True) -> tuple[str, str]: +def create_account(email: str | None = None, username: str | None = None, password: str | None = None, + proxies: dict[str, str] | None = None, hide_browser: bool = True) -> tuple[str, str, str]: """Create a Reddit account.""" _logger.info('Creating reddit account') @@ -27,6 +28,9 @@ def create_account(email: str, username: str | None = None, password: str | None if PAGE_LOAD_TIMEOUT_S is not None: driver.set_page_load_timeout(PAGE_LOAD_TIMEOUT_S) + if email is None: + email = EMail().address + if password is None: password = generate_password() @@ -113,7 +117,7 @@ def create_account(email: str, username: str | None = None, password: str | None if 'character' in password_err.text.lower(): raise PasswordLengthException(password_err.text) raise Exception(password_err.text) - + # Solve captcha _logger.debug('Solving captcha') WebDriverWait(driver, DRIVER_TIMEOUT_S).until(EC.element_to_be_clickable((By.XPATH, '//iframe[@title="reCAPTCHA"]'))) @@ -150,9 +154,7 @@ def create_account(email: str, username: str | None = None, password: str | None # Account created! - except Exception as e: # quit driver if error occurs + finally: # quit driver if error occurs driver.quit() - raise e - driver.quit() - return username, password + return email, username, password diff --git a/reddit_account_generator/protector.py b/reddit_account_generator/protector.py index 393ebef..10b2276 100644 --- a/reddit_account_generator/protector.py +++ b/reddit_account_generator/protector.py @@ -59,7 +59,7 @@ def protect_account(username: str, password: str, driver.get('https://www.reddit.com/login/') except WebDriverException: raise TimeoutException('Website takes too long to load. Probably a problem with the proxy.') - + # Enter username and password _logger.debug('Entering username and password') username_input = driver.find_element(By.ID, 'loginUsername') @@ -100,8 +100,5 @@ def protect_account(username: str, password: str, # Done! - except Exception as e: # quit driver if error occurs + finally: # quit driver if error occurs driver.quit() - raise e - - driver.quit() diff --git a/reddit_account_generator/utils.py b/reddit_account_generator/utils.py index 6c193ed..4ff305b 100644 --- a/reddit_account_generator/utils.py +++ b/reddit_account_generator/utils.py @@ -99,7 +99,7 @@ def setup_firefox_driver(proxies: dict[str, str] | None = None, hide_browser: bo options.set_preference('network.proxy.socks_port', int(socks_port)) options.set_preference('network.proxy.socks_remote_dns', False) - return webdriver.Firefox(options=options, service_log_path=os.devnull) + return webdriver.Firefox(options=options) def try_to_click(element: WebElement, delay: int | float = 0.5, max_tries: int = 20) -> bool: @@ -112,4 +112,4 @@ def try_to_click(element: WebElement, delay: int | float = 0.5, max_tries: int = except: retries += 1 time.sleep(delay) - raise TimeoutException(f'Could not click element after {max_tries} tries.') + raise TimeoutException(f'Could not click element after {max_tries} tries.') \ No newline at end of file diff --git a/reddit_account_generator/verifier.py b/reddit_account_generator/verifier.py new file mode 100644 index 0000000..c734ac7 --- /dev/null +++ b/reddit_account_generator/verifier.py @@ -0,0 +1,58 @@ +import logging + +import requests +from tempmail import EMail + +from .exceptions import EmailVerificationException + +_logger = logging.getLogger(__name__) + + +def verify_email(email: str, proxies: dict[str, str] | None = None): + _logger.info('Verifying reddit account email') + + # Get verification link + link = get_verification_link(email) + direct_link = get_direct_verification_link(link) + + _logger.debug('Verifying email') + resp = requests.post(direct_link, headers={ + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.0' + }, proxies=proxies) + + if resp.status_code != 200: + if 'EMAIL_ALREADY_VERIFIED' not in resp.text: + raise EmailVerificationException(resp.text) + + _logger.warning('Email is already verified') + + +def get_verification_link(email: str) -> str: + try: + email_ = EMail(email) + except ValueError: + raise ValueError('Verification of this email is not supported.') + + _logger.debug('Waiting for email...') + msg = email_.wait_for_message(filter=lambda m: 'reddit' in m.subject.lower()) + + # Get link + start = msg.body.index('https://www.reddit.com/verification/') + end = msg.body.index('"', start) + link = msg.body[start:end] + + return link + + +def get_direct_verification_link(link: str) -> str: + """Create a direct verification link from a verification link.""" + + start = link.index('verification/') + len('verification/') + end = link.index('?', start) + token = link[start:end] + + start = link.index('correlation_id=') + len('correlation_id=') + end = link.index('&', start) + correlation_id = link[start:end] + + return f'https://www.reddit.com/api/v1/verify_email/{token}.json?correlation_id={correlation_id}&ref_campaign=verify_email' diff --git a/requirements.txt b/requirements.txt index 15c8deb..9271606 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,5 @@ selenium-recaptcha-solver >=1.4.0, <=1.9.0 random-username >=1.0.0, <=1.0.2 webdriverdownloader >=1.0.0, <=1.1.0.3 stem >=1.8.0, <=1.8.2 -static-ffmpeg >=2.3, <=2.5 \ No newline at end of file +static-ffmpeg >=2.3, <=2.5 +tempmail-python==2.3.0 diff --git a/setup.py b/setup.py index 15521c7..38debd4 100644 --- a/setup.py +++ b/setup.py @@ -32,6 +32,7 @@ def get_version(ver_file: str) -> str: # Credits to pyTelegramBotAPI setup.py 'webdriverdownloader >=1.0.0, <=1.1.0.3', 'stem >=1.8.0, <=1.8.2', 'static-ffmpeg >=2.3, <=2.5', + 'tempmail-python==2.3.0', ], classifiers=[ 'Development Status :: 5 - Production/Stable',