Showing posts with label Chrome CSS Javascript. Show all posts
Showing posts with label Chrome CSS Javascript. Show all posts

Sunday, September 18, 2016

CSS selector in Chrome using the example of Apple iPhone 7 Plus Availability Monitoring

The iPhone 7 Plus Reserve Page for HK is a dynamic web content as in https://reserve.cdn-apple.com/HK/en_HK/reserve/iPhone/availability

The basic javascript console code in Google Chrome for availability is as below

iPhone7availability    Select all
// proper case string prptotype (JScript 5.5+) String.prototype.toProperCase = function() { return this.toLowerCase().replace(/^(.)|\s(.)/g, function($1) { return $1.toUpperCase(); }); } function testip7plus() { var targetProduct = "Plus" var targetCapacity = "256GB" // "32GB", "128GB", "256GB" var targetColor = "Silver" // "Rose Gold" 玫瑰金色, "Gold" 金色, "Sliver" 銀色, "Black" 黑色, "Jet Black" 亮黑色 var FinalSelectedProduct = false; targetCapacity = targetCapacity.toUpperCase() targetColor = targetColor.toProperCase(); var stores_length = $('form#availabilityForm #selectStore option[disabled!=disabled]').length; for(a=0; a<stores_length; a++) { var enabledStore = $('form#availabilityForm #selectStore option[disabled!=disabled]').eq(a).val(); setTimeout(function() { $('form#availabilityForm div.form-element.select-store select').val(enabledStore); $('form#availabilityForm div.form-element.select-store select').change(); },1800) var enabledStoreText = $('form#availabilityForm #selectStore option[disabled!=disabled]').eq(a).text().replace(/^\s+|\s+$/g, ''); var products_length = $('form#availabilityForm #selectSubfamily option[disabled!=disabled]').length; for(p=0; p<products_length; p++) { var enabledProduct = $('div#productSelectionView #selectSubfamily option[disabled!=disabled]').eq(p).val(); var enabledProductText = $('div#productSelectionView #selectSubfamily option[disabled!=disabled]').eq(p).text(); if (~enabledProductText.toLowerCase().indexOf(targetProduct.toLowerCase())) { console.log("Log " + enabledStoreText + " has " + enabledProductText); $('form#availabilityForm div.form-element.select-product select').val(enabledProduct); $('form#availabilityForm div.form-element.select-product select').change(); var unavailableGB = $('div#capacity-row li.unavailable input[value="'+targetCapacity+'"]').length console.log("Log " + enabledStoreText + " checking for " + targetCapacity) if (unavailableGB == 0) { var sizeAva_length = $('div#capacity-row li').length; for(u=0;u<sizeAva_length;u++) { if ($('div#capacity-row li').eq(u).find('div').attr('id') == targetCapacity) { $('div#capacity-row li').eq(u).find("input").click(); break; } } var unavailableColor = $('div#product-row li.unavailable input[data-color="'+targetColor+'"]').length console.log("Log " + enabledStoreText + " checking for " + targetColor) if (unavailableColor == 0) { var colorAva_length = $('div#product-row li').length; for(v=0;v<colorAva_length;v++) { if ($('div#product-row li').eq(v).find('input').attr('data-color') == targetColor) { setTimeout(function() { $('div#product-row li').eq(v).find("input").click(); },800) FinalSelectedProduct = true; break; } } if (FinalSelectedProduct) { console.log("SUCCESS!!! " + enabledStoreText + " has " + $('div.section-product.product-bottom.hide-for-large.show-only-for-small.with-fade.fade-in div.product div.callout.callout-center.product-specs ul.specs li:first').text().trim() + " " + enabledProductText + $('div.success.row div.success-copy.small-center').text().trim()); break; } } else { console.log("Log " + enabledStoreText + ", sorry no " + targetCapacity + " " + targetColor) } } } else { console.log(enabledStoreText + ", sorry no " + targetProduct) } } if (FinalSelectedProduct) { return; } } } testip7plus()



There is an archive for iPhone 6 Availability script in last year, please click the Chrome CSS Javascript label below


Wednesday, September 30, 2015

CCS Selector for iPhone 6s Reservation Submission Form

For the iPhone 6s Reservation Submission Form, the required javascript code for selectors and the flow are analysed below in red.

(1)
URL = iPhone 6s Reservation
(2) javascript for Chrome console (Cmd + Opt + J for Mac)
iphone6s.js    Select all
var isDebug = true; var isSubmit = false; var storeOrder = ["R409","R428","R499","R485"]; // R409=CWB銅鑼灣, R485=FW又一城, R428=IFC, R499=CantonRoad廣東道 var timeslotOrder = ["2:00 PM","11:30 AM","12:00 PM","12:30 PM","1:00 PM","1:30 PM","3:00 PM","4:00 PM"]; //var timeslotOrder = ["下午 2:00","上午 11:30","下午 12:00","下午 12:30","下午 1:00","下午 1:30","下午 3:00"]; var quantity = 2; // maximum 2 for quantity, 購買數量, 最多2部 var firstname = "javacom"; // First Name 名, 必需填寫 var lastname = "NAME"; // Last Name 姓, 必需填寫 var email = "javacom@icloud.com"; // Email Address 電郵, 必需填寫 var phonenumber = "98765432"; // Phone Number 電話, 必需填寫 var govtIdType = 1; /* HK 1="idHongkongCard" 香港永久性居民身份證 Hong Kong ID Card 2="travelPermitTaiwan" 台灣居民來往內地通行證 Mainland Travel Permit for Taiwan residents 3="entryExitPass" 往來港澳通行證 Entry/Exit Permit to Hong Kong and Macau 4="macauIDCard" 澳門永久性居民身份證 Macau ID Card 5="passport" 國際旅遊護照 Passport (International Visitors) */ var govtId = "A123456(7)"; // Government ID No 證件號碼,必需填寫 function autoSelect() { if (isDebug) console.log("autoSelect()"); if (isDebug) console.log($("#main #storeView .select-store select option").eq(0).val()); if ($("#main #storeView .select-store select option").eq(0).val() > "") selectStore(); else if ($(".reservation .select-store select option").eq(0).text() > "") insertContactInfo(); } function selectStore() { if (isDebug) console.log("selectStore()"); var isSelectedStore = false; var storeSelection_length = $("#main #storeView .select-store select option").length; for(i=0;i<storeOrder.length;i++) { if (isDebug) console.log("Checking Store " + storeOrder[i].toString()); for(a=1;a<storeSelection_length;a++) { if (isDebug) console.log("Against " + $("#main #storeView .select-store select option").eq(a).text()); if ($("#main #storeView .select-store select option").eq(a).val() == storeOrder[i].toString()) { if (isDebug) console.log("Selected Store is " + storeOrder[i].toString()); $("#main #storeView .select-store select option").eq(a).select().attr("selected","selected"); console.log($("#main #availabilityView .section-copy .availability-available").text()); isSelectedStore = true; break; } } if(isSelectedStore) break; } if(isSelectedStore) { $(".form-cell button").click(); } else { console.log("Sorry !! unavailable for in-store pickup"); } } function insertContactInfo() { if ($("select[name='selectedQuantity'] option").eq(quantity-1).val() > "") { $("select[name='selectedQuantity'] option").eq(quantity-1).select().attr("selected","selected").change(); } else { $("select[name='selectedQuantity'] option:last").select().attr("selected","selected").change(); } var isSelectedTimeslot = false; var timeSlotSelection_length = $("select[name='selectedTimeSlotId'] option").length; for(i=0;i<timeslotOrder.length;i++) { if (isDebug) console.log("Checking Timeslot " + timeslotOrder[i].toString()); for(a=1;a<timeSlotSelection_length;a++) { if (isDebug) console.log("Against " + $("select[name='selectedTimeSlotId'] option").eq(a).text()); if ($("select[name='selectedTimeSlotId'] option").eq(a).text().indexOf(timeslotOrder[i].toString()) == 0) { $("select[name='selectedTimeSlotId'] option").eq(a).select().attr("selected","selected").change(); console.log($("select[name='selectedTimeSlotId'] option").eq(a).select().text()); isSelectedTimeslot = true; break; } } if(isSelectedTimeslot) break; } if (!isSelectedTimeslot) { $("select[name='selectedTimeSlotId'] option:last").select().attr("selected","selected").change(); console.log($("select[name='selectedTimeSlotId'] option:last").select().text()); } $("input[name='firstName']").val(firstname); $("input[name='lastName']").val(lastname); $("input[name='email']").val(email) $("input[name='phoneNumber']").val(phonenumber) $(".gov-id-info select[name='selectedGovtIdType'] option").eq(govtIdType).select().attr("selected","selected").change(); $("input[name='govtId']").val(govtId); console.log($(".schedule-copy").text()); if (isSubmit) $(".form-cell button").click(); } autoSelect();


Tuesday, October 7, 2014

CSS Selector in Chrome (Part 2) Apple On-line Store for iPhone 6

Apple On-line Store for iPhone 6 URL for HK is here
http://store.apple.com/hk/buy-iphone/iphone6

The selection flow and the CSS Selector code are listed as below


(1) Choose a model:
AOS/availability    Select all
<div id="group-1"> <div id="Item1" class="step"> <div class="selection"> <div class="small-size-buttons enabled"> <fieldset> <legend class="size-selection-header"> <h2 class="fwl"><span class="section-number step1"><span class="a11y">1</span>>/span> <span class="section-heading">Choose a model:</span> </h2> </legend> <div class="selection-buttons"> <div class="item "> <input type="radio" value="4_7inch" id="Item14_7inch" name="dimensionScreensize" class="a11y"> <label for="Item14_7inch"> <div class="details"> <div class="label"> <div class="size-label">iPhone 6 <span>4.7-inch display</span> </div> <div class="price"> <span itemtype="http://schema.org/Offer" itemprop="offers" itemscope="itemscope"> <meta itemprop="priceCurrency" content="HKD"> <span itemprop="price">From <span>HK$5,588</span></span> </span> </div> </div> </div> </label> </div> <div class="item "> <input type="radio" value="5_5inch" id="Item15_5inch" name="dimensionScreensize" class="a11y" checked=""> <label for="Item15_5inch"> <div class="details"> <div class="label"> <div class="size-label">iPhone 6 Plus <span>5.5-inch display</span> </div> <div class="price"> <span itemtype="http://schema.org/Offer" itemprop="offers" itemscope="itemscope"> <meta itemprop="priceCurrency" content="HKD"> <span itemprop="price">From <span>HK$6,388</span></span> </span> </div> </div> </div> </label> </div> </div> </fieldset> </div> </div> </div>
$("group-1 #Item1 div.selection-buttons div.item").eq(0).find("input").click();
where 0=iPhone 6; 1=iPhone 6 Plus


(2) Choose color:
$("group-1 #Item2 div.selection-buttons div.item").eq(0).find("input").click();
where 0=Silver; 1=Gold; 2=Space-Grey


(3) Choose storage:
$("group-1 #Item3 div.selection-buttons div.item").eq(0).find("input").click();
where 0=16GB; 1=64GB; 2=128GB


(4) Product Summary and Availability:
$("primary .product-title").text() + " " + $("actiontray .customer_commit_display").text();


(5) Enable Select button:
AOS/availability    Select all
<div id="actiontray" class="actiontray"> <ul class="purchase-info"> <li class="specials"></li> <li class="shipping"> Available to ship<b>:</b><br> <span class="customer_commit_display">Currently unavailable</span> <span class="freeshipping promo-text">Free Shipping</span> </li> <li> <span class="price"> <span class="current_price"> <span itemscope="itemscope" itemprop="offers" itemtype="http://schema.org/Offer"> <meta itemprop="priceCurrency" content="HKD"> <span itemprop="price"> HK$7,188 </span> </span> </span> </span> <span class="financing"></span> </li> <li class="add-to-cart"> <button class="button disabled" type="button" disabled="disabled"><span>Select</span></button> </li> <li class="shipping-lead"></li> </ul> </div>
$("actiontray .add-to-cart .button")[0].classList.remove("disabled"); $("actiontray .add-to-cart .button").removeAttr("disabled"); $("actiontray .add-to-cart .button")[0].classList.add("transactional");
note: Chrome supports HTML5 Technique for changing classes


Monitoring program see http://youtu.be/Nj1vcbEyhf4

Sunday, October 5, 2014

CSS selector in Chrome using the example of Apple iPhone 6 Availability Monitoring

The iPhone 6 Reserve Page for HK is a dynamic web content as in
https://reserve.cdn-apple.com/HK/en_HK/reserve/iPhone/availability


An example of the implementation of monitoring program uses javascript and the Chrome browser and further automation to reserve an iPhone can possibly be completed using Webdriver JS from the Selenium + chrome driver (see http://youtu.be/I1-m_qcmQLk).

To start with and illustrate, the steps for the javascript code preparation are as below:

(1) Goto the website and open the javascript console (Control-Shift-J in PC, Cmd-Option-J in Mac) in Chrome browser



(2) Click the element tab, the dynamic webpage code can be revealed.

iPhone/availability    Select all
<div id="wrapper" class="check-availability"> <div class="two-col-container"> <div class="options-container"> <div class="availability-title-container"> ... </div> <div class="storeselect select-style products" style="..."> <select name="products"> <option value="">Select a model</option> <option data-index="0">iPhone 6 Plus</option> <option data-index="1">iPhone 6</option> </select> </div> <div class="storeselect select-style stores" style="..."> <select name="stores"> <option value="">Select a store</option> <option value="R409">Causeway Bay</option> <option value="R485">Festival Walk</option> <option value="R428">ifc mall</option> </select> </div>

(3) Use the CSS style locator (to be entered into the javascript console of Chrome Browser) as below to quickly locate the model selection box and make changes to it, eq(1) being iPhone 6 plus and eq(2) is iPhone 6.
div#wrapper means the div id locator for the id wrapper.
div.two-col-container means the div class locator for the class two-col-container.
$('div#wrapper div.two-col-container div.options-container select[name="products"] option').eq(1).select().attr("selected","selected").change();
$('div#wrapper div.two-col-container div.options-container select[name="products"] option').eq(2).select().attr("selected","selected").change();


(4) Similarly, the code to select the store is
$('div#wrapper div.two-col-container div.options-container select[name="stores"] option').eq(1).select().attr("selected","selected").change();

(5) To retrieve the dynamic content of the store info, use
$("div#wrapper div.two-col-container div.dropdown-container div.results-container .store").text() + $("div#wrapper div.two-col-container div.dropdown-container div.results-container .date").text();

(6) To retrieve the dynamic content of availability of say 16GB sliver, use
" 16GB " +$("div#wrapper div.two-col-container div.dropdown-container div.results-container .device-sizes tbody tr").eq(0).attr("class") + " " + $("div#wrapper div.two-col-container div.dropdown-container div.results-container .device-sizes tbody tr").eq(0).find(".16GB .isAvailableText").text();

(6.1) Similarly, 16GB gold is
" 16GB " +$("div#wrapper div.two-col-container div.dropdown-container div.results-container .device-sizes tbody tr").eq(1).attr("class") + " " + $("div#wrapper div.two-col-container div.dropdown-container div.results-container .device-sizes tbody tr").eq(1).find(".16GB .isAvailableText").text();

(6.2) For others, just repeat and substitute '16GB' for '64GB' and '128GB' and change the eq(0) to eq(1) and eq(2) for different colors, 0=silver, 1=gold, 2=space-grey.

(7) To click the Get Started button on the right of the webpage, use
$('div.skip-wrapper div.button-container .button')[0].click();



To automate the scripts, one possible solution is to use node.js + chromedriver
Download and Put the ChromeDriver (note that it is 32 bit only for Windows/Mac) on your PATH
http://chromedriver.storage.googleapis.com/index.html?path=2.10/

and then install node.js from
http://nodejs.org/download/
and see the WebDriver wiki here https://code.google.com/p/selenium/wiki/WebDriverJs

Note: for windows 8, please create folder in "%HOMEPATH%\AppData\Roaming\npm"
before installing WebDriver using "npm install selenium-webdriver"


appleiphone6_availability.js    Select all
#!/usr/bin/env node // for bash shell // for i in {1..300}; do sleep 1s; ./appleiphone6_availability.js $i; sleep 39s ; done; // for windows command line, Use two %% if it is in a batch file // FOR /L %I IN (1,1,300) DO ("C:\Program Files\nodejs\node.exe" appleiphone6_availability.js %I; sleep 39s) var args = process.argv.slice(2); var webdriver = require('selenium-webdriver'); var driver = new webdriver.Builder().withCapabilities({ browserName : 'chrome', 'chromeOptions': { args: ['test-type'] } }).build(); var isDEBUG = false; var isAvailable = [false,false,false]; var isAvailableCount = 0; var products = ["","iPhone 6 Plus","iPhone 6"]; var stores = ["","Causeway Bay","Festival Walk","IFC Mall"]; var fs = require('fs'); function nextaction(msg, p) { if (isAvailable[p]) { return } else { isAvailable[p] = true; isAvailableCount++; var driver2 = new webdriver.Builder().withCapabilities(webdriver.Capabilities.chrome()).build(); driver2.wait(function() { driver2.get('http://admin:password@192.168.0.1/sms/newmessage.asp') if (isAvailableCount > 1) { driver2.findElement(webdriver.By.id("maincontent")).findElement(webdriver.By.name("phoneNumber")).sendKeys("12345678"); } else { driver2.findElement(webdriver.By.id("maincontent")).findElement(webdriver.By.name("phoneNumber")).sendKeys("12345678;87654321"); } driver2.findElement(webdriver.By.id("maincontent")).findElement(webdriver.By.id("draftContent")).sendKeys("IR Monitoring: " + msg + " now available"); driver2.findElement(webdriver.By.id("maincontent")).findElement(webdriver.By.id("send")).click(); return msg != null; }, 3000) .then(function() { driver2.quit(); var stream = fs.createWriteStream('availableLog.txt', {flags: 'a', encoding : 'unicode'}); stream.once('open', function(fd) { stream.write('SMS sent ' + msg + '\r\n'); stream.end(); }); console.log("SMS sent OK") }); } return } function check_availability(p,s) { driver.get('https://reserve.cdn-apple.com/HK/en_HK/reserve/iPhone/availability'); driver.executeScript('$("#wrapper .two-col-container .options-container .storeselect select[name=\'products\'] option").eq('+p+').select().attr("selected","selected").change()') .then(function() { if (isDEBUG) console.log("product selected"); }, function(err) { console.log('There was an error for product selection ! ' + err); }); driver.executeScript('$("#wrapper .two-col-container .options-container .storeselect select[name=\'stores\'] option").eq('+s+').select().attr("selected","selected").change()') .then(function() { if (isDEBUG) console.log("store selected"); }, function(err) { console.log('There was an error for store selection ! ' + err); }); if (isDEBUG) console.log('CHECKING ' + products[p] + ' ' + stores[s]); driver.wait(function() { return driver.executeScript('return $("#wrapper .two-col-container .dropdown-container .results-container .store").text() + $("#wrapper .two-col-container .dropdown-container .results-container .date").text()') .then(function(message) { console.log(args +' '+message); if (message.length < 5) { console.log('CHECKING ' + products[p] + ' ' + stores[s]); return webdriver.promise.rejected('Please come back later'); } return message != null; }); }, 3000) .then(function() { driver.wait(function() { return driver.executeScript('return $("#wrapper .two-col-container .dropdown-container .results-container .store").text() \ + $("#wrapper .two-col-container .dropdown-container .results-container .date").text() \ + " 16GB " + $("#wrapper .two-col-container .dropdown-container .results-container .device-sizes tbody tr").eq(0).attr("class") + " " \ + $("#wrapper .two-col-container .dropdown-container .results-container .device-sizes tbody tr").eq(0).find(".16GB .isAvailableText").text() \ + " 16GB " + $("#wrapper .two-col-container .dropdown-container .results-container .device-sizes tbody tr").eq(1).attr("class") + " " \ + $("#wrapper .two-col-container .dropdown-container .results-container .device-sizes tbody tr").eq(1).find(".16GB .isAvailableText").text() \ + " 16GB " + $("#wrapper .two-col-container .dropdown-container .results-container .device-sizes tbody tr").eq(2).attr("class") + " " \ + $("#wrapper .two-col-container .dropdown-container .results-container .device-sizes tbody tr").eq(2).find(".16GB .isAvailableText").text() \ + " 64GB " + $("#wrapper .two-col-container .dropdown-container .results-container .device-sizes tbody tr").eq(0).attr("class") + " " \ + $("#wrapper .two-col-container .dropdown-container .results-container .device-sizes tbody tr").eq(0).find(".64GB .isAvailableText").text() \ + " 64GB " + $("#wrapper .two-col-container .dropdown-container .results-container .device-sizes tbody tr").eq(1).attr("class") + " " \ + $("#wrapper .two-col-container .dropdown-container .results-container .device-sizes tbody tr").eq(1).find(".64GB .isAvailableText").text() \ + " 64GB " + $("#wrapper .two-col-container .dropdown-container .results-container .device-sizes tbody tr").eq(2).attr("class") + " " \ + $("#wrapper .two-col-container .dropdown-container .results-container .device-sizes tbody tr").eq(2).find(".64GB .isAvailableText").text() \ + " 128GB " + $("#wrapper .two-col-container .dropdown-container .results-container .device-sizes tbody tr").eq(0).attr("class") + " " \ + $("#wrapper .two-col-container .dropdown-container .results-container .device-sizes tbody tr").eq(0).find(".128GB .isAvailableText").text() \ + " 128GB " + $("#wrapper .two-col-container .dropdown-container .results-container .device-sizes tbody tr").eq(1).attr("class") + " " \ + $("#wrapper .two-col-container .dropdown-container .results-container .device-sizes tbody tr").eq(1).find(".128GB .isAvailableText").text() \ + " 128GB " + $("#wrapper .two-col-container .dropdown-container .results-container .device-sizes tbody tr").eq(2).attr("class") + " " \ + $("#wrapper .two-col-container .dropdown-container .results-container .device-sizes tbody tr").eq(2).find(".128GB .isAvailableText").text()' ).then(function(message) { if (isDEBUG) console.log(message); if(message.indexOf(" Available") > -1) { console.log(products[p] + ' ' + stores[s] + "Available "+ message); var stream = fs.createWriteStream('availableLog.txt', {flags: 'a', encoding : 'unicode'}); stream.once('open', function(fd) { stream.write(args +' ' + products[p] + ' ' + stores[s] +' Acailable'+ '\r\n' + message + '\r\n'); stream.end(); }); vailableText = products[p] + ' ' + stores[s]+ ' (' ; var is16GBAvailable = false; var is64GBAvailable = false; var is128GBAvailable = false; if(message.indexOf("16GB gold Available") > -1) { availableText += "16G金"; is16GBAvailable = true; } if(message.indexOf("16GB space-grey Available") > -1) { if (is16GBAvailable) { availableText += "灰";} else {availableText += "16G灰";} is16GBAvailable = true; } if(message.indexOf("16GB silver Available") > -1) { if (is16GBAvailable) { availableText += "銀";} else { availableText += "16G銀";} is16GBAvailable = true; } if(message.indexOf("64GB gold Available") > -1) { availableText += " 64G金"; is64GBAvailable = true; } if(message.indexOf("64GB space-grey Available") > -1) { if (is64GBAvailable) { availableText += "灰";} else { availableText += " 64G灰";} is64GBAvailable = true; } if(message.indexOf("64GB silver Available") > -1) { if (is64GBAvailable) { availableText += "銀";} else { availableText += " 64G銀";} is64GBAvailable = true; } if(message.indexOf("128GB gold Available") > -1) { availableText += " 128G金"; is128GBAvailable = true; } if(message.indexOf("128GB space-grey Available") > -1) { if (is128GBAvailable) { availableText += "灰";} else { availableText += " 128G灰";} is128GBAvailable = true; } if(message.indexOf("128GB silver Available") > -1) { if (is128GBAvailable) { availableText += "銀";} else { availableText += " 128G銀";} is128GBAvailable = true; } nextaction(availableText+ ')',p); } return message != null; }); }, 3000) }, function(err){ console.log('There was an error checking ' + products[p] + ' ' + stores[s] + ' ' + err); }); } // node.js has non-blocking I/O and recursive, there is no need to have a loop here var p1 = 1; var s1 = 0; driver.get('https://reserve.cdn-apple.com/HK/en_HK/reserve/iPhone/availability'); driver.wait(function() { if (++s1 > 3) { s1=1; if (++p1 > 2){p1=1}} return check_availability(p1,s1); }, 180*1000) .then(function() {} ,function(err){ driver.quit(); console.log('check_availability ' + err); });