最近逛了一個不錯的論壇,上面主要是交換技能,實在是一個很棒的網站。
身為人體工程師,
看到好看的人體就想要解剖,而身為前端工程師想要看一下網頁前端也很正常。
因此我們使用開發者工具,不需要學咒術,只要按下F12或是右鍵檢查就可以了。
這就是前端的EZ PZ。(簡單)
所以我們今天要做的事情,不是自己寫html寫東西寫出來,而是觀察人家大師的作品,
去學習人家使用色彩與線條以及光影等等的技術。
分析完人家的網頁,我們也需要動手操作一些東西,否則就不叫做動手玩創意了。
而使用我們今天會學到的東西以後,我們的駭客任務最終結果:
也就是說我們自己透過程式碼,讓原本不屬於網頁上的email欄位變出來了!
這不是魔法也不是魔術,真的就是前端動手玩創意的趣味。
先做個聲明,此教學純粹作為示範用途,我也很貼心的幫這些email打馬賽克了。
請各位前端超派小高手,好好學習就好了、切勿以身試法、做出壞事。
我們超派但是很乖,乖乖學前端,懂?
看到這篇文章基本上有福了(?)
雖然我喜歡吃草莓大福、不喜歡蝙蝠,更不是人夫,但。
你有福了。
不是發福,可能會是幸福,因為這篇文章會講到全網路都沒有寫的中文教學:開發者工具使用。
為什麼我說都沒有人教學呢,因為你真的google不到,關於AJAX以及f12的使用奧義,
基本上除非你會使用凝,否則很難練起來。
除此之外,我們今天主打的是ajax fetch API 動態生成 json這些觀念,
算是比較中階的課程唷!
廢話結束我們繼續觀察F12的作用。
點到network這邊可以看看網頁都call了什麼東西,我們發現移動卷軸到最底端,
會呼叫資料再把內容渲染出來。
再來點到response就可以看到,原來網頁的畫面不是寫死的html欸?哦天!
原來這些內容都儲存到data裡面才被用JS呼叫出來、渲染。
想知道這樣子的技巧可以複習:
認識 data model 與 render function
這邊不贅述,但我稍微截圖讓各位知道這個觀念,data render也就是前端的牛頓定理。
【前端動手玩創意】動態生成的藝術|小心,亂改DOM你可能會被打臉。
知道原來有email這則資訊,只是沒有渲染出來,
雖然沒有薪水,但我們可以幫偷懶的網頁開發者做這份工作。
(開玩笑的啦!這是不好的示範,別亂學。)
也就是效果圖裡面告訴你的,我已經使用天能法,倒述讓你看到結果了。
我似乎"曾經"在昨天還是前天發表的文章提到一件事。
我只能說這篇是自從「備份IT幫發文、一眼全覽」最強的JS教學文章!
超派,真的不騙( メ∀・)
有些人喜歡看前端小試身手,有些人喜歡前端動手玩創意;
其實這兩個系列的本質都是JS的教學,是可以互相連接的,但也有很多不同的重心。
這個系列就是以腳本為主,重點在於創意與發想,打到使用者痛點。
【前端動手玩創意】則是以建構網站為起點,
任何元素與概念都會變成網頁上的一部分,算是比較基礎工的建立。
來自:前端小試身手(8)--教你寫出「思想審查警衛」,過濾垃圾雜訊的利器!
【前端小試身手】系列一直都是很猛的腳本。的確我沒有說謊,「思想警衛腳本」真的很強!
這也是為什麼我這篇是來一個【前端動手玩創意】,
因為今天這篇文章的強度,幾乎是再度的,輾壓任何一篇!Ꮚ・ꈊ・Ꮚ
畢竟我們今天把人家網站都解剖了。
就像是把妹最高的藝術就是娶回家一般。
// 滾動事件
window.addEventListener('scroll', function() {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
// 當滾動到底部時執行emailFind函數
emailFind();
}
});
我們設計當觸發到捲動底部的時候,就執行我們的emailFind();
也就是call API去得到data。
要怎麼知道email這個data怎麼call出來?人家又沒有給你API,這時候開發者工具的威力就來了。
剛剛我們是看response的部分,現在我們往左邊選,
點到payload就可以看到發送出去的參數。
這邊看到原來使用userID是一個方法,那麼我們就必須找到userId是什麼。
稍微觀察了一下網站,狠辛苦地找了老半天,發現原來網址上就有userID。
不過這樣是不夠的,我們在首頁上並沒有這樣子的資訊。
因此我又繼續做名偵探柯北,好好調查。
終於發現有個破綻!
也就是說,每個使用者的大頭貼,
都是使用存放在這個網站上的圖,而這些圖片都用id作為網址的一部份去標記。
於是我們可以針對img去做字串擷取,就能拿到其userID,也就能夠當作fetch的參數,
去把email打出來。
// emailFind函數
function emailFind() {
// 獲取所有的img標簽
const imgElements = document.querySelectorAll('img');
// 遍歷每個img標簽 因為裡面有id
imgElements.forEach((img) => {
if (img.getAttribute('alt') === 'user') {
// 要確認是使用者的圖片 不是其他的
const src = img.getAttribute('src');
const startIndex = src.lastIndexOf('/') + 1; // 獲取最後一個/後的位置
const endIndex = src.indexOf('-', startIndex); // 獲取-的位置
if (startIndex !== -1 && endIndex !== -1) {
let extractedString = src.substring(startIndex, endIndex);
// 去除"user%2F"
extractedString = extractedString.replace('user%2F', '');
// 檢查h1元素是否已存在
const existingH1Element = img.parentElement.parentElement.parentElement.querySelector('h5');
if (!existingH1Element) {
// 創建h1元素
const h1Element = document.createElement('h5');
h1Element.textContent = extractedString;
// 將h1元素插入到img的父元素的父元素的父元素中
const parentElement = img.parentElement.parentElement.parentElement;
parentElement.appendChild(h1Element);
const email = extractedString; // 獲取
........後續待補
這邊我們所謂的email還只是userID而已,接下來重頭戲就是繼續寫一個Fetch。
// 發送Fetch請求,獲取最終的email
fetch("網站的網址", {
headers: {
"accept": "*/*",
"accept-language": "zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-CN;q=0.6",
"content-type": "application/json",
"sec-ch-ua": "\"Chromium\";v=\"118\", \"Google Chrome\";v=\"118\", \"Not=A?Brand\";v=\"99\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\"",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-site",
},
referrer: "網站的網址",
referrerPolicy: "strict-origin-when-cross-origin",
body: JSON.stringify({
operationName: "getUserPosts",
variables: {
userId: email // 把ID參數給他套入進去
},
query: `fragment PostFields on Post {
id
type
teach
learn
course
goal
location
desc
offer
tags
datetime
author {
id
name
position
photo
email
__typename
}
likeCount
liked
commentCount
__typename
}
query getUserPosts($userId: ID!) {
getUserPosts(userId: $userId) {
...PostFields
__typename
}
}`,
}),
method: "POST",
mode: "cors",
credentials: "include",
})
.then(async (res) => res.json())
.then((data) => {
let finalEmail = data.data.getUserPosts[0].author.email;
if (finalEmail.includes('@privaterelay.appleid.com')) {
finalEmail = '隱藏信箱不顯示';
}
h1Element.textContent = finalEmail;
});
}
}
}
});
}
這邊先解說什麼是"隱藏信箱不顯示",也就是apple登入提供隱藏信箱的選項,
當你用蘋果當作第三方登入,可以好好保護你的信箱。
現在就發現十分有用呢。ฅ^•ﻌ•^ฅ
偉災蘋果。
然後重點是這個fetch怎麼寫的?其實不用寫,使用開發者工具的好處之一就是舒服。
直接複製使用就好了。
這真的是你網路上搜尋10年都很難看到的技巧教學,
更何況是拿來做這麼有趣的練習(?)。
各位可以看到我備註雖然是寫h1 但其實後來製造的是h5標籤(前者太大了)
而這個腳本的作用
就是每次捲動到底部就會觸發 網頁會call資料出來渲染 我們也會透過forEach逐一針對
img裡的userID去當作參數 call資料出來 並把email這個創建於h5後
一起渲染出來
於是就像是我最初效果截圖的 email全部被叫出來
就像是原本就在網頁上一般⁽⁽٩(๑˃̶͈̀ ᗨ ˂̶͈́)۶⁾⁾
越強的文章,心得越少。
因為力氣都已經花光了XD
總之此文章僅是做教學用途,現在我的兩個系列JS教學,都已經來到中階部分。
初學者別擔心,往後未來還是有很多基礎的內容!
而且就像是各種武俠小說裡強調的,一拳一腳最強的其實就是來自每天的微小練習,
因此不要怕太簡單、簡單的東西累積起來就很強;
也不要害怕難關,難關也只是簡單的東西,累積起來(ノ◕ヮ◕)ノ*:・゚✧
接下來【前端動手玩創意】還會繼續更新,目前已經來到15了,
也許有一天會到達100吧!
那時候,
還請你也好好跟上嘿!ヾ(◎´・ω・`)ノ