nvidia website gives false positives
samuelm2 opened this issue · 13 comments
recently the nvidia website started giving false positives. I haven't had time to figure out a way around these false positives, so if someone has time to figure it out and wants to submit a PR that'd be great
I was getting false positives on the 3080 search page, but am no longer when using main 3080 page on nvidia.
Picking up a false positive on best buy after the recent restock. cart.svg doesn't appear in the html.
If that's replaced with the css classes for the active button it seems to work correctly again:
"btn btn-primary btn-sm btn-block btn-leading-ficon add-to-cart-button"
One quite robust way could be to read directly from their store API.
Example below (5438481700 is the product ID for 3080)
GET https://api-prod.nvidia.com/direct-sales-shop/DR/products/en_us/USD/5438481700
{
"products": {
"product": [
{
"id": 5438481700,
"name": "NVIDIA GEFORCE RTX 3080 - US",
"displayName": "NVIDIA GEFORCE RTX 3080",
"sku": "900-1G133-2530-000",
"displayableProduct": "false",
"manufacturerPartNumber": "900-1G133-2530-000",
"maximumQuantity": 1,
"thumbnailImage": "https://drh1.img.digitalriver.com/DRHM/Storefront/Company/nvidia/images/product/thumbnail/geforce-rtx-3080-shop-thumbnail-100x100.png",
"customAttributes": {
"attribute": [
{
"name": "paypalOff",
"type": "Boolean",
"value": "false"
},
{
"name": "nonSolr",
"type": "Boolean",
"value": "false"
},
{
"name": "isGFNBundle",
"type": "Boolean",
"value": "false"
},
{
"name": "needsRestrictedShippingOption",
"type": "Boolean",
"value": "false"
},
{
"name": "shippingCountries",
"type": "String",
"value": "US,CA,PR,VI"
},
{
"name": "shipmentAgreement",
"type": "Boolean",
"value": "false"
},
{
"name": "CategorySelection",
"type": "String",
"value": "Other"
},
{
"name": "usps",
"type": "String",
"value": "false"
},
{
"name": "additionalCartMessage",
"type": "String",
"value": "Limit 1 per customer"
},
{
"name": "isGFN",
"type": "Boolean",
"value": "false"
},
{
"name": "preorderOverride",
"type": "Boolean",
"value": "false"
},
{
"name": "originalIsViewable",
"type": "Boolean",
"value": "false"
},
{
"name": "clonedFromStaging",
"type": "Boolean",
"value": "false"
},
{
"name": "landedCost",
"type": "Boolean",
"value": "false"
},
{
"name": "originalIsOrderable",
"type": "Boolean",
"value": "true"
},
{
"name": "length",
"type": "Quantity",
"value": "357.000 mm"
},
{
"name": "upc",
"type": "String",
"value": "812674024509"
},
{
"name": "weight",
"type": "Quantity",
"value": "2.500 kg"
},
{
"name": "disablePayPal",
"type": "Boolean",
"value": "true"
},
{
"name": "hideInfo",
"type": "Boolean",
"value": "false"
},
{
"name": "hideQty",
"type": "Boolean",
"value": "false"
},
{
"name": "nvidiaPVDecoder",
"type": "String",
"value": "PureVideo Decoder Bronze"
},
{
"name": "width",
"type": "Quantity",
"value": "166.000 mm"
},
{
"name": "ProductDescription",
"type": "String",
"value": "GeForce"
},
{
"name": "privateStoreOnly",
"type": "Boolean",
"value": "false"
},
{
"name": "shipsInTimeFrameOverrideEnabled",
"type": "Boolean",
"value": "false"
}
]
},
"pricing": {
"uri": "https://dispatch-nvidia.digitalriver.com/v1/shoppers/me/products/5438481700/pricing",
"listPrice": {
"currency": "USD",
"value": 699
},
"listPriceWithQuantity": {
"currency": "USD",
"value": 699
},
"salePriceWithQuantity": {
"currency": "USD",
"value": 699
},
"formattedListPrice": "$699.00",
"formattedListPriceWithQuantity": "$699.00",
"formattedSalePriceWithQuantity": "$699.00",
"totalDiscountWithQuantity": {
"currency": "USD",
"value": 0
},
"formattedTotalDiscountWithQuantity": "$0.00",
"listPriceIncludesTax": "false",
"tax": {
"vatPercentage": 0
},
"feePricing": {
"salePriceWithFeesAndQuantity": {
"currency": "USD",
"value": 699
},
"formattedSalePriceWithFeesAndQuantity": "$699.00"
}
},
"inventoryStatus": {
"uri": "https://dispatch-nvidia.digitalriver.com/v1/shoppers/me/products/5438481700/inventory-status",
"availableQuantityIsEstimated": "false",
"productIsInStock": "true",
"productIsAllowsBackorders": "false",
"productIsTracked": "true",
"requestedQuantityAvailable": "true",
"status": "PRODUCT_INVENTORY_OUT_OF_STOCK",
"statusIsEstimated": "false"
},
"relatedProducts": [
{
"id": 5440852400,
"name": "GeForce NOW 1 Year Membership (RTX 30 Series Offer)",
"image": "https://drh1.img.digitalriver.com/DRHM/Storefront/Company/nvidia/images/product/thumbnail/geforce-rtx-bundle-geforce-now-thumbnail-100x100.png"
},
{
"id": 5440851900,
"name": "Watch Dogs: Legion",
"image": "https://drh1.img.digitalriver.com/DRHM/Storefront/Company/nvidia/images/product/thumbnail/geforce-rtx-bundle-watch-dogs-legion-thumbnail-100x100.png"
}
],
"viewStyle": "ampere"
}
]
}
}
The interesting bit there is this:
{
"inventoryStatus":{
"uri":"https://dispatch-nvidia.digitalriver.com/v1/shoppers/me/products/5438481700/inventory-status",
"availableQuantityIsEstimated":"false",
"productIsInStock":"true",
"productIsAllowsBackorders":"false",
"productIsTracked":"true",
"requestedQuantityAvailable":"true",
"status":"PRODUCT_INVENTORY_OUT_OF_STOCK",
"statusIsEstimated":"false"
}
}
Specifically:
{
"status":"PRODUCT_INVENTORY_OUT_OF_STOCK",
}
this is what I did to get around nvidia false positives. Not ideal but it seems to be working... for now. Above approach is miles better. @EKMN how do I run GET in python? Thanks
def got_stock(url, info):
try:
if info[2]:
html = seleniumGet(url)
else:
html = urllibGet(url)
except Exception as e:
print("Connection failed...")
print(e)
return False
keyWord = info[0]
alertOnFound = info[1]
index = html.find(keyWord)
index = html.upper().find(keyWord.upper())
gotStock=False
if alertOnFound and index != -1 and "show-out-of-stock" not in html[index-150:index+150]:
print(index)
print(html[index-150:index+150])
#alert(url)
gotStock = True
elif not alertOnFound and index == -1:
#print(html[index-50:index+50])
gotStock = True
return gotStock
def main():
numSearches = 0
while True:
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
print("Starting search {} at {}".format(numSearches, current_time))
numSearches += 1
for url, info in urlKeyWords.items():
print("\tChecking {}...".format(info[3]))
if got_stock(url, info):
print("........confirming in stock signal")
baseSleepAmt = 1
totalSleep = baseSleepAmt + random.uniform(0, 4)
time.sleep(totalSleep)
if got_stock(url, info):
alert(url)
baseSleepAmt = 1
totalSleep = baseSleepAmt + random.uniform(6, 20)
# print("Sleeping for {} seconds".format(totalSleep))
time.sleep(totalSleep)
if __name__ == '__main__':
main()
how often are you guys getting them?
under def seleniumGet i added:
driver.set_page_load_timeout(60)
so far so good. so it either helped, or i've just been extremely lucky.
i've also adjusted the sleep timings as i didn't want to get IP banned by nvidia/bbuy etc.
baseSleepAmt = 30
totalSleep = baseSleepAmt + random.uniform(0, 10)
@dereckhall
bestbuy - havent gotten any yet
nvidia - was getting it on every 10-ish request. Now it was running for 2 hours no issues.
Good point on ban, would suck to also switch vpn every now and then. Might increase wait time to be a little longer
this is what I did to get around nvidia false positives. Not ideal but it seems to be working... for now. Above approach is miles better. @EKMN how do I run GET in python? Thanks
def got_stock(url, info): try: if info[2]: html = seleniumGet(url) else: html = urllibGet(url) except Exception as e: print("Connection failed...") print(e) return False keyWord = info[0] alertOnFound = info[1] index = html.find(keyWord) index = html.upper().find(keyWord.upper()) gotStock=False if alertOnFound and index != -1 and "show-out-of-stock" not in html[index-150:index+150]: print(index) print(html[index-150:index+150]) #alert(url) gotStock = True elif not alertOnFound and index == -1: #print(html[index-50:index+50]) gotStock = True return gotStock def main(): numSearches = 0 while True: now = datetime.now() current_time = now.strftime("%H:%M:%S") print("Starting search {} at {}".format(numSearches, current_time)) numSearches += 1 for url, info in urlKeyWords.items(): print("\tChecking {}...".format(info[3])) if got_stock(url, info): print("........confirming in stock signal") baseSleepAmt = 1 totalSleep = baseSleepAmt + random.uniform(0, 4) time.sleep(totalSleep) if got_stock(url, info): alert(url) baseSleepAmt = 1 totalSleep = baseSleepAmt + random.uniform(6, 20) # print("Sleeping for {} seconds".format(totalSleep)) time.sleep(totalSleep) if __name__ == '__main__': main()
You can basically use any request library that makes a GET request (usually the default option). Then parse the JSON response and evaluate the key-value pair that I highlighted.
Heres a basic example - not sure what possible status codes there are though.
response = requests.get("https://api-prod.nvidia.com/direct-sales-shop/DR/products/en_us/USD/5438481700")
item = response.json()
print(item['products']['product'][0]['inventoryStatus']['status'])
if item['products']['product'][0]['inventoryStatus']['status'] != "PRODUCT_INVENTORY_OUT_OF_STOCK":
alert("Nvidia API")
Try this:
def got_stock(url, info):
try:
if info[2]:
html = seleniumGet(url)
else:
html = urllibGet(url)
except Exception as e:
print("Connection failed...")
print(e)
return False
keyWord = info[0]
alertOnFound = info[1]
index = html.find(keyWord)
index = html.upper().find(keyWord.upper())
gotStock=False
if alertOnFound and index != -1 and "show-out-of-stock" not in html[index-150:index+150]:
print(index)
print(html[index-150:index+150])
#alert(url)
gotStock = True
elif not alertOnFound and index == -1:
#print(html[index-50:index+50])
gotStock = True
return gotStock
def check_nvidia_api():
response = requests.get("https://api-prod.nvidia.com/direct-sales-shop/DR/products/en_us/USD/5438481700")
item = response.json()
print(item['products']['product'][0]['inventoryStatus']['status'])
if item['products']['product'][0]['inventoryStatus']['status'] != "PRODUCT_INVENTORY_OUT_OF_STOCK":
return True
else:
return False
def main():
numSearches = 0
toast.show_toast("Hello World!!!",
"Python is 10 seconds awsm!",
icon_path="icon.ico",
duration=10)
while True:
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
print("Starting search {} at {}".format(numSearches, current_time))
numSearches += 1
for url, info in urlKeyWords.items():
print("\tChecking {}...".format(info[3]))
if got_stock(url, info):
print("........confirming in stock signal")
baseSleepAmt = 1
totalSleep = baseSleepAmt + random.uniform(2, 10)
time.sleep(totalSleep)
if got_stock(url, info):
if info[3] == "Nvidia":
if check_nvidia_api():
alert(url)
else:
alert(url)
baseSleepAmt = 1
totalSleep = baseSleepAmt + random.uniform(2, 15)
# print("Sleeping for {} seconds".format(totalSleep))
time.sleep(totalSleep)
if __name__ == '__main__':
main()
@ItsCalebJones i ended up at the same code, just moved
else:
alert(url)
to make it for if info[4] == "Nvidia": statement
That was a derp ;)
Submitted #5 , should handle grabbing nvidia stuff by API instead of by html, and has a few other QOL changes.
Gonna close this out. Thanks for ironing this out, all!