diff --git a/README.md b/README.md
index 1ca6b05..2eddbfa 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,7 @@ Automation tool for checking the balance of gift cards issued by various provide
- [GameStop](https://www.gamestop.com/giftcards/) - `gamestop` CAPTCHA
- [Best Buy](https://www.bestbuy.com/gift-card-balance) - `bestbuy`
- [Home Depot](https://www.homedepot.com/mycheckout/giftcard) - `homedepot` CAPTCHA
+- [Starbucks](https://www.starbucks.com/card) - `starbucks`
Providers marked with CAPTCHA will require an [Anti-CAPTCHA](https://anti-captcha.com) API key.
diff --git a/balance_check/providers/__init__.py b/balance_check/providers/__init__.py
index 309bcc0..21c7034 100644
--- a/balance_check/providers/__init__.py
+++ b/balance_check/providers/__init__.py
@@ -9,4 +9,5 @@
"onevanilla",
"prepaidgiftbalance",
"spafinder",
+ "starbucks",
]
diff --git a/balance_check/providers/starbucks.py b/balance_check/providers/starbucks.py
new file mode 100644
index 0000000..3715dc5
--- /dev/null
+++ b/balance_check/providers/starbucks.py
@@ -0,0 +1,51 @@
+import asyncio
+import pyppeteer
+from balance_check import logger
+from balance_check.provider import BalanceCheckProvider
+from balance_check.validators.gift_card import Merchant, GiftCardSchema
+
+
+class Starbucks(BalanceCheckProvider):
+ def __init__(self):
+ super().__init__()
+
+ self.website_url = "https://www.starbucks.com/card"
+ self.schema = GiftCardSchema(Merchant.Starbucks)
+
+ async def scrape(self, fields):
+ browser = await pyppeteer.launch(
+ handleSIGINT=False, handleSIGTERM=False, handleSIGHUP=False
+ )
+ page = await browser.newPage()
+
+ logger.info("Fetching balance check page")
+ await page.goto(self.website_url)
+
+ logger.info("Filling balance check form")
+ await page.type("#Card_Number", fields["card_number"])
+ await page.type("#Card_Pin", fields["pin"])
+
+ logger.info("Requesting balance")
+ await page.click("#CheckBalance button")
+ await page.waitForSelector(".fetch_balance_value", {"timeout": 10000})
+
+ avail_balance = await page.querySelectorEval(
+ ".fetch_balance_value", "(node => node.innerText)"
+ )
+
+ logger.info("Success! Card balance: {}".format(avail_balance))
+
+ return {"available_balance": avail_balance}
+
+ def check_balance(self, **kwargs):
+ if self.validate(kwargs):
+ logger.info("Checking balance for card: {}".format(kwargs["card_number"]))
+
+ loop = asyncio.new_event_loop()
+ asyncio.set_event_loop(loop)
+
+ return loop.run_until_complete(
+ self.scrape(
+ {"card_number": kwargs["card_number"], "pin": kwargs["pin"],}
+ )
+ )
diff --git a/requirements.txt b/requirements.txt
index 6669cb4..7795227 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,4 +9,5 @@ requests
tqdm
lxml
selenium
+pyppeteer
chromedriver-binary