Skip to content

Commit

Permalink
fix recaptcha & move variation
Browse files Browse the repository at this point in the history
  • Loading branch information
MRHRTZ committed Apr 6, 2023
1 parent 657c94e commit ad5fbf6
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 61 deletions.
4 changes: 2 additions & 2 deletions config/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
"modules": [
"progress",
"inquirer",
"selenium-wire",
"seleniumwire",
"progress",
"colorama",
"requests",
"wget"
],
"platform": ""
}
}
31 changes: 6 additions & 25 deletions lib/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import platform
import wget

from .utils import is_valid_url
from requests import get, post
from colorama import Fore, Style
from zipfile import ZipFile
Expand Down Expand Up @@ -230,29 +231,11 @@ def set_url():
answer = inquirer.prompt(URL)['url']
settings['url'] = answer
print(f'\n{Fore.LIGHTYELLOW_EX}Checking url ...\n')
item_detail = checkUrl(**settings)
if item_detail:
variation = item_detail['tier_variations']
print(variation)
sel_variation_list = []
if len(variation) > 0:
for variant in variation:
variant_name = variant['name']
select_variant = []
for i in range(len(variant['options'])):
if not variant['summed_stocks'] or variant['summed_stocks'][i] > 0:
select_variant.append(variant['options'][i])
list_variant = [
inquirer.List(
f'variant-{i}', message=variant_name, choices=select_variant)
]

_prompt = inquirer.prompt(list_variant)
selected_variant = _prompt[f'variant-{i}']
sel_variation_list.append(selected_variant)
settings['variation'] = sel_variation_list
variation_str = f' {Fore.RED}| {Fore.WHITE}'.join(sel_variation_list)
print(f'{Fore.GREEN}Saving{Fore.WHITE}: {Fore.BLUE}{item_detail["name"]}\n{Fore.WHITE}{variation_str}')
is_valid = is_valid_url(answer)
if is_valid:
# settings['variation'] = sel_variation_list
# variation_str = f' {Fore.RED}| {Fore.WHITE}'.join(sel_variation_list)
print(f'{Fore.GREEN}Saving{Fore.WHITE}: {Fore.BLUE}{answer}')
time.sleep(3)
writeFileJson(settings, './config/index.json')
menu()
Expand Down Expand Up @@ -307,8 +290,6 @@ def start_countdown():
input(Fore.GREEN + '[ Back ]' + Style.RESET_ALL)
menu()
else:
clearConsole()
print(Fore.YELLOW + '[ Initial chrome automation... ]\n\n')
executeScript(**settings)


Expand Down
141 changes: 107 additions & 34 deletions lib/driverExecutor.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json, traceback, time
import inquirer

from datetime import datetime
from colorama import Fore, Style
Expand All @@ -8,10 +9,42 @@
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait as WebDriverWaitUI
from selenium.common.exceptions import TimeoutException

from .utils import decode_network
from lib.moduleChecker import clearConsole

def select_variation(driver, item_details):
#select all available types on web
variation = item_details['tier_variations']
variation_selections = []
if len(variation) > 0:
for variant in variation:
variant_name = variant['name']
select_variant = []
for i in range(len(variant['options'])):
if not variant['summed_stocks'] or variant['summed_stocks'][i] > 0:
select_variant.append(variant['options'][i])
list_variant = [
inquirer.List(
f'variant-{i}', message=variant_name, choices=select_variant)
]

_prompt = inquirer.prompt(list_variant)
selected_variant = _prompt[f'variant-{i}']
variation_selections.append(selected_variant)

for variant in variation_selections:
variant_selector = f'button.product-variation[aria-label="{variant}"]'
wait_variant_btn = WebDriverWait(driver, 10)
variant_button = wait_variant_btn.until(EC.element_to_be_clickable((By.CSS_SELECTOR, variant_selector)))
variant_button.click()

def executeScript(**params):
clearConsole()
print(Fore.YELLOW + '[ Initial chrome automation... ]\n\n')

process_indicator = 0
url = params['url']
session_path = './sessions/' + params['session']
Expand All @@ -21,6 +54,7 @@ def executeScript(**params):

chromeOpts = webdriver.ChromeOptions()
# chromeOpts.add_argument('--headless')
chromeOpts.add_argument("--window-size=1280,720")

driver = webdriver.Chrome(driverPath, options=chromeOpts)
driver.get(url)
Expand All @@ -35,45 +69,62 @@ def executeScript(**params):
driver.add_cookie(cookie)

clearConsole()
print(Fore.YELLOW + ' [ # process ... ]')

# Detect network
request = driver.wait_for_request('/api/v4/item/get')
item_details = json.loads(decode(request.response.body, request.response.headers.get('Content-Encoding', 'identity')))
# Check account
try:
print(Fore.LIGHTYELLOW_EX + ' [ Loading account ... ]\n')
delay = 3
waitAcc = WebDriverWaitUI(driver, delay).until(EC.presence_of_element_located((By.CLASS_NAME, 'navbar__username')))
print(Fore.GREEN + ' [ Success #. ]\n')
except TimeoutException:
pass

# Detect network
request = driver.wait_for_request('/api/v4/item/get', 60)
item_details = decode_network(request)
for key, value in item_details.items():
print(f' {Fore.WHITE}{key}{Fore.RED}: {Fore.GREEN}:{value}')

# Check item
if not item_details or 'data' not in item_details:
print(Fore.RED + '\n\n\n [ Item not found ]\n\n')
return
print(Fore.CYAN + '\n [ Item not found, This can happen because login error, attempting second phase in 10 sec ... ]\n')
driver.refresh()
time.sleep(5)
request = driver.wait_for_request('/api/v4/item/get')
item_details = decode_network(request)
for request in driver.requests:
if request.response:
if '/api/v4/item/get?' in request.url:
# print(
# request.url,
# request.response.status_code,
# request.response.headers['Content-Type']
# )
item_details = decode_network(request)
if not item_details or 'data' not in item_details:
print(Fore.RED + '\n [ Second phase failed! ]\n')
return
else:
item_details = item_details['data']
else:
item_details = item_details['data']

# Check stock
if item_details['stock'] == 0:
print(Fore.RED + '\n\n\n [ Item is out of stock ]\n\n')
return

# Check account
while True:
if process_indicator % 5000 == 0: driver.refresh()
spinner = MoonSpinner(Fore.LIGHTYELLOW_EX + 'Loading page, if you stay here too long please refresh the page or stop to change session account')
htmlsource = driver.page_source
if 'navbar__username' in htmlsource:
clearConsole()
break
else:
spinner.next()
process_indicator += 1

# Check is flashsale
if not item_details['flash_sale'] and not item_details['upcoming_flash_sale']:
if 'flash_sale' not in item_details and 'upcoming_flash_sale' not in item_details:
# Check stock
if item_details['stock'] == 0:
print(Fore.RED + '\n\n\n [ Item is out of stock ]\n\n')
return
isbuy = input(Fore.YELLOW + '\n This is not an item for flashsale, continue buy? [Y/n] ')
if isbuy.lower() != 'y': return
select_variation(driver, item_details)
elif item_details['flash_sale']:
if item_details['flash_sale']['stock'] == 0:
print(Fore.RED + '\n [ FlashSale item out of stock. ]\n')
return
else:
print(Fore.BLUE + '\n [ FlashSale already started. ]\n')
print(Fore.BLUE + '\n [ FlashSale already started. ]\n')
select_variation(driver, item_details)
elif item_details['upcoming_flash_sale']:
item_name = item_details['name']
shop_loc = item_details['shop_location']
Expand All @@ -87,6 +138,8 @@ def executeScript(**params):
start_time = item_details['upcoming_flash_sale']['start_time']
start_time = datetime.fromtimestamp(start_time)

select_variation(driver, item_details)

while True:
now = datetime.today()
raw_remain_time = start_time - now
Expand All @@ -111,13 +164,6 @@ def executeScript(**params):

# Checkout & Order (Premium Edition)
try:
#select all available types on web
for variant in variation:
variant_selector = f'button.product-variation[aria-label="{variant}"]'
wait_variant_btn = WebDriverWait(driver, 10)
variant_button = wait_variant_btn.until(EC.element_to_be_clickable((By.CSS_SELECTOR, variant_selector)))
variant_button.click()

to_cart_active = 'button.btn.btn-solid-primary.btn--l'
to_cart_disable = 'button.btn.btn-solid-primary.btn--l.btn-solid-primary--disabled'
checkout = 'button.shopee-button-solid.shopee-button-solid--primary'
Expand All @@ -144,23 +190,50 @@ def executeScript(**params):
print(f'\n Bye 👋' + Style.RESET_ALL)


def checkUrl(**params):
def checkUrl(**params):
# TODO: Resolve Captcha !!!!

process_indicator = 0
url = params['url']
driverPath = params['chromedriver']
platform = params['platform']
session_path = './sessions/' + params['session']

try:
chromeOpts = webdriver.ChromeOptions()
chromeOpts.add_argument('--headless')
# chromeOpts.add_argument('--headless')

driver = webdriver.Chrome(driverPath, options=chromeOpts)
driver.get(url)

with open(session_path, 'r') as f:
session = json.load(f)

for cookie in session:
if 'sameSite' in cookie:
if cookie['sameSite'] == 'None' or 'unspecified':
cookie['sameSite'] = 'Strict'
driver.add_cookie(cookie)

# Check account
while True:
if process_indicator % 5000 == 0: driver.refresh()
print(Fore.LIGHTYELLOW_EX + 'Loading page, if you stay here too long please refresh the page or stop to change session account')
htmlsource = driver.page_source
if 'navbar__username' in htmlsource:
clearConsole()
break
else:
time.sleep(0.5)
clearConsole()
process_indicator += 1

# Detect network
request = driver.wait_for_request('/api/v4/item/get')
item_details = json.loads(decode(request.response.body, request.response.headers.get('Content-Encoding', 'identity')))

# Check item
print(item_details)
if not item_details or 'data' not in item_details:
print(Fore.RED + '\n [ Item not found ]\n')
return None
Expand Down
14 changes: 14 additions & 0 deletions lib/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import json

from urllib import parse
from seleniumwire.utils import decode

def decode_network(request):
return json.loads(decode(request.response.body, request.response.headers.get('Content-Encoding', 'identity')))

def is_valid_url(url):
try:
result = parse.urlparse(url)
return all([result.scheme, result.netloc, result.path])
except:
return False

0 comments on commit ad5fbf6

Please # to comment.