Shoppingscraper Dynamic Price scraper

December 17, 2023
Google Ads

ShoppingScraper is een krachtige en gebruiksvriendelijke scraper, speciaal ontwikkeld om jou te helpen geld te besparen en slimmer de campagnes in te stellen. Dankzij deze SaaS-oplossing kun je prijsinformatie verzamelen van een breed scala aan producten en leveranciers door simpelweg de EAN-code in te voeren [...]

ShoppingScraper is een krachtige en gebruiksvriendelijke scraper, speciaal ontwikkeld om jou te helpen geld te besparen en slimmer de campagnes in te stellen. Dankzij deze SaaS-oplossing kun je prijsinformatie verzamelen van een breed scala aan producten en leveranciers door simpelweg de EAN-code in te voeren. 

Je kunt niet alleen EAN-nummers scrapen, maar ook zoekwoorden. Zo heb je snel inzicht in welke concurrenten met welke producten en prijzen adverteren op zoekwoordniveau. 

Soms is het beter om een dynamic pricing strategie te hanteren voor zoekwoorden waarop je gevonden wilt worden. Dit geldt vooral voor generieke zoekwoorden, zoals ‘Baardolie’. Daar heb je heel veel variaties in. Waar eigenlijk niet specifiek naar een EAN gezocht wordt. Je hebt hier heel veel verschillende aanbieders van ‘baardolie’, maar allemaal verschillende merken (producten) en dus EAN’s. 

Voor elektronische producten bijvoorbeeld, daar is het weer slimmer om op EAN nummer te scrapen. Ik heb daarom twee type scrapers ontwikkeld die geautomatiseerd de prijsdata ophaalt met de Shoppingscraper API. 
 


Je kunt, indien je dat zou willen, een prijsrange opgeven en de concurrenten. In het script geef je jouw Merchant Centre naam aan.

  1. Door het geven van een prijsrange heb je minder outliers.
  2. Mediaan wordt berekend op basis van alle prijsdata uit de veiling (maximum 60).
  3. Je geeft in een ander tabblad de concurrenten door.
  4. Met de Shoppingscraper API kan je de prijsdata ophalen.
  5. Je kunt een trigger aanmaken die elke dag de prijsdata ophaalt. Of alleen bij een leeg veld.
     
const ss = SpreadsheetApp.getActiveSpreadsheet()
const sheet = ss.getSheetByName('Zoekwoorden')
const max_retries = 5;




const competitors = ss.getSheetByName('Concurrenten')
const new_sheet = ss.getSheetByName('Price Benchmark - Keywords')


function onOpen() {
 var ui = SpreadsheetApp.getUi();
 // Create a custom menu with a name and an item
 ui.createMenu('Run Script')
   .addItem('Start', 'runScriptNew') // 'Run My Script' is the menu item, 'myFunction' is the function to run
   .addToUi(); // Add the menu to the user interface
}




function runScriptNew() {
 fetchShoppingDataNew();
}


function getKeywordsNew() {
 return new_sheet.getDataRange().getValues();
}


function insertData(arrayData) {
 var range = sheet.getRange(1, 1, arrayData.length, arrayData[0].length);
 sheet.clear();
 Utilities.sleep(1000)
 range.setValues(arrayData);
}




function fetchShoppingDataNew() {


 var keywords = getKeywordsNew()
 console.log(keywords.length)
 for (var i = 1; i < keywords.length; i++) {
   var v = keywords[i]
   console.log('Range => ', v[0], '  =  ', 'keyword => ', v[1])
   if (v[2]) {
     console.log('Already Processed')
     continue
   }
   if (!v[1]) {
     console.log('Empty row found')
     continue
   }


   var temp = [];
   var url = "https://api.shoppingscraper.com/search/googleshopping/nl/?keyword=" + v[1] + "&api_key=0c81f1b0d5b24eXXXXXXcf20b5b86e12&page=1&limit=10";


   var options = {
     method: "GET",
     headers: {
       "Content-Type": "application/json",
     }
   };


   var retries = 0;
   while (retries < max_retries) {
     Utilities.sleep(retries * 1000)
     var response = UrlFetchApp.fetch(url, options);
     var json = response.getContentText();
     var data = JSON.parse(json);
     var result = data['shoppingscraper'] ? data['shoppingscraper']['results'] : [];


     if (result.length > 0) {
       // console.log('API call successful');
       break;
     } else {
       console.log('API call failed, retrying...');
       retries++;
     }


   }
   if (retries === max_retries) {
     console.log('Max retries reached, unable to get data from API');
     // main_dataset.push([v[0], v[1], '', '', '', '', '', '', '', '', '', '', '', '', ''])
     new_sheet.getRange(i + 1, 1, 1, 2).setValues([[v[0], v[1]]]);
   }


   else {
     console.log('result.length => ', result.length)
     result.forEach((v) => {
       var seller = v['offers'][0]['seller']
       var totalprice = v['offers'][0]['totalPrice']
       var link = v['offers'][0]['link']


       temp.push({
         seller: seller,
         totalprice: totalprice,
         link: link


       })
     })


     var output = processDataNew(v[0], v[1], temp)
     console.log('output lenth ', output)
     console.log('i => ', i)
     new_sheet.getRange(i + 1, 1, 1, output.length).setValues([output]);
   }
 }
}


function processDataNew(range, keyword, items) {


 // Extract min and max values from the range string
 let [min, max] = range.split(' - ').map(Number);


 // Use filter to create a new array containing only objects within the range
 let array = items.filter(obj => obj.totalprice >= min && obj.totalprice <= max);


 console.log(array);


 let arrayOfSellerNames = competitors.getDataRange().getValues(); // Note: seller names are in lowercase
 let flatArrayOfSellerNames = arrayOfSellerNames.flat().map(name => name.toLowerCase());
 let filteredArray = array.filter(obj => flatArrayOfSellerNames.includes(obj.seller.toLowerCase()));
 console.log(filteredArray);


 let median;
 let output = [];




 filteredArray.sort((a, b) => a.totalprice - b.totalprice);
 const numValues = filteredArray.length;


 if (numValues === 0) {
   median = 0; // or any other appropriate value for an empty array
 } else if (numValues % 2 === 0) {
   const middle1 = filteredArray[numValues / 2 - 1];
   const middle2 = filteredArray[numValues / 2];
   median = (middle1.totalprice + middle2.totalprice) / 2;
 } else {
   median = filteredArray[Math.floor(numValues / 2)].totalprice;
 }
 output.push(range);
 output.push(keyword);
 output.push(median);


 var my_price = items.find(item => item.seller.toLowerCase().includes('zaza woods nl'));


 if (my_price) {
   output.push(my_price.seller);
   output.push(my_price.totalprice)
 }
 else {
   console.log('my price not found in page 1, now searching in page 2 keyword is => ', keyword)
   my_price = fetchMissing(keyword, 2)
   if (my_price) {
     output.push(my_price.seller);
     output.push(my_price.totalprice)
   }
   else {
     console.log('my price not found in page 2, now searching in page 3 keyword is => ', keyword)
     my_price = fetchMissing(keyword, 3)
     if (my_price) {
       output.push(my_price.seller);
       output.push(my_price.totalprice)
     }
     else {
       console.log('my price not found in page 3, returning. keyword was => ', keyword)
       output.push('Zaza Woods NL');
       output.push('not found')
     }
   }


 }
 var ros = 'https://www.google.com/search?channel=fs&client=ubuntu&q=eng+to+urdu'


 filteredArray.forEach(item => {
   output.push('=HYPERLINK("' + item.link + '"; "' + item.seller + '")');
   output.push(item.totalprice);
 });


 return output
}


function insertDataIntoSheet(data) {


 new_sheet.clear();
 for (var i = 0; i < data.length; i++) {
   new_sheet.getRange(i + 1, 1, 1, data[i].length).setValues([data[i]]);
 }
}






function fetchMissing(keyword, pageNum) {
 var url = "https://api.shoppingscraper.com/search/googleshopping/nl/?keyword=" + keyword + "&api_key=0c81f1b0d5b24ee49d6fcf20b5b86e12&page=" + pageNum + "&limit=50";


 var options = {
   method: "GET",
   headers: {
     "Content-Type": "application/json",
   }
 };


 var retries = 0;
 while (retries < max_retries) {
   Utilities.sleep(retries * 1000)
   var response = UrlFetchApp.fetch(url, options);
   var json = response.getContentText();
   var data = JSON.parse(json);
   var result = data['shoppingscraper'] ? data['shoppingscraper']['results'] : [];


   if (result.length > 0) {
     // console.log('API call successful');
     break;
   } else {
     console.log('API call failed, retrying...');
     retries++;
   }


 }
 if (retries === max_retries) {
   console.log('Max retries reached, on page ', pageNum);
   return null;
 }
 else {
   console.log('page 2 result.length => ', result.length)
   var items = []
   result.forEach((v, i) => {
     var seller = v['offers'][0]['seller']
     var totalprice = v['offers'][0]['totalPrice']
     items.push({
       seller: seller,
       totalprice: totalprice
     })
   })
   const my_price = items.find(item => item.seller.toLowerCase().includes('retailerName'));
   return my_price
 }
}
jermaya leijen
Jermaya Leijen arrow icon

In de loop der jaren heb ik de liefde ontwikkeld voor automation, AI en data(analyse). Hoewel ik me altijd heb gericht op Google Ads, ben ik al geruime tijd betrokken bij uiteenlopende SEO-projecten. Ik heb mezelf Python en JavaScript aangeleerd om automation en data(verwerking) te kunnen integreren in zowel mijn eigen projecten als die van klanten, met als doel hen te ondersteunen bij het behalen van hun bedrijfs- en omzetdoelstellingen.

Cases Blogs Audit