Exemplo n.º 1
0
    def scrape(self, **kwargs):
        logger.info("Solving reCAPTCHA (~30s)")

        captcha_solver = CaptchaSolver(api_key=config.ANTI_CAPTCHA_KEY)

        # Site key obtained from: https://www.homedepot.com/mycheckout/assets/react/giftcard.bundle.1.2302.0.js
        captcha_resp = captcha_solver.solve_recaptcha(
            self.website_url, "6LfEHBkTAAAAAHX6YgeUw9x1Sutr7EzhMdpbIfWJ")

        if captcha_resp["errorId"] != 0:
            raise RuntimeError(
                f"Unable to solve reCAPTCHA ({captcha_resp['errorDescription']})"
            )

        payload = {
            "GiftCardsRequest": {
                "cardNumber": kwargs["card_number"],
                "pinNumber": kwargs["pin"],
                "reCaptcha": captcha_resp["solution"]["gRecaptchaResponse"],
            }
        }

        logger.info("Fetching balance from API")

        try:
            resp = requests.post(self.api_endpoint,
                                 json=payload,
                                 headers=HEADERS)

            if resp.status_code != 200:
                raise RuntimeError(
                    f"Invalid API response (status code {resp.status_code})")

            result = deep_get(resp.json(), "giftCards.giftCard")
            if result is None:
                raise RuntimeError(
                    f"Invalid API response: unable to find giftCard key in JSON response"
                )

            err_code = deep_get(result, "errorCode")
            if err_code:
                err_desc = deep_get(result, "description")
                raise RuntimeError(
                    f"Failed to retrieve balance from API: {err_desc} ({err_code})"
                )

            initial_balance = deep_get(result, "originalAmount")
            avail_balance = deep_get(result, "availableAmount")

            logger.info(f"Success! Card balance: {avail_balance}")

            return {
                "initial_balance": initial_balance,
                "available_balance": avail_balance,
            }
        except requests.exceptions.RequestException as e:
            raise RuntimeError(f"Error on API post: {e}")
        except JSONDecodeError:
            raise RuntimeError("Failed to parse API response as JSON")
Exemplo n.º 2
0
    def scrape(self, fields):
        session = requests.Session()
        session.headers.update({"User-Agent": config.USER_AGENT})

        logger.info("Fetching balance check page")

        resp = session.get(self.website_url)
        if resp.status_code != 200:
            raise RuntimeError(
                "Failed to GET Spafinder website (status code {})".format(
                    resp.status_code))

        page_html = BeautifulSoup(resp.content, features="html.parser")
        inquiry = page_html.find(id="balance-inquiry")
        form = inquiry.find("form")
        if not form:
            raise RuntimeError("Unable to find balance check form")

        endpoint = "{}{}".format(self.base_url, form["action"])

        # Page has bad HTML, need to search from top level
        recaptcha_field = page_html.find("div", class_="g-recaptcha")
        if not recaptcha_field:
            raise RuntimeError("Unable to find reCAPTCHA")

        site_key = recaptcha_field["data-sitekey"]

        logger.info("Solving reCAPTCHA (~30s)")

        captcha_solver = CaptchaSolver(api_key=config.ANTI_CAPTCHA_KEY)
        captcha_resp = captcha_solver.solve_recaptcha(self.website_url,
                                                      site_key)
        if captcha_resp["errorId"] != 0:
            raise RuntimeError("Unable to solve reCAPTCHA ({})".format(
                captcha_resp["errorDescription"]))

        fields["g-recaptcha-response"] = captcha_resp["solution"][
            "gRecaptchaResponse"]

        logger.info("Fetching card balance")

        form_resp = session.post(endpoint, data=fields)
        if form_resp.status_code != 200:
            raise RuntimeError(
                "Failed to retrieve card balance (status code {})".format(
                    form_resp.status_code))

        resp_html = BeautifulSoup(form_resp.content, features="html.parser")
        error_html = resp_html.find("div", class_="alert-danger")
        if error_html:
            raise RuntimeError("Got error while checking balance: {}".format(
                error_html.text))

        balance_container = resp_html.find("div", class_="alert-success")
        if not balance_container:
            raise RuntimeError("Unable to find balance container")

        balance_match = re.search("(\d{1,2}\.\d{2})",
                                  balance_container.get_text())
        if not balance_match:
            raise RuntimeError("Unable to find balance text")

        balance = "${}".format(balance_match.group(0))

        logger.info("Success! Card balance: {}".format(balance))

        return {"balance": balance}
Exemplo n.º 3
0
    def scrape(self, fields):
        # Open Selenium browser
        browser = webdriver.Chrome()
        browser.set_window_size(600, 800)

        logger.info("Fetching balance check page")
        browser.get(self.website_url)

        try:
            form = browser.find_elements_by_tag_name("form")[1]
        except (NoSuchElementException, IndexError):
            raise RuntimeError("Unable to find login form on page")

        logger.info("Filling login form 1/2")
        try:
            form.find_element_by_name("accountNumber").send_keys(
                fields["accountNumber"])
            time.sleep(1)
        except NoSuchElementException:
            browser.close()
            raise RuntimeError(f"Unable to find 'accountNumber' field on page")

        # Click continue button
        form.find_element_by_css_selector("input[type='submit']").click()

        # Wait for page to load
        try:
            WebDriverWait(browser, 3).until(
                EC.presence_of_element_located((By.ID, "login-form")))
        except TimeoutException:
            browser.close()
            raise RuntimeError("Login page took too long to load")

        try:
            form = browser.find_element_by_id("login-form")
        except NoSuchElementException:
            browser.close()
            raise RuntimeError("Unable to find login form on page")

        logger.info("Solving CAPTCHA (~10s)")

        # Extract CAPTCHA image from page
        captcha_b64 = get_image_b64_by_id(browser, "captchaImg")

        captcha_solver = CaptchaSolver(api_key=config.ANTI_CAPTCHA_KEY)
        captcha = captcha_solver.solve_image_b64(captcha_b64)
        if captcha["errorId"] != 0:
            browser.close()
            raise RuntimeError("Unable to solve CAPTCHA ({})".format(
                captcha["errorDescription"]))

        logger.info("Filling login form 2/2")
        try:
            form.find_element_by_name("cv2").send_keys(fields["cv2"])
            time.sleep(1)
        except NoSuchElementException:
            browser.close()
            raise RuntimeError("Unable to find 'cv2' field on page")

        try:
            form.find_element_by_id(
                "_MultiStageFSVpasswordloginresponsive_WAR_cardportalresponsive_captchaText"
            ).send_keys(captcha["solution"]["text"])
            time.sleep(1)
        except NoSuchElementException:
            browser.close()
            raise RuntimeError("Unable to find CAPTCHA field on page")

        # Click continue button
        form.find_element_by_css_selector("input[type='submit']").click()

        # Wait for page to load
        try:
            WebDriverWait(browser, 3).until(
                EC.presence_of_element_located((By.ID, "cardBalanceInfo")))
        except TimeoutException:
            browser.close()
            raise RuntimeError("Balance page took too long to load")

        logger.info("Obtaining card information")
        try:
            avail_balance = browser.find_element_by_class_name(
                "cardBalanceText").text
        except NoSuchElementException:
            browser.close()
            raise RuntimeError("Could not find available card balance")

        browser.close()
        logger.info(f"Success! Card balance: {avail_balance}")

        return {"initial_balance": None, "available_balance": avail_balance}
Exemplo n.º 4
0
    def scrape(self, fields):
        session = requests.Session()
        session.headers.update({"User-Agent": config.USER_AGENT})

        fields["X-Requested-With"] = "XMLHttpRequest"

        logger.info("Fetching balance check page")

        resp = session.get(self.website_url)
        if resp.status_code != 200:
            raise RuntimeError(
                f"Failed to GET Blackhawk website (status code {resp.status_code})"
            )

        page_html = BeautifulSoup(resp.content, features="html.parser")
        transactions = page_html.find(id="CheckBalanceTransactions")
        form = transactions.find("form")
        if not form:
            raise RuntimeError("Unable to find balance check form")

        endpoint = "{}{}".format(self.website_url, form["action"])

        token_field = transactions.find(
            "input", attrs={"name": "__RequestVerificationToken"})
        if not token_field:
            raise RuntimeError("Failed to retrieve verification token")

        fields["__RequestVerificationToken"] = token_field["value"]

        arkose_key = extract_arkose_key(resp.text)
        if not arkose_key:
            raise RuntimeError("Failed to extract Arkose Labs public key")

        logger.info("Solving FunCaptcha (~30s)")

        captcha_solver = CaptchaSolver(api_key=config.ANTI_CAPTCHA_KEY)
        captcha = captcha_solver.solve_funcaptcha(self.website_url, arkose_key)
        if captcha["errorId"] != 0:
            raise RuntimeError("Unable to solve FunCaptcha ({})".format(
                captcha["errorDescription"]))

        fields["captchaToken"] = captcha["solution"]["token"]

        logger.info("Fetching card balance")

        session.headers.update({
            "Accept": "*/*",
            "Accept-Encoding": "gzip, deflate, br",
            "Accept-Language": "en-US,en;q=0.5",
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
            "Pragma": "no-cache",
            "Referer": "https://mygift.giftcardmall.com/",
            "X-Requested-With": "XMLHttpRequest",
        })

        form_resp = session.post(endpoint, data=fields)
        if form_resp.status_code != 200:
            raise RuntimeError(
                "Failed to retrieve card balance (status code {})".format(
                    form_resp.status_code))

        balance_html = BeautifulSoup(form_resp.content, features="html.parser")

        avail_balance = (balance_html.find(
            "div", text="Available Balance").parent.find("div",
                                                         class_="value").text)

        initial_balance = (balance_html.find(
            "div", text="Initial Balance").parent.find("div",
                                                       class_="value").text)

        logger.info("Success! Card balance: {}".format(avail_balance))

        return {
            "initial_balance": initial_balance,
            "available_balance": avail_balance
        }
Exemplo n.º 5
0
    def scrape(self, fields):
        session = requests.Session()
        session.headers.update({"User-Agent": config.USER_AGENT})

        logger.info("Fetching balance check page")

        resp = session.get(self.website_url)
        if resp.status_code != 200:
            logger.critical(
                f"Failed to GET Blackhawk website (status code {resp.status_code})"
            )
            sys.exit(1)

        page_html = BeautifulSoup(resp.content, features="html.parser")
        form = page_html.find("form")
        if not form:
            logger.critical("Unable to find balance check form")
            sys.exit(1)

        endpoint = "{}{}".format(self.website_url, form["action"])

        token_field = page_html.find(
            "input", attrs={"name": "__RequestVerificationToken"})
        if not token_field:
            logger.critical("Failed to retrieve verification token")
            sys.exit(1)

        fields["__RequestVerificationToken"] = token_field["value"]

        recaptcha_field = page_html.find("div", class_="g-recaptcha")
        if not recaptcha_field:
            logger.critical("Unable to find reCAPTCHA")
            sys.exit(1)

        site_key = recaptcha_field["data-sitekey"]

        logger.info("Solving reCAPTCHA (~30s)")

        captcha_solver = CaptchaSolver(api_key=config.ANTI_CAPTCHA_KEY)
        captcha = captcha_solver.solve_recaptcha(self.website_url, site_key)
        if captcha["errorId"] != 0:
            logger.critical(
                f"Unable to solve reCAPTCHA ({captcha['errorDescription']})")
            sys.exit(1)

        fields["g-recaptcha-response"] = captcha["solution"][
            "gRecaptchaResponse"]

        logger.info("Fetching card balance")

        session.headers.update({
            "Accept": "*/*",
            "Accept-Encoding": "gzip, deflate, br",
            "Accept-Language": "en-US,en;q=0.5",
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
            "Pragma": "no-cache",
            "Referer": self.website_url,
            "X-Requested-With": "XMLHttpRequest",
            "Host": "cardholder.happycards.com",
            "Origin": "https://cardholder.happycards.com",
        })

        form_resp = session.post(endpoint, data=fields)
        if form_resp.status_code != 200:
            logger.critical(
                f"Failed to retrieve card balance (status code {form_resp.status_code})"
            )
            sys.exit(1)

        balance_html = BeautifulSoup(form_resp.content, features="html.parser")

        try:
            avail_balance = (balance_html.find(
                "div",
                text="Available Balance").parent.find("div",
                                                      class_="value").text)
        except:
            print("Couldnt read available balance from page.")
            print(form_resp.content)

        initial_balance = (balance_html.find(
            "div", text="Initial Balance").parent.find("div",
                                                       class_="value").text)

        logger.info("Success! Card balance: {}".format(avail_balance))

        return {
            "initial_balance": initial_balance,
            "available_balance": avail_balance
        }
Exemplo n.º 6
0
    def scrape(self, **kwargs):
        cookies = CookieJar()
        opener = request.build_opener(request.HTTPCookieProcessor(cookies))

        logger.info("Fetching balance check page")

        # Use urllib directly as requests gets blocked
        req = request.Request(self.website_url, headers=HEADERS)
        resp = opener.open(req)

        if resp.status != 200:
            raise RuntimeError(
                f"Failed to get GameStop website (status code {resp.status})")

        page_html = BeautifulSoup(resp.read(), features="html.parser")

        recaptcha_el = page_html.find("div", {"data-sitekey": True})
        if not recaptcha_el:
            raise RuntimeError("Unable to find reCAPTCHA on page")

        csrf_el = page_html.find("input", {"name": "csrf_token"})
        if not csrf_el:
            raise RuntimeError("Unable to find CSRF on page")

        site_key = recaptcha_el["data-sitekey"]
        csrf_token = csrf_el["value"]

        logger.info("Solving reCAPTCHA (~30s)")

        captcha_solver = CaptchaSolver(api_key=config.ANTI_CAPTCHA_KEY)
        captcha_resp = captcha_solver.solve_recaptcha(self.website_url,
                                                      site_key)
        if captcha_resp["errorId"] != 0:
            raise RuntimeError(
                f"Unable to solve reCAPTCHA ({captcha_resp['errorDescription']})"
            )

        payload = {
            "dwfrm_giftCard_balance_accountNumber": kwargs["card_number"],
            "dwfrm_giftCard_balance_pinNumber": kwargs["pin"],
            "g-recaptcha-response":
            captcha_resp["solution"]["gRecaptchaResponse"],
            "csrf_token": csrf_token,
        }

        logger.info("Fetching balance from API")

        try:
            req = request.Request(self.api_endpoint, headers=HEADERS)
            data = urlencode(payload).encode("utf-8")
            req.add_header("Content-Type",
                           "application/x-www-form-urlencoded; charset=UTF-8")
            req.add_header("Content-Length", len(data))
            resp = opener.open(req, data)

            if resp.status != 200:
                raise RuntimeError(
                    f"Invalid API response (status code {resp.status})")

            result = json.loads(resp.read().decode(
                resp.info().get_param("charset") or "utf-8"))
            errors = deep_get(result, "error")
            if errors:
                err = errors[0]
                raise RuntimeError(
                    f"Failed to retrieve balance from API: {err}")

            balance = deep_get(result, "balance")
            if balance is None:
                raise RuntimeError(
                    f"Invalid API response: unable to find required key in JSON response"
                )

            logger.info(f"Success! Card balance: ${balance}")

            return {
                "balance": f"${balance}",
            }
        except json.JSONDecodeError:
            raise RuntimeError("Failed to parse API response as JSON")
Exemplo n.º 7
0
import colorlog
from balance_check import config
from balance_check.utils.logging import configure_logger
from balance_check.utils.captcha import CaptchaSolver

logger = colorlog.getLogger()
configure_logger(logger)

captcha_solver = CaptchaSolver(api_key=config.ANTI_CAPTCHA_KEY)