Created
March 25, 2025 06:22
-
-
Save anchetaWern/2d5220d557c08a55b12bbd599bd19125 to your computer and use it in GitHub Desktop.
profitl seller stock fix
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useRef, useEffect, useState } from "react"; | |
import { View, StyleSheet } from "react-native"; | |
import { WebView } from "react-native-webview"; | |
import AlertBox from './AlertBox'; | |
import LabelText from './LabelText'; | |
const injectScript = ` | |
const timeout = 1000 * 180; | |
async function getAmazonSellerStockData(scrapedASIN) { | |
const inventory = []; | |
const amazonRootElement = document.getElementById("qid"); | |
const qid = amazonRootElement ? amazonRootElement.value : ''; | |
const domain = window.location.hostname; | |
async function getInventory(asin, page = 1) { | |
const productScrapeUrl = | |
page === 1 | |
? "https://" + domain + "/gp/product/ajax/ref=aod_f_new?asin=" + asin + "&m=&qid=&smid=&sourcecustomerorglistid=&sourcecustomerorglistitemid=&sr=&pc=dp&experienceId=aodAjaxMain" | |
: "https://" + domain + "/gp/product/ajax/ref=aod_page_" + page + "?asin=" + asin + "&m=&qid=" + qid + "&smid=&sourcecustomerorglistid=&sourcecustomerorglistitemid=&sr=8-1&pc=dp&isonlyrenderofferlist=true&pageno=" + page + "&experienceId=aodAjaxMain"; | |
const response = await fetch(productScrapeUrl); | |
const cartPageText = await response.text(); | |
const parser = new DOMParser(); | |
const cartPageDoc = parser.parseFromString(cartPageText, "text/html"); | |
if (page === 1) { | |
const product = cartPageDoc.querySelector(['[id="aod-pinned-offer"]']); | |
if (product) { | |
const stockData = extractStock(product); | |
if (stockData) { | |
inventory.push(stockData); | |
} | |
} | |
} | |
const offers = cartPageDoc.querySelectorAll('.aod-other-offer-block'); | |
let stopScraping = false; | |
for (const offer of offers) { | |
const stockData = extractStock(offer); | |
const existing = inventory.filter((itm) => { | |
return stockData.seller_id === itm.seller_id && stockData.price === itm.price && stockData.condition === itm.condition; | |
}); | |
if (existing && existing.length > 0) { | |
stopScraping = true; | |
} else { | |
inventory.push(stockData); | |
} | |
} | |
if (offers.length === 10 && stopScraping === false) { | |
page++; | |
await getInventory(asin, page); | |
} | |
} | |
const extractStock = function (element) { | |
const sellerLink = element.querySelector('[id="aod-offer-soldBy"] a'); | |
const soldBy = element | |
.querySelector('[id="aod-offer-soldBy"]'); | |
if (soldBy) { | |
let sellerId = ''; | |
if (sellerLink) { | |
const sellerLinkHref = sellerLink.getAttribute('href'); | |
const sellerLinkSearchParams = new URLSearchParams(sellerLinkHref); | |
sellerId = sellerLinkSearchParams.get('seller'); | |
} | |
const sellerSpan = soldBy.firstElementChild.firstElementChild.lastElementChild.querySelector("span"); | |
const seller = sellerLink | |
? sellerLink.textContent.trim() | |
: sellerSpan.textContent.trim(); | |
let condition = element | |
.querySelector('[id="aod-offer-heading"] h4'); | |
if (!condition) { | |
condition = element | |
.querySelector('[id="aod-offer-heading"]'); | |
} | |
if (condition) { | |
condition = condition.textContent.trim() | |
.replace(/\s+/g, " "); | |
} | |
let price = element.querySelector('[class="a-offscreen"]').textContent.substr(1).trim(); | |
if (!parseFloat(price)) { | |
price = element.querySelector('[class="aok-offscreen"]').textContent.trim().substr(1); | |
} | |
const quantity = | |
element.querySelectorAll('[id="aod-qty-dropdown-scroller"] > span').length + | |
1; | |
let sellerType = element | |
.querySelector('[id="aod-offer-shipsFrom"]>div') | |
.firstElementChild.lastElementChild.querySelector("span") | |
.textContent.trim(); | |
let type = | |
sellerType === "Amazon" || sellerType === "Amazon.com" | |
? "FBA" | |
: "FBM"; | |
const rating = element.querySelector( | |
'[id="seller-rating-count-{iter}"]>span' | |
); | |
let rating_count = null; | |
let rating_percentage = null; | |
if (rating) { | |
const ratingText = rating.innerHTML; | |
let currentNumber = ""; | |
const numbers = []; | |
for (let i = 0; i < ratingText.length; i++) { | |
const char = ratingText.charAt(i); | |
if (!isNaN(char)) { | |
currentNumber += char; | |
} else if (currentNumber) { | |
numbers.push(parseInt(currentNumber)); | |
currentNumber = ""; | |
} | |
} | |
if (currentNumber) { | |
numbers.push(parseInt(currentNumber)); | |
} | |
const trueNumbers = numbers.filter(num => !isNaN(num)); | |
if (trueNumbers) { | |
rating_count = Number(trueNumbers[0]); | |
rating_percentage = parseFloat(trueNumbers[1]); | |
} else { | |
rating_count = 1; | |
rating_percentage = ratingText; | |
} | |
} | |
if (seller === "Amazon" || seller === "Amazon.com") { | |
type = "AMZ"; | |
} | |
return { | |
'seller_name': seller, | |
'seller_id': sellerId, | |
'price': price, | |
'stocks': quantity, | |
'type': type, | |
'ratings_total': rating_count, | |
'ratings_percentage': rating_percentage, | |
'condition': condition, | |
'domain': domain, | |
}; | |
} | |
}; | |
await getInventory(scrapedASIN); | |
const newOffers = inventory.filter(n => n).filter((o) => o.condition === "New"); | |
return newOffers; | |
} | |
const executeScript = async () => { | |
document.querySelector('[data-action=show-all-offers-display] a').click(); | |
return new Promise(async (resolve, reject) => { | |
const scriptTimeout = setTimeout(() => { | |
reject(new Error('Script execution timed out')); | |
}, timeout); | |
window.addEventListener('message', async function(event) { | |
if (event.data && event.data.type === 'my-asin') { | |
const newOffers = await getAmazonSellerStockData(event.data.data); | |
clearTimeout(scriptTimeout); | |
resolve(JSON.stringify(newOffers)); | |
} | |
}); | |
}); | |
}; | |
Promise.race([ | |
executeScript(), | |
new Promise((resolve, reject) => { | |
setTimeout(() => { | |
reject(new Error('Script execution timed out')); | |
}, timeout); | |
}), | |
]) | |
.then((result) => { | |
window.ReactNativeWebView.postMessage(JSON.stringify({ | |
type: 'success', | |
data: result | |
})); | |
}) | |
.catch((error) => { | |
window.ReactNativeWebView.postMessage(JSON.stringify({ | |
type: 'error' | |
})); | |
}); | |
`; | |
const AmazonProductPageWebView = ({ | |
asin, | |
setAmazonData, | |
setAmazonStocksData, | |
setAmazonDataLoading, | |
amazonWebsite, | |
setAmazonOffers, | |
setFbaOffers, | |
setFbmOffers, | |
cacheSellerStock, | |
}) => { | |
const webViewRef = useRef(null); | |
const handleWebViewLoad = () => { | |
const data = { | |
'type': 'my-asin', | |
'data': asin, | |
}; | |
const theData = JSON.stringify(data); | |
const messageToInject = `window.postMessage(${theData})`; | |
if (webViewRef && webViewRef.current) { | |
webViewRef.current.injectJavaScript(messageToInject); | |
} | |
}; | |
const handleUnmount = () => { | |
webViewRef.current = null; | |
}; | |
useEffect(() => { | |
return () => { | |
handleUnmount(); | |
}; | |
}, []); | |
const handleWebViewMessage = event => { | |
const data = JSON.parse(event.nativeEvent.data); | |
if (data && data.type === 'error') { | |
setAmazonDataLoading(false); | |
setAmazonStocksData([]); | |
setAlertVisible(true); | |
setAlertText('Something went wrong. Please try again.'); | |
} | |
if (data && data.type === 'success' && data.data) { | |
const theData = JSON.parse(data.data); | |
if (theData && theData.length) { | |
setAmazonData(theData); | |
console.log('========'); | |
console.log('SELLER STOCK'); | |
console.log(JSON.stringify(theData)); | |
console.log('========'); | |
cacheSellerStock(asin, amazonWebsite, theData); | |
const stocksData = theData.map((itm) => { | |
return { | |
'stocks': itm.stocks, | |
'type': itm.type, | |
} | |
}); | |
const amazonOffers = stocksData.filter(itm => itm.type === 'AMZ'); | |
const fbaOffers = stocksData.filter(itm => itm.type === 'FBA'); | |
const fbmOffers = stocksData.filter(itm => itm.type === 'FBM'); | |
setAmazonOffers(amazonOffers.length); | |
setFbaOffers(fbaOffers.length); | |
setFbmOffers(fbmOffers.length); | |
setAmazonDataLoading(false); | |
setAmazonStocksData(stocksData); | |
setAlertVisible(false); | |
setAlertText(''); | |
} else { | |
setAmazonDataLoading(false); | |
setAmazonStocksData([]); | |
setAlertVisible(true); | |
setAlertText(' No sellers found.'); | |
} | |
} else { | |
setAmazonDataLoading(false); | |
setAmazonStocksData([]); | |
setAlertVisible(true); | |
setAlertText(' No sellers found.'); | |
} | |
}; | |
const onError = () => { | |
setAmazonDataLoading(false); | |
setAmazonStocksData([]); | |
setAlertVisible(true); | |
setAlertText(' No sellers found.'); | |
} | |
const pageUrl = `https://www.amazon.${amazonWebsite}/dp/${asin}`; | |
const source = { | |
uri: pageUrl, | |
headers: { | |
'Cookie': 'session-id=262-0595900-4132742; i18n-prefs=GBP; ubid-acbuk=258-1963667-8125912; av-timezone=Asia/Manila; lc-acbuk=en_GB; session-id-time=2082787201l; sp-cdn="L5Z9:PH"; session-token=qUFm3afn6iSXDwaDVtq1H5/tjRi6f9lyepL1Kpxcr1fgB7pkyFwiSH8BIE17oBaGF7ZxQ47MyLcuVmMLd2JMrEHIA1hXBvEbKQx1xN+qJ/d6onImc5AXZhpxx0BGbHzifbiiys34xLAHInBjYRbe4VO9xBiuyt7bXlE/6Vu14JFguZQqKNW5plD8EHVSit7VfiWOfH5whI2J10egIjt2saLgbqz0Cr2Civ8slaz2opo8wO6t9uFOjMMT27saeSeEmOMOawh4Jlba4ReOU6oK/XrExMnP0QlrgMXvKwaCziCf2rBsq6g64fPvtBD6xzYvqngDoM8/RuT8orL6jTgw+94wZD7Oxak8gxjtJy/K6CE=; csm-hit=adb:adblk_yes&t:1693301769810&tb:SE46KWFE07QB5H7CKR5G+s-HS9QEFXRFXZ1SWPX5A6V|1693301769807' | |
} | |
}; | |
const [alertVisible, setAlertVisible] = useState(false); | |
const [alertText, setAlertText] = useState(''); | |
return ( | |
<View> | |
{ | |
alertVisible && | |
<View style={{marginTop: 10}}> | |
<AlertBox type="warning" dismissable toggle={setAlertVisible}> | |
<LabelText color="valueText"> | |
{alertText} | |
</LabelText> | |
</AlertBox> | |
</View> | |
} | |
<WebView | |
source={source} | |
javaScriptEnabled={true} | |
cacheEnabled={false} | |
incognito={true} | |
cacheMode={"LOAD_NO_CACHE"} | |
onMessage={handleWebViewMessage} | |
injectedJavaScript={injectScript} | |
onLoad={handleWebViewLoad} | |
onError={onError} | |
ref={webViewRef} | |
style={{ opacity: 0 }} | |
/> | |
</View> | |
); | |
}; | |
const styles = StyleSheet.create({ | |
normalPadding: { | |
padding: 10, | |
}, | |
}); | |
export default AmazonProductPageWebView; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment