Když nedávno kluci ze Skliku na PPC Campu oznámili, že produktové inzeráty (PI) se budou posouvat do top pozic, rozhodl jsem se na to připravit. Zkusil jsem tedy zrevidovat kampaně dle návodu v dokumentaci. Trápil jsem se s importy dva dny, ale pořád to nebylo ono.
Naštěstí se ozvala v diskusi Hanka Kobzová a poradila mi svůj skript na import produktových kampaní. Byl to krok vpřed, ale pořád mi přišlo, že je tam moc manuální práce. Tak jsem Hančin skript se Standovou pomocí, trošku upravil. Výsledek nyní předkládám.
Co tedy skript umí
- na základě pravidel vytvoří z feedu importní soubor pro PI
- dokáže kombinovat tagy z feedu custom_label_0, custom_label_1, categorytext, manufacturer, brand
- dokáže přidat do produktových skupin jen produkty skladem
- dokáže přidat do produktových skupin cenové rozsahy
- výsledkem je importní soubor s kampaní, která obsahuje sestavy s produktovými skupinami, dle zadaných kritérií
Nastavení
V konfigurační části je třeba nastavit tyto věci
feed_url – url vašeho feedu pro Zbozi.cz
mail – e-mail na který vám přijde výsledný importní soubor
campaignName – jméno vaší kampaně, já si držím v názvu podmínky, dle kterých skládám produktové skupiny, pro případný update tedy například: PLA | Kategorie/Výrobce/Sklad/Cena.
campaignBudget – rozpočet vaší kampaně, v rozhraní lze později změnit
shopID – shopID nejlépe zjistíte tak, že dáte v sekci Export kampaní vyexportovat stávající PI kampaň a hodnotu shopID tam najdete, vypadá nějak takto: zbozi:12345780:JMENOESHOPU.cz.
defaultCPC – výchozí hodnota ceny za proklik, pokud budete provádět update kampaně, doporučuji nechat hodnotu prázdnou, systém pak sám doplní u nově přidaných sestav CPC 8 Kč a vy si filtrem CPC=8 Kč a Zobrazení=0 snadno dohledáte nově doimportované sestavy.
Dále je pak třeba nastavit filtr, dle kterého skript na základě vašich podmínek vytvoří názvy sestav a produktové skupiny. Stačí u položek od řádku 19-26 nastavit hodnotu TRUE, na tagy z feedu, které chcete použít. Podmínkou je, že musí být splněny všechny podmínky TRUE, pokud je jedna prázdná, tak se sestava nevytvoří.
Na řádku 26 pak můžete v poli priceRange nastavit cenové rozsahy, dle kterých se sestavy dále segmentují. (POZOR! Pokud to s rozsahy přeženete, script se zpomalí a může přesáhhnout limit 30 minut a spadnout. Stačí generování dle rozsahů rozdělit do více souborů s méně rozsahy a vše se zrychlí.)
Výsledný soubor pak stáhněte z e-mailu, ideálně do něj vůbec nezasahujte a dejte importovat do Skliku. Dobře si zkontrolujte zda se import podařil a vše sedí!
Pozor také na práci s tagem CATEGORYTEXT. Pokud vám správce zbožáků změní jméno CATEGORYTEXT kvůli párování na Zbozi.cz, rozhodí vám tím kompletně sestavy a produktové skupiny. Vyřešil jsem to tím, že si originální hodnotu CATEGORYTEXT z webu zasílám do štítku. Obdoba google_product_category a product_type se prý neplánuje.
//Url config spreadsheet----------------------------------------------------------------------------------
//********************************************************************************************************
var feed_url = "FEEDURL"; // URL feedu pro Zbozi.cz
/*********************************************************************************************************
Skript: Sklik PI kampaně z feedu
Verze: 26.3. 2018
Poskládal: Karel Rujzl [rujzl.cz]
Vydatně pomáhal: Standa Jílek [standajilek.cz]
Prvotní myšlenka a základ scriptu: Hana Kobzová [hanakobzova.cz]
/********************************************************************************************************/
var mail = "email@email.cz"; //email kam přijde CSV s importem
// konfigurace kampaní
var campaignName = "1 | PLA | KategorieLabel/Výrobce/Sklad/Cena"; // název kampaně
var campaignBudget = "300"; // rozpočet kampaně
var shopID = "zbozi:123456:eshop.cz"; //ID shopu ze Zbozi.cz
var defaultCPC = "1"; // pokud provádíte update, nechte prázdné, import přidá k novým sestavám CPC 8 Kč
// konfigurace produktových skupin (sčítá se)
var readLabel0 = false; // filtruj dle labelu 0
var readLabel1 = true; // filtruj dle labelu 0
var readCategorytext = false; // filtruj dle kategorie
var readManufacturer = true; // filtruj dle výrobce
var readBrand = false; // filtruj dle brandu
var inStock = true; // filtruje jen zboží skladem
var enPrRange = true; // segmentace sestav dle ceny produktů, v následujícím řádku nadefinuj rozsahy
var priceRange = ["0-249","250-499","500-999","1000-1999","2000-2999","3000-999999"];
/********************************************************************************************************/
//KONEC RUČNÍHO CONFIGU DÁL NEŠAHAT
/********************************************************************************************************/
//vars
var feed_split = "";
var csv="";
var newData = [];
function main() {
try {
// nácuc a extrakce dat z feedu
var xml = (UrlFetchApp.fetch(feed_url).getContentText()).split(feed_split);
var data = [];
var sestava =[];
for (var i = 0; i < (xml.length - 1); i++)
{
//slozit produtk skupiny a adgroups dle podmínek
// název sestavy
var entities = [];
var rCategorytext="";
var rManufacturer="";
var rBrand="";
var makeName="ok";
// sjednotit načtení promných z feedu a ošetřit prázdné hotnoty manufacturer a další
if (readCategorytext==true) {
rCategorytext = parse(xml[i], "", " ");
if (rCategorytext=="") {
makeName="no";}
else {
rCategorytext = removeCdata (rCategorytext);
}
}
if (readManufacturer==true) {
rManufacturer = parse(xml[i], "", " ");
if (rManufacturer=="") {
makeName="no";}
else {
rManufacturer = removeCdata (rManufacturer);
}
}
if (readBrand==true) {
rBrand = parse(xml[i], "", " ");
if (rBrand=="") {
makeName="no";}
else {
rBrand = removeCdata (rBrand);
}
}
if (readLabel0==true) {
rLabel0 = parse(xml[i], "", " ");
if (rLabel0=="") {
makeName="no";}
else {
rLabel0 = removeCdata (rLabel0);
}
}
if (readLabel1==true) {
rLabel1 = parse(xml[i], "", " ");
if (rLabel1=="") {
makeName="no";}
else {
rLabel1 = removeCdata (rLabel1);
}
}
if(makeName=="ok"){
//pokud jsou dostupné všechny názvy udělej sestavu a produktovou skupinu
if (readLabel0==true) entities.push(rLabel0);
if (readLabel1==true) entities.push(rLabel1);
if (readCategorytext==true) entities.push(rCategorytext);
if (readManufacturer==true) entities.push(rManufacturer);
if (readBrand==true) entities.push(rBrand);
// název sestavy rozseká oddělovačem
var adgroupName = entities.join(" | ");
//Logger.log(entities);
// definice produktové skupiny
var prodGroup="*";
if (readLabel0==true) prodGroup += " / Custom label 0='" + rLabel0 + "'";
if (readLabel1==true) prodGroup += " / Custom label 1='" + rLabel1 + "'";
if (readCategorytext==true) prodGroup += " / Product type='" + rCategorytext + "'";
if (readManufacturer==true) prodGroup += " / Manufacturer='" + rManufacturer + "'";
if (readBrand==true) prodGroup += " / Brand='" + rBrand + "'";
if (inStock==true) prodGroup += " /Availability='in_stock'";
// přidá do pole řádek adgroupy a produktové skupiny
sestava.push({adgroup: adgroupName, productgroup: prodGroup});
}
}
} catch(err) {
Logger.log(err);
}
Logger.log("Neunikatnich sestav: " + sestava.length);
//slozit sestavu a produktovou skupinu
var flags = [], output = [], l = sestava.length, i;
for( iii=0; iii
//Url config spreadsheet----------------------------------------------------------------------------------
//********************************************************************************************************
var feed_url = "FEEDURL"; // URL feedu pro Zbozi.cz
/*********************************************************************************************************
Skript: Sklik PI kampaně z feedu
Verze: 26.3. 2018
Poskládal: Karel Rujzl [rujzl.cz]
Vydatně pomáhal: Standa Jílek [standajilek.cz]
Prvotní myšlenka a základ scriptu: Hana Kobzová [hanakobzova.cz]
/********************************************************************************************************/
var mail = "email@email.cz"; //email kam přijde CSV s importem
// konfigurace kampaní
var campaignName = "1 | PLA | KategorieLabel/Výrobce/Sklad/Cena"; // název kampaně
var campaignBudget = "300"; // rozpočet kampaně
var shopID = "zbozi:123456:eshop.cz"; //ID shopu ze Zbozi.cz
var defaultCPC = "1"; // pokud provádíte update, nechte prázdné, import přidá k novým sestavám CPC 8 Kč
// konfigurace produktových skupin (sčítá se)
var readLabel0 = false; // filtruj dle labelu 0 <CUSTOM_LABEL_0>
var readLabel1 = true; // filtruj dle labelu 0 <CUSTOM_LABEL_1>
var readCategorytext = false; // filtruj dle kategorie <CATEGORYTEXT>
var readManufacturer = true; // filtruj dle výrobce <MANUFACTURER>
var readBrand = false; // filtruj dle brandu <BRAND>
var inStock = true; // filtruje jen zboží skladem
var enPrRange = true; // segmentace sestav dle ceny produktů, v následujícím řádku nadefinuj rozsahy
var priceRange = ["0-249","250-499","500-999","1000-1999","2000-2999","3000-999999"];
/********************************************************************************************************/
//KONEC RUČNÍHO CONFIGU DÁL NEŠAHAT
/********************************************************************************************************/
//vars
var feed_split = "</SHOPITEM>";
var csv="";
var newData = [];
function main() {
try {
// nácuc a extrakce dat z feedu
var xml = (UrlFetchApp.fetch(feed_url).getContentText()).split(feed_split);
var data = [];
var sestava =[];
for (var i = 0; i < (xml.length - 1); i++)
{
//slozit produtk skupiny a adgroups dle podmínek
// název sestavy
var entities = [];
var rCategorytext="";
var rManufacturer="";
var rBrand="";
var makeName="ok";
// sjednotit načtení promných z feedu a ošetřit prázdné hotnoty manufacturer a další
if (readCategorytext==true) {
rCategorytext = parse(xml[i], "<CATEGORYTEXT>", "</CATEGORYTEXT>");
if (rCategorytext=="") {
makeName="no";}
else {
rCategorytext = removeCdata (rCategorytext);
}
}
if (readManufacturer==true) {
rManufacturer = parse(xml[i], "<MANUFACTURER>", "</MANUFACTURER>");
if (rManufacturer=="") {
makeName="no";}
else {
rManufacturer = removeCdata (rManufacturer);
}
}
if (readBrand==true) {
rBrand = parse(xml[i], "<BRAND>", "</BRAND>");
if (rBrand=="") {
makeName="no";}
else {
rBrand = removeCdata (rBrand);
}
}
if (readLabel0==true) {
rLabel0 = parse(xml[i], "<CUSTOM_LABEL_0>", "</CUSTOM_LABEL_0>");
if (rLabel0=="") {
makeName="no";}
else {
rLabel0 = removeCdata (rLabel0);
}
}
if (readLabel1==true) {
rLabel1 = parse(xml[i], "<CUSTOM_LABEL_1>", "</CUSTOM_LABEL_1>");
if (rLabel1=="") {
makeName="no";}
else {
rLabel1 = removeCdata (rLabel1);
}
}
if(makeName=="ok"){
//pokud jsou dostupné všechny názvy udělej sestavu a produktovou skupinu
if (readLabel0==true) entities.push(rLabel0);
if (readLabel1==true) entities.push(rLabel1);
if (readCategorytext==true) entities.push(rCategorytext);
if (readManufacturer==true) entities.push(rManufacturer);
if (readBrand==true) entities.push(rBrand);
// název sestavy rozseká oddělovačem
var adgroupName = entities.join(" | ");
//Logger.log(entities);
// definice produktové skupiny
var prodGroup="*";
if (readLabel0==true) prodGroup += " / Custom label 0='" + rLabel0 + "'";
if (readLabel1==true) prodGroup += " / Custom label 1='" + rLabel1 + "'";
if (readCategorytext==true) prodGroup += " / Product type='" + rCategorytext + "'";
if (readManufacturer==true) prodGroup += " / Manufacturer='" + rManufacturer + "'";
if (readBrand==true) prodGroup += " / Brand='" + rBrand + "'";
if (inStock==true) prodGroup += " /Availability='in_stock'";
// přidá do pole řádek adgroupy a produktové skupiny
sestava.push({adgroup: adgroupName, productgroup: prodGroup});
}
}
} catch(err) {
Logger.log(err);
}
Logger.log("Neunikatnich sestav: " + sestava.length);
//slozit sestavu a produktovou skupinu
var flags = [], output = [], l = sestava.length, i;
for( iii=0; iii<l; iii++) {
if( flags[sestava[iii].adgroup]) continue;
flags[sestava[iii].adgroup] = true;
// pokud je zapnuto přidání cenových rozsahů
if (enPrRange == true) {
for (ii = 0; ii < priceRange.length; ii++) {
output.push({adgroup: sestava[iii].adgroup + " | " + priceRange[ii], productgroup: sestava[iii].productgroup + " / Price=["+priceRange[ii] + "]"});
}
} else {
// bez cenových rozsahů
output.push({adgroup: sestava[iii].adgroup, productgroup:sestava[iii].productgroup});
}
}
Logger.log("Unikatnich sestav: " + output.length);
// slozit hlavicku import souboru
var tableHeader = ["Campaign", "Campaign type", "Campaign Daily Budget", "Networks", "Campaign Status", "Ad Group", "Max CPC", "Ad Group Status", "Status", "Product Group", "Product Set Label", "PLA shop"];
var campaignLine = [campaignName, "Shopping", campaignBudget, "Search;Google Search;Search Partners","active"];
csv += '"' + tableHeader.join('"\t"') + '"\r\n';
csv += '"' + campaignLine.join('"\t"') + '"\r\n';
// zalozit sestavy a produktové skupiny
for(key in output) {
if(output.hasOwnProperty(key)) {
var value = output[key].productgroup;
//vytvori produktovou skupinu
//Logger.log (output[key].adgroup.length);
//zkratit název reklamní skupiny
var trimmedString = output[key].adgroup.substring(0, 50);
var groupLine = [campaignName, "", "", "", "", output[key].adgroup, "", "", "active", output[key].productgroup, trimmedString, shopID];
//vytvori sestavu
var adgroupLine = [campaignName, "", "", "", "", output[key].adgroup, defaultCPC, "active", "", "", "", ""];
csv += '"' + groupLine.join('"\t"') + '"\r\n';
csv += '"' + adgroupLine.join('"\t"') + '"\r\n';
}
}
// poslat csv mailem
var blob = Utilities.newBlob(csv, "application/octet-stream", "SklikImportPI.csv").setDataFromString(csv, "UTF-16");
MailApp.sendEmail({to: mail, subject: "Import PI Sklik CSV", attachments: blob});
}
//-------------------------------------------------------------------------------------------
function parse(text, from, to)
{
var step_one = text.substr(text.indexOf(from) + from.length);
return (step_one.substr(0, step_one.indexOf(to))).trim();
}
function removeCdata(text){
var text = text.replace("<![CDATA[", "");
var text = text.replace("]]>", "");
return text;
}
1. 10. 2019 -
Ahoj, parádní script a díky, jen bych se chtěl zeptat, s kolika produkty eshopu s timto scriptem pracuješ a jaké to má výhody oproti struktuře jedna sestava = jeden produkt?
7. 10. 2019 -
Mám feedy kde jsou desetitisíce produktů.
Dělit to co sestava to produkt mi přijde už hodně silná segmentace, zvláště pokud se ti produkty překrývají pak se ti budou chytat obecná slova na více sestav což je horší na správu. Dávám přednost rozumné segmentaci na větší skupinky kategorie/značka/cena
3. 10. 2019 -
Ahoj, mohl bych se zeptat, jak naložit s takovýmito chybovými hláškami? Díky!
Exception: Request failed for https://www.xyz.cz returned code 403. Truncated server response: 403 Forbidden (use muteHttpExceptions option to examine full response)
TypeError: Cannot read property „length“ from undefined. (file Code.gs, line 137)
7. 10. 2019 -
Neodkážu říct přesně ale dle té chyby bych si tipl že bude problém s feedem. Buď je špatná URL nebo neexistuje.
14. 9. 2020 -
Ahoj,
super skript. Díky za něj. Jak třeba řešíš to, když máš větší počet podkategorií, že tě třeba zajímá úroveň 2 rozdělená dle cenových hladin.
Např. máš kategorii Kancelářské potřeby | Obaly a balení | Bublinkové a chtěl bys jen Kancelářské potřeby | Obaly a balení rozdělenou dle cenových hladin.
Jde to nějak v nastavení takhle s tím pracovat?
Moc díky.
Honza
14. 9. 2020 -
Ahoj, teoreticky si to můžeš rozhodit jak potřebuješ, stačí si poslat do šítku hodnoty dle toho jak potřebuješ, něco asi půjde v Mergadu a něco možná bude spíš na programátora, ale udělat to jde.
14. 10. 2020 -
Jasne, super. Rozumím. Diky moc. Jdu to nastavit v Mergadu.
H.
9. 11. 2020 -
Skvelá práca, ďakujem! Viem, že skript je už staršieho data, ale stále super. V kombinácii so „smartibiddingom“ skrz automatické pravidlá mňam!
15. 1. 2021 -
Zdravím Karle, prosím vás, chcem sa len rýchlo spýtať, pri aktualizácii importu s nejakou periodicitou potom pri importe volíte aktualizačný režim, alebo přepsat? Predpokladám, že aktualizačný, aby sa zachoval bidding, ale chcel som si to pre istotu potvrdiť. Ďakujem.
6. 5. 2021 -
Přesně tak aktualizační režim a ve scriptu nechávám proměnnou defaultCPC=““
24. 2. 2021 -
Ahoj,
díky za script. Chci se zeptat – řešili jste u něj nějakou automatizaci nahrávání do Skliku? Třeba tak, aby nebylo třeba při každé větší změně v sortimentu spouštět skript a soubor ručně nahrávat do systému, ale vše se dělo plně automaticky, třeba na týdenní, nebo měsíční bázi?
Děkuji za odpověď!
Jakub
6. 5. 2021 -
Bohužel neřešili, cca jednou za měsíc vygentuji nový import soubor a nahraji update do Skliku. Z toho důvodu mám pro každý projekt tento script sólo a je to pak na jeden klik.