Python to Playstation: Tracking PS5 Stocks with AWS Lambda

Profile picture
Lamarr
15 min readNovember 30, 2020

The PS5 is here! Let's go get one...

ps5_sold_outEvery website right now

They're All Sold Out?

With high demand and limited supply, consoles are selling out within seconds of becoming available. This shortage is amplified by resellers buying dozens and pricing them at a 200% markup. As my friends and I struggled to get our hands on one, I decided to tackle this challenge by building a bot to monitor supplies and notify us when PS5s were available. In this blog, I’ll walk you through how I used Python, Selenium, and AWS Lambda to get this done.

How It Started

We were all frantically checking websites like Best Buy, GameStop, and Target. These retailers show the console as out of stock but allow you to subscribe to their "stock alerts". The problem with these is by the time they send these notifications, the consoles are long gone.

Everyone who has managed to secure a console so far constantly checks the page throughout the day, hoping that they will stumble upon the magical "Add To Cart" button. People have been doing this dozens of times a day for weeks, so after checking with XKCD, I concluded that this is a task worth automating.

XKCD_Automate_tableXKCD: Is It Worth the Time?

Check PS5 Stock Manually

Before we start writing the code or working on deployment, let’s understand how we manually check for PS5 stock. This involves checking different retailers, each with their own quirks, and then notifying our friends if we find any in stock. Let’s walk through an example using Best Buy.

Steps

 

  1. Navigate to the exact link for the PS5.
  2. Check the add to cart button. At Best Buy, it will either say “Unavailable Nearby” or “Add To Cart”.
  3. If it says “Add To Cart”, let all of our friends know so they can buy them before they run out.

best-buy-out-of-stockPS5 - out of stock

Now that we know how to do the process manually, let's automate it.

Checking For Stock Automatically

Tools

We'll use a few different tools to automate this.

  • AWS Lambda: To run our bot all the time for cheap
  • Python: The best programming language 😄
  • Selenium: Library for browser automation
  • Amazon SNS: A service we'll use to text everyone when consoles are available
  • Terraform: Deploy all our resources to avoid clickity clicking in the console

Writing The Code

We can use selenium to automate the first two steps. We'll need to find a good way to identify the Add To Cart button. With selenium, it's often a good idea to use an elements ID to select it if it's available. In this case, we can identify the element with the ID fulfillment-add-to-cart-button-8739818.

best-buy-add-to-cart

Here's some code that checks for the Add To Cart button:

1from selenium import webdriver 2from selenium.webdriver.common.by import By 3 4def is_stock_available(): 5 driver = webdriver.Chrome() 6 driver.get("https://www.bestbuy.com/site/sony-playstation-5-console-white/6523167.p?skuId=6523167") 7 add_to_cart = driver.find_element(By.ID, "fulfillment-add-to-cart-button-8739818") 8 if add_to_cart.text == "Add To Cart": 9 return True 10 return False 11 12print(is_stock_available())

For step 3, we need a service to send text messages to our friends. Since we plan to use AWS Lambda for deployment, let’s use AWS SNS. After enrolling all desired phone numbers, the notification code is simple:

1def notify(key, link): 2 sns = boto3.client('sns') 3 sns.publish( 4 TopicArn=os.environ['SNS_TOPIC'], 5 Message=f'PS5 is in stock from {key} at {link} !', 6 )

Putting It All Together

Now that we have automated all the steps, we’ll need some driver code and parameterize the link and the add to cart selector so that it’ll work for multiple retailers, not just Best Buy.

Here’s an example config file for Best Buy and GameStop:

1{ 2 "bestbuy": { 3 "link": "https://www.bestbuy.com/site/sony-playstation-5-console-white/6523167.p?skuId=6523167", 4 "selector": "//*[contains(@id, 'fulfillment-add-to-cart')]", 5 "button_text": "Add to Cart" 6 }, 7 "gamestop: { 8 "link": "https://www.gamestop.com/consoles-hardware/playstation-5/consoles/products/sony-playstation-5-slim-console-digital-edition/402378.html", 9 "selector": "//*[@id='add-to-cart-buttons']", 10 "button_text": "Add to Cart" 11 }, 12 ... 13}

And our complete lambda code.

1from selenium import webdriver 2from selenium.webdriver.common.by import By 3import json 4import boto3 5import os 6 7def notify(retailer, link): 8 sns = boto3.client('sns') 9 sns.publish( 10 TopicArn=os.environ['SNS_TOPIC'], 11 Message=f'PS5 is in stock from {retailer} at {link}!', 12 ) 13 14def is_stock_available(store_config, local_execution): 15 driver = get_driver(local_execution) 16 driver.get(store_config['link']) 17 add_to_cart = driver.find_element(By.XPATH, store_config['selector']) 18 if add_to_cart.text != store_config["button_text"]: 19 return True 20 return False 21 22def lambda_handler(event, context): 23 retailer = event['retailer'] 24 print(f"Running notifier for: {retailer}") 25 store_config = json.load(open("store_config.json")) 26 27 local_execution = context == {} 28 in_stock = is_stock_available(store_config, local_execution) 29 if in_stock: 30 notify(retailer, store_config['link']) 31 32if __name__ == "__main__": 33 lambda_handler({"retailer": "bestbuy"}, {})

Now, we can run this code locally to alert us if there are any consoles available. However, we want this to run all the time and for multiple retailers. To do this, we’ll deploy our code to AWS Lambda and use AWS EventBridge to trigger it for each retailer every 5 minutes.

Deployment

Here’s what our setup will look like:

ps5_archNotifier Architecture Diagram

Setup Selenium in Lambda

Check out this quick blog for help setting up a lambda layer so that you can easily use selenium without repetitive setup.

Driving with Selenium

Now that we have Selenium set up in Lambda as a layer, we can modify our code a bit to use the driver that we have packaged in our layer when running in AWS.

1def get_driver(local): 2 driver = None 3 if local: 4 driver = webdriver.Chrome() 5 else: 6 # We want to import it from the layer when running in lambda 7 from headless_chrome import create_driver 8 driver = create_driver() 9 return driver

Setup Eventbridge Trigger(s)

Click “Add Trigger” and add an “EventBridge” trigger with a rate of 5 minutes. Then, add an input with the key of each retailer in the store_config.json from earlier.

That’s it! Now the Lambda will be invoked every 5 minutes for each retailer. If it detects any PS5s in stock, it’ll use SNS to text every number you provided when you set up your SNS topic.

Why Not Take It Further?

One topic worth mentioning is why not take the next step and automate the checkout process? Well, there are some philosophical and technical challenges to understand.

The main philosophical objection is that takes us into the same direction as the people who are causing supply to be limited in the first place.

There are also technical challenges. Many of these retailers deal with limited supply releases often and have some bot protections in place. These include things like signature detections, CAPTCHAs, and IP restrictions. There are ways around each of these that I may have explored 👀 for example using Hidden Selenium, programmatically changing your browser agents, and using VPNs in Lambda. So, even with the technical challenges, it is possible to continue with this approach through checkout.

However, with this approach you must have selenium enter in your card info, address, potentially deal with crashes, etc. But, if you're notified and complete checkout manually instead, all of these details are already saved on your account so you'll complete checkout faster than a bot.

Gonna Go Play Games Now 👋🏽

Building this bot was fun and allowed me to explore the capabilities of Python, Selenium, and AWS Lambda, and apply them to solve a real-world problem. By automating the process of checking for PS5 stock and notifying my friends, we were all able to get a console!

I hope this blog inspires you to explore automation for your own challenges and projects. If you have any questions or suggestions, feel free to reach out. Happy coding, and good luck getting a PS5!

See the full code for this project on my GitHub