論如何優(yōu)雅的復(fù)制一個(gè)網(wǎng)站的所有頁(yè)面
時(shí)間:2023-06-10 02:57:01 | 來(lái)源:網(wǎng)站運(yùn)營(yíng)
時(shí)間:2023-06-10 02:57:01 來(lái)源:網(wǎng)站運(yùn)營(yíng)
論如何優(yōu)雅的復(fù)制一個(gè)網(wǎng)站的所有頁(yè)面:
說(shuō)在前面
在業(yè)內(nèi)由于某些不可抗力的因素,我們不得不去做一些麻煩的事情來(lái)備份資料。為了盡最大可能挽留那些知識(shí),也就有了這篇文章和最后的腳本。(文章和腳本寫的都異常粗糙,希望師傅們不要介意。)
關(guān)于網(wǎng)站復(fù)制:
網(wǎng)站復(fù)制,也可稱為網(wǎng)站備份。是通過(guò)工具將網(wǎng)頁(yè)上的內(nèi)容全部保存下來(lái)。當(dāng)然不僅僅只是保存了一個(gè)html頁(yè)面,而是將網(wǎng)頁(yè)源碼內(nèi)所包含的css、js和靜態(tài)文件等全部保存,以在本地也可以完整的瀏覽整個(gè)網(wǎng)站。網(wǎng)絡(luò)上也有一些類似的工具,但使用起來(lái)并不理想。于是我打算自己寫一個(gè)Python腳本,方便個(gè)人對(duì)網(wǎng)站的備份,也方便一些網(wǎng)絡(luò)資料的收集。
處理并保存單個(gè)頁(yè)面
網(wǎng)站復(fù)制之需要保存的內(nèi)容
在開(kāi)始動(dòng)手寫代碼之前,我們需要確定一下要保存下來(lái)的內(nèi)容,以便后期編寫腳本來(lái)處理。
暫且分為這么兩個(gè)部分:
- 網(wǎng)頁(yè)源碼(單個(gè)頁(yè)面的html源碼)
- css、js與圖片文件(靜態(tài)文件)
css、js與圖片文件的下載地址都是從網(wǎng)頁(yè)源碼中獲取得到的,如圖:
內(nèi)容似乎不是很多,就只需要把靜態(tài)文件的下載地址從網(wǎng)頁(yè)源碼中提取出來(lái)然后下載保存就行了。但是實(shí)際情況會(huì)比較麻煩,為什么呢?
下圖是一個(gè)靜態(tài)文件的保存過(guò)程,文件在下載保存之前還需要處理相對(duì)地址進(jìn)而得到文件的下載地址以及保存到本地的路徑。除此之外,還要對(duì)HTML源碼中原來(lái)的相對(duì)地址進(jìn)行替換,讓文件內(nèi)容在本地也能夠正常的使用并顯示。這也是保存網(wǎng)頁(yè)相對(duì)來(lái)說(shuō)復(fù)雜的地方,在獲取鏈接之后我們來(lái)看看如何處理這個(gè)情況。
網(wǎng)站復(fù)制之鏈接的提取
有了一個(gè)頁(yè)面的鏈接,就可以通過(guò)這個(gè)鏈接獲取HTML源碼進(jìn)而獲取各類文件的相對(duì)地址。相較于路徑處理,這里的方式就簡(jiǎn)單直接很多。用beautifulsoup直接獲取標(biāo)簽,再獲取鏈接即可。過(guò)程如圖:
通過(guò)構(gòu)造一個(gè)ExtractLinks()函數(shù)來(lái)獲取一個(gè)網(wǎng)頁(yè)內(nèi)所有同類標(biāo)簽的同種參數(shù)??梢怨?jié)省一些重復(fù)的語(yǔ)句,方面獲取到css、js、img、a標(biāo)簽的url地址。
這里的過(guò)濾的內(nèi)容如下:
- 去重復(fù)
- 丟棄無(wú)效url地址如:#、javascript偽協(xié)議等
那獲取了鏈接之后就需要對(duì)路徑進(jìn)行處理了。
網(wǎng)站復(fù)制之路徑的處理
在網(wǎng)頁(yè)源碼當(dāng)中,相對(duì)地址的形式有很多種情況。
需要正常應(yīng)對(duì)的相對(duì)地址形式有多少種呢?用圖片文件作為一個(gè)例子,簡(jiǎn)單總結(jié)了一些如下:
(在確定的形式之外又會(huì)有很多種我們不能預(yù)測(cè)的情況。對(duì)于那些不確定的地址,就直接作丟棄處理。)
從相對(duì)地址的類型也能看出來(lái),要寫處理的代碼的話會(huì)有很多不同的情況,每種情況基本都需要進(jìn)行單獨(dú)的處理,并且其中的邏輯也是稍微有點(diǎn)繞。
這里我們建立一個(gè)ProcessResourcePath的函數(shù)來(lái)處理文件相對(duì)地址的關(guān)系
處理鏈接時(shí)需要的傳入?yún)?shù):
- 頁(yè)面地址:用于獲取源碼中的文件地址,并根據(jù)url的層級(jí)關(guān)系確定圖片保存的路徑。
- 圖片地址:根據(jù)頁(yè)面地址與圖片地址確定圖片的下載地址
返回的參數(shù):
- 頁(yè)面地址
- 圖片地址
- 圖片的下載地址
- 替換的圖片地址
- 保存的路徑
- 圖片地址的類型(方便DEBUG)
函數(shù)處理的過(guò)程如圖:
函數(shù)解釋:
- Md5Encrypt(): 是用作對(duì)站外文件的下載鏈接進(jìn)行MD5加密,防止重復(fù)下載
- GetUrlPart(): 用于獲取url中不同部分的值,方便對(duì)url的處理
- ProcessResourcePath(): 處理頁(yè)面地址和圖片地址的相對(duì)關(guān)系
URL層級(jí)關(guān)系的處理就不解釋了,比較麻煩。如果有對(duì)單個(gè)過(guò)程感興趣可以直接跟我交流喔。通過(guò)這個(gè)函數(shù)的處理之后,保存網(wǎng)頁(yè)時(shí)就變得非常方便。因?yàn)槟阒恍枰獙ss、js、圖片等文件的鏈接提取出來(lái)進(jìn)行處理,將處理完的地址進(jìn)行替換即可。
網(wǎng)站復(fù)制之單個(gè)頁(yè)面的處理與保存
那在保存單個(gè)頁(yè)面之前,需要往前思考一點(diǎn)。最終的文件都是要保存到一個(gè)總文件夾里,這個(gè)文件夾的名字得提前確定。我這里想把一個(gè)網(wǎng)站保存到以域名為名稱的文件夾中,比如
http://www.bilibili.com 的所有頁(yè)面和資源就全部保存到www_bilibili_com的文件夾里。所以,保存單個(gè)頁(yè)面所需要的參數(shù)就為頁(yè)面的地址,再通過(guò)頁(yè)面的地址獲取域名來(lái)定義保存的文件夾。保存的時(shí)候需要將頁(yè)面html源碼中的地址進(jìn)行替換。
文件和頁(yè)面都直接保存下來(lái)了,該怎么讓頁(yè)面可以正常調(diào)用本地的js和顯示本地的圖片呢?我們需要做的就是將頁(yè)面中的文件地址都進(jìn)行替換。配合之前的網(wǎng)址處理函數(shù),將頁(yè)面地址和文件地址通過(guò)ProcessResourcePath處理后得到適配本地的地址,然后進(jìn)行替換即可。
不止是css、js、圖片文件需要處理好相對(duì)位置,單個(gè)頁(yè)面也需要處理里面的各個(gè)鏈接。這樣在本地就可以在各個(gè)頁(yè)面正常切換。因?yàn)樵诜?wù)器上的頁(yè)面是動(dòng)態(tài)生成的,我們把網(wǎng)頁(yè)保存下來(lái)后,都應(yīng)該修改為.html結(jié)尾的文件,于是就有這幾種情況:
- 以.html結(jié)尾的 => 直接以原文件名保存
- 以.php等不適.html結(jié)尾的 => 在原來(lái)的文件名后添加.html后綴保存
- 沒(méi)有文件名的 => 保存為index.html
在保存單個(gè)頁(yè)面的時(shí)候進(jìn)行一次這樣的處理,在鏈接地址替換的時(shí)候?qū)標(biāo)簽內(nèi)的地址也進(jìn)行一次這樣的處理就可以保證各個(gè)頁(yè)面的地址之間的正常交互了。(對(duì)鏈接的處理僅限于同一個(gè)子域名)
保存文件的總結(jié)
保存并處理一個(gè)網(wǎng)頁(yè),就是要保證css、js、圖片文件能夠正常調(diào)用與顯示。并且鏈接能夠與多個(gè)頁(yè)面進(jìn)行交互。
獲取網(wǎng)站的所有頁(yè)面
獲取網(wǎng)站的所有頁(yè)面的鏈接
通過(guò)前面的內(nèi)容,已經(jīng)可以獲取到單個(gè)頁(yè)面的所有內(nèi)容,并且可以較好的處理里面的鏈接關(guān)系。那該怎么獲取得到整個(gè)網(wǎng)站的所有頁(yè)面呢?非常的簡(jiǎn)單粗暴,就是遍歷所有鏈接!(也沒(méi)想到其他好的方式了)遍歷網(wǎng)頁(yè)url流程圖:
通過(guò)這個(gè)方式把網(wǎng)站所有的url獲取到,然后批量進(jìn)行單個(gè)頁(yè)面的保存即可。
加快獲取鏈接與保存文件的速度
為了加快獲取網(wǎng)站所有頁(yè)面的鏈接和保存每個(gè)頁(yè)面的文件,我們需要使用多線程和協(xié)程來(lái)加快執(zhí)行效率。
我使用的是自己寫的一個(gè)簡(jiǎn)單的協(xié)程框架:
協(xié)程初體驗(yàn)之簡(jiǎn)單的利用框架
這個(gè)框架的流程如下圖所示:
框架寫的比較簡(jiǎn)陋,修改一下是可以直接用到復(fù)制網(wǎng)站腳本里面的。具體內(nèi)容可以進(jìn)文章里面細(xì)看。
通過(guò)協(xié)程,可以顯著加快獲取網(wǎng)站所有頁(yè)面與保存單個(gè)頁(yè)面的速度。
總結(jié)
Github項(xiàng)目
文章中各個(gè)部分的代碼實(shí)現(xiàn)都在一個(gè)python腳本當(dāng)中,github倉(cāng)庫(kù)地址如下:
SiteCopy:
https://github.com/Threezh1/SiteCopy復(fù)制單個(gè)頁(yè)面:
python sitecopy.py -u "https://threezh1.com"
復(fù)制整個(gè)網(wǎng)站(-t設(shè)置線程):
python sitecopy.py -u "https://threezh1.com" -e -t 30
聲明:
對(duì)互聯(lián)網(wǎng)任何網(wǎng)站的復(fù)制需在取得授權(quán)后方可進(jìn)行,若使用者因此做出危害網(wǎng)絡(luò)安全的行為后果自負(fù),與作者無(wú)關(guān),特此聲明。
存在的問(wèn)題
- 目錄替換時(shí)在有些情況下會(huì)進(jìn)行多次替換導(dǎo)致頁(yè)面無(wú)法正常顯示
- 網(wǎng)站或圖床有防爬措施時(shí)無(wú)法正常保存
- 網(wǎng)絡(luò)問(wèn)題導(dǎo)致腳本無(wú)法正常執(zhí)行
非常希望能夠和師傅們共同交流對(duì)這些問(wèn)題的解決方式,我的郵箱:makefoxm@qq.com
復(fù)制網(wǎng)站測(cè)試
- 復(fù)制自己的博客:https://threezh1.com 花費(fèi)時(shí)間:2分鐘48秒
運(yùn)行截圖:
目錄截圖:
頁(yè)面截圖:
本文轉(zhuǎn)自先知社區(qū),原作者Threezh1(侵刪)
推薦閱讀:
- 事發(fā)突然,我中了勒索病毒!
- 破解Wif密碼最簡(jiǎn)單的步驟,僅需三步
- 常用紅隊(duì)安全攻防總結(jié)
關(guān)注【網(wǎng)絡(luò)安全資源庫(kù)】,學(xué)習(xí)更多網(wǎng)絡(luò)安全干貨,還可獲得超多資料哦~