用Python自動(dòng)下載網(wǎng)站所有文件
最近維基 jie mi 徹底公開了網(wǎng)站的全部文件,我就在想如何使用 Python 將其下載到本地永久保存,于是就有了這篇文章,寫爬蟲會(huì)遇到很多坑,借鑒他人經(jīng)驗(yàn),考慮越全面,出錯(cuò)的概率就越小。
假如一個(gè)網(wǎng)站,里面有很多鏈接,有指向文件的,有指向新鏈接的,新的鏈接點(diǎn)擊進(jìn)去后,仍然是有指向文件的,有指向新鏈接的,類似一個(gè)文件夾,里面即有文件,又有目錄,目錄中又有文件和目錄。如何從這樣的網(wǎng)站上下載所有的文件,并按網(wǎng)站的目錄結(jié)構(gòu)來保存這些文件呢?
關(guān)鍵詞:Python、下載、正則表達(dá)式、遞歸。
按照自頂向下來設(shè)計(jì)程序,我們整理自己的思路,然后使用 Python 語言來翻譯下即可。
思路:由于目錄的深度不固定,也不可能窮舉,且每一個(gè)目錄的處理方式和子目錄父目錄的處理流程都是一樣的,因此我們可以使用遞歸來下載所有文件。
遞歸代碼必須要有退出條件,退出條件要放在前面,本例中的遞歸退出條件就是:如果是文件就下載,下載完遞歸函數(shù)即完成任務(wù)。
總體思路:1、給定一個(gè) url,判斷是否是文件,如果是文件,下載即可,然后函數(shù)結(jié)束。
2、如果給定 url 不是文件,那么訪問該 url,并獲取它下面的所有鏈接。
3、遍歷步驟 2 產(chǎn)生的所有鏈接,遞歸的執(zhí)行步驟 1 和 2,直到程序運(yùn)行結(jié)束。
以上思路,用代碼描述如下:
import urllib.requestimport requestsimport re, osdef get_file(url): ’’’ 遞歸下載網(wǎng)站的文件 :param url: :return: ’’’ if isFile(url): print(url) try: download(url) except: pass else: urls = get_url(url) for u in urls: get_file(u)
前面導(dǎo)入的包在接下來函數(shù)中會(huì)用到,下面就是逐漸層向下,實(shí)現(xiàn)子功能。
判斷鏈接是否指向文件:這里總結(jié) url 規(guī)律,很容易寫出。
def isFile(url): ’’’ 判斷一個(gè)鏈接是否是文件 :param url: :return: ’’’ if url.endswith(’/’): return False else: return True下載文件:
下載文件時(shí)要從 url 中獲取文件應(yīng)該存儲(chǔ)的位置,并使用 os.makedirs 來創(chuàng)建多級目錄。然后使用 urllib.request.urlretrieve 來下載文件。
def download(url): ’’’ :param url:文件鏈接 :return: 下載文件,自動(dòng)創(chuàng)建目錄 ’’’ full_name = url.split(’//’)[-1] filename = full_name.split(’/’)[-1] dirname = '/'.join(full_name.split(’/’)[:-1]) if os.path.exists(dirname): pass else: os.makedirs(dirname, exist_ok=True) urllib.request.urlretrieve(url, full_name)獲取 url 下的所有鏈接:
這里要具體網(wǎng)站具體分析,看看如何使用正則表達(dá)式獲取網(wǎng)頁中的鏈接,這樣的正則表達(dá)式可以說是再簡單不過了。
def get_url(base_url): ’’’ :param base_url:給定一個(gè)網(wǎng)址 :return: 獲取給定網(wǎng)址中的所有鏈接 ’’’ text = ’’ try: text = requests.get(base_url).text except Exception as e: print('error - > ',base_url,e) pass reg = ’<a href='http://www.aoyou183.cn/bcjs/(.*)' rel='external nofollow' >.*</a>’ urls = [base_url + url for url in re.findall(reg, text) if url != ’../’] return urls
這里有個(gè)小坑,就是網(wǎng)站有個(gè)鏈接是返回上級頁面的,url 的后輟是 ’../’ 這樣的鏈接要去掉,否則遞歸函數(shù)就限入了死循環(huán)。
接下來就是寫主函數(shù),執(zhí)行任務(wù)了,慢慢等它下載完吧。
if __name__ == ’__main__’: get_file(’https://file.wikileaks.org/file/’)
其實(shí),還會(huì)存兩個(gè)問題:
1、假如網(wǎng)站某頁有個(gè)鏈接它指向了首頁,那么遞歸程序仍然會(huì)限入一個(gè)死循環(huán),解決方法就是將訪問過的 url 保存在一個(gè)列表里(或者其他數(shù)據(jù)結(jié)構(gòu)),如果接下來要訪問的 url 不在此列表中,那么就訪問,否則就忽略。
2、如果下載的過程中程序突然報(bào)錯(cuò)退出了,由于下載文件較慢,為了節(jié)約時(shí)間,那么如何讓程序從報(bào)錯(cuò)處繼續(xù)運(yùn)行呢?這里可采用分層遞歸,一開始時(shí)先獲取網(wǎng)站的所有一級 url 鏈接,順序遍歷這些一級 url 鏈接,執(zhí)行上述的 get_file(url) ,每訪問一次一級 url 就將其索引位置加1(索引位置默認(rèn)為0,存儲(chǔ)在文件中或數(shù)據(jù)庫中),程序中斷后再運(yùn)行時(shí)先讀取索引,然后從索引處開始執(zhí)行即可。另外,每下載成功一個(gè)文件,就把對應(yīng)的 url 也保存在文件中或數(shù)據(jù)庫中,如果一級 url 下的鏈接已經(jīng)下載過文件,那么就不需要重新下載了。
以上就是用Python自動(dòng)下載網(wǎng)站所有文件的詳細(xì)內(nèi)容,更多關(guān)于python 自動(dòng)下載網(wǎng)站文件的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!
相關(guān)文章:
1. React實(shí)現(xiàn)一個(gè)倒計(jì)時(shí)hook組件實(shí)戰(zhàn)示例2. 小技巧處理div內(nèi)容溢出3. XML解析錯(cuò)誤:未組織好 的解決辦法4. CSS3實(shí)現(xiàn)動(dòng)態(tài)翻牌效果 仿百度貼吧3D翻牌一次動(dòng)畫特效5. XHTML 1.0:標(biāo)記新的開端6. 三個(gè)不常見的 HTML5 實(shí)用新特性簡介7. html清除浮動(dòng)的6種方法示例8. 使用css實(shí)現(xiàn)全兼容tooltip提示框9. Xml簡介_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理10. html中的form不提交(排除)某些input 原創(chuàng)
