Finish line是美國的一個運動品牌網站,我平時比較喜歡海淘鞋子,時不時可能想看看有沒有什麼好貨,但是呢,每次都要自己在頁面上一個個查看比較麻煩,故想弄一些自動化的篩選,自動選出性價比高的東西。廢話不多說,上源碼(chrome瀏覽器,篩選鞋子可行,其他大部分也可以的):
//指定你期望的折扣
let expectedDiscount = 0.4
//分析第一個頁面的信息
openShoesInNewTab(expectedDiscount)
//設置定時器,遍歷剩下所有頁面
const timer = setInterval(()=>{
// 第一步:找到“下一頁”的按鈕,並觸發點擊事件(這裏我偷懶了,直接用Chrome開發者工具找到JS引用該節點的方式)
document.querySelector("#mainColumn > div.row.align-middle.m-0.mt-2.mb-1.mt-medium-4.mb-medium-4 > div > div.grid-pagination-column.hide-for-small-only > div > div > div:nth-child(6) > a.button.pag-button.next.light-gray.ml-1 > span").click()
// 第二步:使用setTimeout將計算商品折扣的代碼放入macrotask中,等請求到數據後再執行(event loop相關)
setTimeout(() => {
openShoesInNewTab(expectedDiscount)
}, 0)
}, 5000)
//查找符合折扣要求的商品
function openShoesInNewTab(expectedDiscount) {
//找到頁面所有物品的信息,遍歷(要將NodeList結構的類數組轉爲正真的數組後,才能使用數組方法)
[...document.querySelectorAll('.product-card__details')].forEach( product => {
//找到價格節點
const node = product.querySelector('.product-price')
//將字符串的價格:"$35.00 $25.00" ,轉化爲數字數組[35, 25],前面爲原價,後面爲現價
const priceInfo = node.innerText.replace(/\$([0-9]*)/g, (a,b) => b).split(' ').map(price => price/1)
// 計算折扣
const discount = (priceInfo[1]/priceInfo[0]).toFixed(2)
// 該物品對應的鏈接
const url = product.querySelector('.hover-underline').href
//若折扣小於expectedDiscount,則在新的標籤頁中打開該物品
if(discount < expectedDiscount) {
window.open(url, '_blank')
}
})
}
//過幾分鐘等遍歷所有的頁面後,運行以下代碼清除定時器:
clearInterval(timer)
使用步驟:
- 登入Finish line官網,然後選擇一個你想要的品類,如下圖選擇的是男士鞋子:
- 可以在頁面的左邊選擇欄選擇好自己的偏好以後,打開瀏覽器的console面板(windows快捷鍵:
Ctrl + Shift + J
,Mac快捷鍵:Cmd + Option + J
),將上述代碼複製到console面板中,回車執行(注意:這裏最後這行代碼clearInterval(timer)
不要複製進去,等一段時間後再運行,用於遍歷完所有頁面後清除定時器),然後你就可以幹自己的事,該幹嘛幹嘛去咯,代碼自動將你設定的低於指定折扣的商品在新的標籤頁中打開。過幾分鐘來收割就行了,你就可以美滋滋地瀏覽那些符合期望的商品了。如下圖:
總結
代碼中主要用到的知識點:
- 定時器:
setInterval(fn, ms)
、setTimeout(fn, ms)
。用於在指定時間ms
毫秒後執行fn
回調函數,setInterval
是每隔ms
毫秒循環不斷地執行,setTimeout
只執行一次,它們的回調函數都會被添加到macrotask隊列中(事件循環相關可以看:這裏),從而可以在獲取頁面數據(microtask任務優先級比macrotask高)後再執行。 - 查找頁面元素:
querySelector(selector)
、querySelectorAll(selector)
。這兩個函數都是用於查找符合CSS選擇器selector
規則的元素,querySelector()
只返回查找到的第一個元素節點,querySelectorAll()
返回的是NodeList節點列表,它是一個類數組(array-like),我們可以通過[...]
展開運算符將其變爲一個真正的數組,從而可以使用數組方法。 - 字符串方法以及正則表達式:
const priceInfo = node.innerText.replace(/\$([0-9]*)/g, (a,b) => b).split(' ').map(price => price/1)
解釋一下這段代碼:
①正則表達式/\$([0-9]*)/g
用來全局匹配美元字符$
後面跟着數字的字串,數字部分加上小括號是用於捕獲數字,用來替換原來包含$
符號的數字(正則表達式相關可以參考:這裏)。
②通過字符串的replace()
方法將類似這種形式的字符串'$35.00 $25.00'
轉化爲這種形式'35.00 25.00'
。replace()
方法的第二個參數是一個回調函數,這個回調函數會在每次匹配到相關的字串時執行,回調函數的第一個參數a
表示匹配到的字串(這個例子就是:'$35'
,'$25'
),第二個參數b
就是捕獲到的內容(25
,'25
),回調函數的返回值就是用來替換掉匹配到的內容。
③再通過字符串的split(' ')
方法將'35 25'
字符串按空格切分爲字符串數組['35', '25']
。
④最後通過數組的map()
方法將字符串數組轉化爲數字數組。
- 在瀏覽器新窗口中打開指定url的方法:
window.open(url, '_blank')
。
PS:以上純屬娛樂,其實主要想將學習過的東西拿來練練手,有時,程序員的快樂就是這麼枯燥且乏味(哈哈哈,朱一旦非洲警告)