要求
第一部分:
第二部分:
正題
分析一下他們的代碼,我在瀏覽器中對應位置右鍵,然后點擊檢查元素,可以找到對應部分的代碼。但是,直接查看當前網頁的源碼發現,里面並沒有對應的代碼。我猜測這里是根據服務器上的數據動態生成的這部分代碼,所以我們需要找到數據文件,以便向服務器申請,得到這部分資源。

在剛才查看元素的地方接着找數據文件,在Network里面的文件中很順利的就找到了,並在報文中拿到了URL和請求方法。

查看一下這個文件發現是JSON文件,那樣的話難度就又降低了,因為Python中有json庫,解析json的能力很強。可以直接將json轉換為字典和列表類型。

在這里我簡單介紹一下數據解析的過程吧。首先,我將爬取到的json文本轉換成某種數據類型,具體由數據決定,一般不是字典就是列表。查看類型發現是字典,且字典中有三個key值,而我們需要的key在一個叫data的key中。

而data中的數據是一個學生信息的列表類型,列表的每個元素都是一個字典,包括學生姓名,學號等信息。可以利用下標獲取列表元素,並用key值得到你想拿到的信息。比如,利用Url得到網頁鏈接。


這時候我們爬取需要的信息的准備工作可以說是結束了,我們拿到了數據的URL,並且知道了數據類型和數據結構。於是,我們只需要用requests庫爬一下這個頁面,然后用json解析一下,並且篩選有用的信息就好了。
(沒用到BeautifulSoup和re庫有點小失落)
接下來就是創建文件,就沒有什么難度了。只是在為每個學生創建文件的時候注意一下,創建好以后及時的回到上層目錄,否則,可能會讓文件一層層的嵌套下去。
代碼
# -*- coding:utf-8 -*- import requests import json import os #抓取頁面 url = 'https://edu.cnblogs.com/Homework/GetAnswers?homeworkId=2420&_=1542959851766' try: r = requests.get(url,timeout=20) r.raise_for_status() r.encoding = r.apparent_encoding except: print('網絡異常或頁面未找到,請重試') #利用json拿到數據列表,每個列表元素都是字典 datas = json.loads(r.text)['data'] result = "" #數據處理 for data in datas: result += str(data['StudentNo'])+','+data['RealName']+','+data['DateAdded'].replace('T',' ')+','+data['Title']+','+data['Url']+'\n' #寫入文件 with open('hwlist.csv','w') as f: f.write(result) #創建文件夾hwFolder os.mkdir('hwFolder') os.chdir('hwFolder') #創建每個學生的作業文件 for data in datas: #創建目錄 os.mkdir(str(data['StudentNo'])) os.chdir(str(data['StudentNo'])) #抓取頁面 try: webmsg = requests.get(data['Url'],timeout=20) webmsg.raise_for_status() webmsg.encoding = webmsg.apparent_encoding except: print('網絡異常或頁面未找到,請重試') #保存抓到的頁面 with open(str(data['StudentNo'])+'.html','wb') as f: f.write(webmsg.content) os.chdir(os.path.pardir)
部分結果展示

上圖是hwlist.csv文件的部分結果(Excel下打開)
玩個稍復雜點的
像之前那樣爬取頁面的話,其實是有點問題的。首先,我們只是爬取了頁面的內容,但是並沒有抓取到頁面的樣式,頁面顯示會不太正常,排版混亂。其次,頁面中還有圖片等元素都不會顯示出來。而且,如果遇到網絡問題代碼需要再次運行的時候還會遇到一個問題,那就是目錄已經存在了,我們在創建目錄就會失敗。除此之外還是有不少問題的,此處我先解決之前說到的幾個問題。即顯示問題和目錄問題。
如何解決我提到的這些問題呢,目錄問題我使用了一種比較容易實現的方案,那就是先判斷當前目錄是否存在,如果不存在就創建目錄,否則就什么都不做。至於文件,暫定的方法是直接覆蓋。顯示問題也比較好解決,抓取網頁和抓取樣式或者網頁其實都一樣,就是用URL發送一個請求,來獲得這個資源,其實和抓取HTML相比,就是文件格式不太一致。
以抓取樣式表(CSS)為例,樣式的URL怎么獲取呢?有一些樣式是在一個叫做Link的標簽的href屬性里,這里面就是外聯樣式存儲的位置。把它提取出來,請求這個樣式,並且修改原來的href屬性為抓到的文件在自己電腦上的保存位置即可。這樣的話即可保證抓到的CSS可以正常使用,確保排版正確。
當然了,即使這樣,和原本的網頁也是有差別的,因為抓取到的資源還是不夠,和瀏覽器中獲得的元素對比一下就會發現還差不少。鑒於本人能力有限,這里就補充一下爬取外聯CSS和圖片的內容,感興趣的可以看一看。
Tips:這里解析HTML頁面借助了強大的BeautifulSoup4庫(解析標簽和玩一樣)和re庫,使工作量減少了不少。(安裝bs4庫: pip install BeautifulSoup4)
# -*- coding:utf-8 -*- import requests import json import os import re from bs4 import BeautifulSoup def getHtml(url,timeout=110): try: res = requests.get(url,timeout) res.raise_for_status() res.encoding = res.apparent_encoding return res except: print('網絡異常,'+url+"爬取失敗") def saveFile(name,content,mode='w'): try: with open(name,mode) as f: f.write(content) except: print("文件"+name+"創建失敗") def getSource(text): #抓取樣式 root_url = 'https://www.cnblogs.com' soup = BeautifulSoup(text,'html.parser') for i in soup('link'): css_list = [css for css in i['href'].split('/') if 'css' in css] if css_list!=[]: filename = re.search(r'.*css',css_list[0]).group(0) r = requests.get(root_url+i['href']) saveFile(filename,r.content,'wb') text = text.replace(i['href'],'Source/'+filename) #抓取圖片 用戶自己插入的圖片和網站自己生成的圖片都抓 #用戶自己插的那些格式很亂……用戶自己搞的東西就是個坑 for i in soup('img'): try: img_list = [img for img in i['src'].split('/') if 'gif' in img or 'png' in img or 'jpeg' in img] except KeyError :#某用戶自己改了HTML代碼 得讓我單獨判斷一下 img_list = [] if img_list!=[]: filename = img_list[0] try: r = requests.get(root_url+i['src']) r.raise_for_status() except: if not 'http' in i['src']: r = requests.get("https:"+i['src']) else:#又是某用戶寫博客用了HTML編輯器,寫的還不對 r = requests.get(i['src']) saveFile(filename,r.content,'wb') text = text.replace(i['src'],'Source/'+filename) #text用於修改原始的頁面鏈接,保證本地可以正常查看頁面 return text #############################主程序############################ #抓取頁面 並得到數據 r = getHtml('https://edu.cnblogs.com/Homework/GetAnswers?homeworkId=2420&_=1542959851766') datas = json.loads(r.text)['data'] #處理數據並將數據寫入文件 result = "" for data in datas: result += str(data['StudentNo'])+','+data['RealName']+','+data['DateAdded'].replace('T',' ')+','+data['Title']+','+data['Url']+'\n' saveFile('hwlist.csv',result,'w') #創建文件夾hwFolder if not os.path.exists('hwFolder'): os.mkdir('hwFolder') os.chdir('hwFolder') #創建每個學生的作業文件 for data in datas: #創建目錄 if not os.path.exists(str(data['StudentNo'])): os.mkdir(str(data['StudentNo'])) os.chdir(str(data['StudentNo'])) #抓取頁面 webmsg = requests.get(data['Url']) print('當前的URL:'+data['Url'])#等待的過程有字出來不會無聊 #頁面的一些資源 if not os.path.exists('Source'): os.mkdir('Source') os.chdir('Source') webtext = getSource(webmsg.text) os.chdir(os.path.pardir) saveFile(str(data['StudentNo'])+'.html',webtext.encode(),'wb') os.chdir(os.path.pardir)
如果你的網絡沒問題,講道理,應該不會拋異常。接下來找個頁面看看效果吧:


排版抓出來了,挺炫的,當然,圖片也抓了。


考慮到有人會HTML,我把被程序調整后的HTML代碼找一個給大家看看,箭頭指向的地方都是程序自己改過的地方:

其實,雖然現在又和原頁面接近了不少,但是……我暫時沒有時間繼續完善了,以后還會繼續完善。給大家一個原博客的圖片,你會我先我還是少了些東西。暫時先這樣吧。

