可以叫我Peter, 這是GitHub連結
活躍的開元專案貢獻者
擔任過下列會議的講者
COSCUP、MOPCON......
工程師
DevOps
前後端技術研究
系統架構研究
網頁應用程式安全
熟悉PHP、Python與JavaScript等
曾服務過工業技術研究院(2017~2021)
研究過資通訊技術導入智慧電網與能源等領域
目前服務於資訊工業策進會(2021~)
研究資通訊技術導入到醫資、運動科技與碳排等領域
Array.from(document.querySelectorAll('[id]'))
.some(e => e._reactRootContainer !== undefined)
有各式的瀏覽器外掛可以偵測前端技術框架
啟用瀏覽器外掛會增加使用記憶體的資源,因此平常建議要偵測時再行啟用
也可利用document.querySelector等方式進行篩選元素去判斷
使用瀏覽器外掛識別外,也可看載入JavaScript函式庫套件去猜測出網站所用的技術
curl -I https://ideathon.data-sports.tw/ideathon/
HTTP/2 200
date: Sat, 15 Jun 2024 17:17:52 GMT
content-type: text/html; charset=UTF-8
strict-transport-security: max-age=31536000; includeSubDomains; preload
expires: Thu, 19 Nov 1981 08:52:00 GMT
cache-control: no-store, no-cache, must-revalidate
pragma: no-cache
set-cookie: ci_session=864f6bdb143d73c4343a7a28ecf0d5052b1ff443; expires=Sat, 15-Jun-2024 19:17:51 GMT; Max-Age=7200; path=/; HttpOnly; SameSite=Lax
cf-cache-status: DYNAMIC
report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=iPvAxYIU5Z3j1gR9FDmX8uRsrHfEoLupG3a5nx9xrDKZ3QORXVusUeZvERoygwdQePY2uGvaGdbfQhEQaEdvoud5aHZ0cO0LiXsC6kYKKavSsU1AuxhFVV51KUqPlpwTnPuiYh7OEVxrzg%3D%3D"}],"group":"cf-nel","max_age":604800}
nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
server: cloudflare
cf-ray: 8944373b0e965f63-SIN
alt-svc: h3=":443"; ma=86400
curl -I http://www.allianceair.in:8080/allianceair/en/login-signup
HTTP/1.1 200 OK
Accept-Ranges: none
Content-Length: 699
Content-Location: http://www.allianceair.in:8080/allianceair/en/login-signup/
Content-Type: text/html; charset=utf-8
Date: Sat, 15 Jun 2024 17:01:35 GMT
Date: Sat, 15 Jun 2024 17:01:35 GMT
Etag: ts12841357.9919817
Last-Modified: Sat, 15 Jun 2024 17:01:35 GMT
Server: waitress
Via: waitress
X-Cache-Rule: plone.content.folderView
X-Powered-By: Zope (www.zope.org), Python (www.python.org)
善用cURL指令並發送HTTP GET方法並從回應的標頭(header)訊息找出資訊
善用F12按鍵開啟開發者人員模式找到Cookie中是否有特殊session資訊
這方法對於使用程式語言所開發出的網站框架特別的有效
現今大部分的後端都會利用反向代理的技術在後端做請求的轉送(dispatch)
因此增加判斷標的網站後端技術的難度
或是準備可以運行Google Chrome與PHP 8.2的環境
虛擬機器(OVA檔):
使用Ubuntu 20.04進行建置與設定
https://u.pcloud.link/publink/show?code=kZNEmD0ZCYBMraLvKRHKLHhfsTT4oXbI9cw7
Virtualbox版本需要6.1或以上
虛擬機器若有需要輸入密碼則為:phpcrawler2024
php-crawlers-lab@phpcrawlerslab:~$ git clone https://github.com/peter279k/php-crawler-labs-2024
正複製到 'php-crawler-labs-2024'...
remote: Enumerating objects: 80, done.
remote: Counting objects: 100% (80/80), done.
remote: Compressing objects: 100% (54/54), done.
remote: Total 80 (delta 36), reused 69 (delta 25), pack-reused 0
展開物件中: 100% (80/80), 405.76 KiB | 640.00 KiB/s, 完成.
php-crawlers-lab@phpcrawlerslab:~$ php -v
PHP 8.2.20 (cli) (built: Jun 8 2024 21:37:11) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.20, Copyright (c) Zend Technologies
with Zend OPcache v8.2.20, Copyright (c), by Zend Technologies
php-crawlers-lab@phpcrawlerslab:~$ curl -sS https://getcomposer.org/installer | php
All settings correct for using Composer
Downloading...
Composer (version 2.7.7) successfully installed to: /home/php-crawlers-lab/composer.phar
Use it: php composer.phar
php-crawlers-lab@phpcrawlerslab:~$ cd php-crawler-labs-2024/
php-crawlers-lab@phpcrawlerslab:~/php-crawler-labs-2024$
php-crawlers-lab@phpcrawlerslab:~/php-crawler-labs-2024$ php ~/composer.phar install -n
No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install for more information.
Loading composer repositories with package information
Updating dependencies
Lock file operations: 21 installs, 0 updates, 0 removals
- Locking chrome-php/chrome (v1.11.0)
......
- Installing symfony/dom-crawler (v7.1.1): Extracting archive
12 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
12 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
php-crawlers-lab@phpcrawlerslab:~/php-crawler-labs-2024$
function SetCSRFToken(xhr) {
var CSRFToken = GetGuid();
xhr.setRequestHeader('CSRFToken', CSRFToken);
SetCK('CSRFToken', CSRFToken);
}
function extrandom() {
var arr = new Uint32Array(2);
var crypto = window.crypto || window.msCrypto; //相容IE
crypto.getRandomValues(arr);
var mantissa = (arr[0] * Math.pow(2, 20)) + (arr[1] >>> 12)
var extresult = mantissa * Math.pow(2, -52);
return extresult.toString(16).substring(2,6);
}
function GetGuid() {
//function s4() {
// return Math.floor((1 + Math.random()) * 0x10000)
// .toString(16)
// .substring(1);
//}
//return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
return extrandom() + extrandom() + '-' + extrandom() + '-' + extrandom() + '-' + extrandom() + '-' + extrandom() + extrandom() + extrandom();
}
//SetCookie
function SetCK(Name, Value, ExTime) {
if (document.cookie.indexOf(Name) >= 0) {
var expD = new Date();
expD.setTime(expD.getTime() + (-1 * 24 * 60 * 60 * 1000));
var uexpires = 'expires=' + expD.toUTCString();
document.cookie = Name + '=' + Value + '; ' + uexpires;
}
var d = new Date();
d.setTime(d.getTime() + (ExTime));
var expires = 'expires=' + d.toUTCString();
document.cookie = Name + '=' + Value + '; ' + expires;
}
//GetCookie
function GetCK(_Name) {
var name = _Name + '=';
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++)
{
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return '';
}
$ php lab1_failed_csrftoken.php
string(63) "{"d":"{\"Result\":\"0\",\"Message\":\"CSRFToken Check Fail\"}"}"
$ php lab1_arbitrary_csrftoken.php
string(63) "{"d":"{\"Result\":\"1\",\"Message\":\"43811590010470105001\"}"}"
<input type="button" class="btn btn-info" style="margin:0 3px 0 0;" value="是" onclick="showMailInfoPrint('56165990010370310004')">
<input type="button" class="btn btn-info" style="margin:0 3px 0 0;" value="確定" onclick="window.open('./PrintPDF.aspx?'+ Math.random());disablectrl();">
$ cd lab1/
$ php lab1_arbitrary_csrftoken_print.php
43815490010470105000.pdf file is saved.
$ file 43815490010470105000.pdf
43815490010470105000.pdf: PDF document, version 1.4
若把'ASP.NET_SessionId' => '0tkrkvxiqmfpl0cl143x4f5s'移除...
$ cd lab1/
$ php lab1_arbitrary_csrftoken_no_aspsession_print.php
45801390010470105002.pdf file is saved.
$ file 43815790010470105007.pdf
45801390010470105002.pdf: PDF document, version 1.4
瀏覽運動類型時,發現非常的多且複雜
若要手動全部瀏覽完成,可能會到明天過後
需要有自動化的方法將所有的運動類型收集回來
擬定收集的策略
分析前後端的技術與標的網站
選用需要用到的技術
實作並撰寫程式碼
執行程式與驗證
分析前後端的技術與標的網站
view-source:https://www.data-sports.tw/#/SportData/Service
/js/chunk-vendors.2624ce87.js
分析前後端的技術與標的網站
檢視chunk-vendors.2624ce87.js檔案的內容
可以發現裡面有Vue.js v2.6等版本的註解
因此可以得知該網站前端應是使用Vue.js 2作為開發的
透過開啟F12的網站開發人員工具,檢查網路請求的活動
https://www.data-sports.tw/prod-api/data/datatype
https://www.data-sports.tw/prod-api/data/specification?main_type=Sport&type=Run&subtype=100m
透過開啟F12的網站開發人員工具,檢查網路請求的活動
https://www.data-sports.tw/prod-api/data/datatype
透過開啟F12的網站開發人員工具,檢查網路請求的活動
https://www.data-sports.tw/prod-api/data/specification?main_type=Sport&type=Run&subtype=100m
上述的請求網址所帶的參數可以得知,運動數據類型有分成主類型、類型與子類型等
從前述的前後端技術分析可以知道,後端請求只能取得英文運動類型
而前端擁有中文運動類型的資料
分成兩部分
第一部分使用自動化方式啟動Google Chrome瀏覽器或是透過Selenium
第二部分則是將上述從前端取得到的內容與後端請求作搭配
最後整合成中英對照的運動數據類型
第一部分使用自動化方式啟動Google Chrome瀏覽器把各個運動類型進行儲存
lab2_sport_type_fetcher.php
第二部分使用後端所請求的網址替換去取得每個運動類型的欄位資訊
lab2_sport_type_collector.php
$ cd lab2/
$ php lab2_sport_type_collector.php
./spec/運動(Sport)_跑步(Run)_100公尺(100m).csv file is saved.
./spec/運動(Sport)_跑步(Run)_200公尺(200m).csv file is saved.
./spec/運動(Sport)_跑步(Run)_400公尺(400m).csv file is saved.
./spec/運動(Sport)_跑步(Run)_800公尺(800m).csv file is saved.
./spec/運動(Sport)_跑步(Run)_1500公尺(1500m).csv file is saved.
./spec/運動(Sport)_跑步(Run)_3公里路跑(3KRun).csv file is saved.
......
./spec/體適能(PhysicalFitness)_重量訓練(WeightTraining)_無子項目.csv file is saved.
./spec/體適能(PhysicalFitness)_肌力訓練(StrengthTraining)_無子項目.csv file is saved.
./spec/體適能(PhysicalFitness)_伸展運動(StretchingExercise)_無子項目.csv file is saved.
./spec/體適能(PhysicalFitness)_混合健身(Crossfit)_無子項目.csv file is saved.
./spec/體適能(PhysicalFitness)_滑步機(AirWalker)_無子項目.csv file is saved.
./spec/體適能(PhysicalFitness)_踏步機(StairStepper)_無子項目.csv file is saved.
./spec/體適能(PhysicalFitness)_飛輪(Flywheel)_無子項目.csv file is saved.
./spec/體適能(PhysicalFitness)_阻力訓練(ResistanceTraining)_無子項目.csv file is saved.
./spec/體適能(PhysicalFitness)_彼拉提斯(Pilates)_無子項目.csv file is saved.
./spec/體適能(PhysicalFitness)_瑜珈(Yoga)_無子項目.csv file is saved.
./spec/體適能(PhysicalFitness)_跑步機(Treadmill)_無子項目.csv file is saved.
./spec/體適能(PhysicalFitness)_橢圓機(Elliptical)_無子項目.csv file is saved.
./spec/生理(Physiology)_身體數值(BodyComposition)_無子項目.csv file is saved.
./spec/生理(Physiology)_睡眠(Sleep)_無子項目.csv file is saved.
在運動數據公益平台中,分成數據應用者與數據提供者
數據應用者能夠下載運動數據集
看起來有提供Swagger UI的介面可以呼叫API,https://api.data-sports.tw/swagger-ui
實作爬蟲
從前述以數據運用者登入到運動數據公益平台可以得知,前端驗證碼是在前端驗證
因此直接呼叫https://www.data-sports.tw/prod-api/member/login後端即可取得Token
再將取得的Token來取得運動數據
https://api.data-sports.tw/data/processed?main_type=Sport&type=Run&subtype=100m&data_size=100
lab3_retrieve_sport_data.php
$ cd lab3/
$ php lab3_retrieve_sport_data.php
Login is successful.
Retrieving sport data example is started...
array(3) {
["datetime"]=>
string(26) "2024-06-17T16:55:23.612580"
["data"]=>
array(2) {
["data"]=>
array(1) {
[0]=>
array(58) {
["main_type"]=>
string(5) "Sport"
["type"]=>
string(3) "Run"
["subtype"]=>
string(4) "100m"
["start_date"]=>
string(10) "2024-01-17"
......
Tesseract OCR進行圖形的辨識
透過圖片處理將圖片做灰階(Gray scale)處理,以提升圖形辨識的成功率
透過機器學習訓練模型的方式提升圖形辨識的成功率
透過呼叫Google Cloud Vision API進行圖形辨識
還有其他的圖形辨識的雲端服務,如AWS Image Recognition Services等
透過呼叫Cloud Vision API的方式進行辨識圖形驗證碼
下圖左邊為「jcaptcha.jpg」;右邊為「jcaptcha2.jpg」
$ export cloud_vision_api_key="cloud vision api key"
$ cd lab4/
$ php lab4_cloud_vision_api.php
string(3) "038"
The first request is done and terminate 3 seconds...
string(4) "5584"
從上述執行的結果可以得知,Google Cloud Vision API會受到驗證碼圖形的雜訊影響
導致辨識的結果錯誤,若需要改善驗證碼圖形的結果,則可考慮:
在發送請求前,先進行灰階圖像處理,以降低圖片的雜訊
驗證失敗就算了,再要一張圖片進行重新驗證
或是利用Google Speech To Text API進行語音辨識驗證碼
因此會加入除了圖形驗證碼之外,使用語音來當作驗證碼的途徑
因此除了透過OCR的方式進行圖像識別之外,也可考慮利用語音識別的技術
在該Lab中,使用Google Speech To Text API的技術來完成辨識驗證之語音檔
驗證碼語音檔出處:https://postserv.post.gov.tw/pstmail/main_mail.html
在lab5的資料夾中,可以找到驗證碼音檔「jcaptchasnd.wav」,答案為:5212
$ export speech_text_api_key="speech text API key"
$ cd lab5/
$ php lab5_speed_to_text.php
string(4) "5212"
也可以透過Cloudflare Worker AI中的Whisper模型進行語音辨識
透過呼叫API,在Cloudflare網路上運行預先訓練的機器學習模型並取得預測的結果
驗證碼語音檔出處:https://postserv.post.gov.tw/pstmail/main_mail.html
在lab6的資料夾中,可以找到驗證碼音檔「jcaptchasnd.wav」,答案為:5212
$ export cloudflare_ai_worker_token="Cloudflare AI Worker Token"
$ export cloudflare_account_token="Cloudflare Account Token"
$ cd lab6/
$ php lab6_cloudflare_whisper.php
array(4) {
["result"]=>
array(4) {
["text"]=>
string(7) "5 2 1 2"
["word_count"]=>
int(4)
["words"]=>
array(4) {
[0]=>
array(3) {
["word"]=>
string(1) "5"
["start"]=>
int(0)
["end"]=>
float(0.5600000023841858)
}
[1]=>
array(3) {
.........
與Google Speech Text to API不同的是,訓練的機器學習模型與方式不同
在辨識準確率上會比Google Speech Text to API來的差
音訊檔出處:https://reurl.cc/qVbr6D,檔名:1718731499912.mp3,答案為:637
執行lab6_failed_cloudflare_whisper.php後的結果如下:
$ export cloudflare_ai_worker_token="Cloudflare AI Worker Token" && export cloudflare_account_token="Cloudflare Account Token"
$ cd lab6/
$ php lab6_failed_cloudflare_whisper.php
array(4) {
["result"]=>
array(4) {
["text"]=>
string(3) "Leo"
["word_count"]=>
int(1)
["words"]=>
array(1) {
[0]=>
array(3) {
["word"]=>
string(3) "Leo"
["start"]=>
int(0)
["end"]=>
float(0.2800000011920929)
......
音訊檔出處:https://reurl.cc/qVbr6D,檔名:1718731499912.mp3,答案為:637
$ export speech_text_api_key="Google Cloud Speech To Text API key"
$ cd lab5/
$ php lab5_mp3_speed_to_text.php
string(3) "637"