詳細記錄了python爬取小說《元尊》的整個過程,看了你必會~
學了好幾天的滲透測試基礎理論,週末了讓自己放鬆一下,最近聽說天蠶土豆有一本新小說,叫做《元尊》,學生時代的我可是十分喜歡讀天蠶土豆的小說,《鬥破蒼穹》相信很多小夥伴都看過吧。今天我們就來看看如果一步一步爬下來《元尊》的所有內容。
首先我們需要選擇一個網站進行爬取,我這邊使用的是書家園網站,其它網站的操作也是類似原理。
相關庫檔案
我們使用的庫有requests、re和time,其中re和time都是python自帶庫,我們只需要安裝一個requests庫。
pip install requests
編碼過程
我們可以先訪問書家園網站找到《元尊》書籍首頁的url——https://www.shujy.com/5200/9683/。
通過requests進行請求,然後將html打印出來。
import requests url ='https://www.shujy.com/5200/9683/' response = requests.get(url) html = response.text print(html)
打印出來如下圖:
我們找到html中關於文章標題和作者的部分
我們通過正則表示式將標題和作者提取出來
title = re.findall(r'<meta property="og:novel:book_name" content="(.*?)"/>',html)[0] author = re.findall(r'<meta property="og:novel:author" content="(.*?)"/>',html)[0]
接下來我們就需要將每一章小說的連結拿出來了,我們通過瀏覽器中F12工具
- 點選左上角的箭頭
- 點選我們需要定位的元素,我們需要找到每一章的連結,所以我們點選“正文 第一章”
- 我們就可以看到開發者工具中出現了物件在html中的位置
分析連結的位置我們發現都是在“<div id="list"></div>”這個div標籤中間,然後每個連結都是在href後面。那我們先將這個div標籤中的內容取出來然後對取出的內容找到所有的href標籤中的連結放在一個列表中。
dl =re.findall(r'<div id="list">.*?</div>',html,re.S)[0] chapter_info_list=re.findall(r'<a href="(.*?)">(.*?)</a>',dl)
這樣我們就拿到了所有的章節列表,現在我們需要考慮如何去獲取每一章節的內容。我們將首頁的URL和每一個章節的連結進行拼接。
chapter_url = url+'/'+chapter_url chapter_url = chapter_url.replace(' ','')
然後我們同樣通過requests庫獲取到章節內容的HTML檔案
chapter_response = requests.get(chapter_url) chapter_html = chapter_response.text
通過同樣的方式,我們發現正文的內容都是在“<div id="content"></div>”這樣一個div標籤中
我們將這個div標籤中的正文內容全部拿出來
#獲取第一頁正文內容 chapter_content = re.findall(r'<div id="content">(.*?)</div>',chapter_html,re.S)[0]
我們將取出來的內容列印一下看看
我們發現還存在一些“<br />”和“  ”這樣的元素,這些都是我們不希望看到的,那我們就通過replace函式給過濾掉。
chapter_content = chapter_content.replace('  ','') chapter_content = chapter_content.replace('<br />','')
我們看看過濾後的內容
發現還是有些不對,為什麼每一行文字都空了一行呢?我們通過debug看一下過程中的chapter_content內容
果然還存在一些製表符,那我們就只保留一個換行符“\n”
chapter_content = chapter_content.replace('\r\n\r', '')
這樣我們就將這個頁面的正文全部扒下來了,但我們翻到頁面的末尾我們發現每章可能不僅僅一頁,可能存在兩頁、三頁甚至更多內容,怎麼才能完整的將這不確定的內容拿下來呢?
我們看到在每一頁的正文中都寫明瞭這一章一共需要多少頁,並且提供了下一頁的連結,我們就通過這個線索來完成。
首先我們需要將總共的頁數和下一頁的連結取出來。
chapter_url,current_page,total_pages = re.findall(r'本章未完,請點選<a style="color:red;" href="(.*?)">下一頁</a>繼續閱讀!第(.*?)頁 / 共(.*?)頁</p>', chapter_content,re.S)[0]
然後我們利用一個for迴圈去取內容,取的方式和前面類似,就不再詳細描述了,直接上程式碼。
for i in range(1,int(total_pages)): chapter_url,current_page,total_pages = re.findall(r'本章未完,請點選<a style="color:red;" href="(.*?)">下一頁</a>繼續閱讀!第(.*?)頁 / 共(.*?)頁</p>',chapter_content)[0] chapter_url = url+'/'+chapter_url chapter_url = chapter_url.replace(' ','') chapter_response = requests.get(chapter_url) chapter_html =chapter_response.text chapter_content = re.findall(r'<div id="content">(.*?)</div>', chapter_html, re.S)[0] chapter_content = chapter_content.replace('  ', '') chapter_content = chapter_content.replace('<br />', '') chapter_content = chapter_content.replace('\r\n\r', '') f.write('\n') f.write(chapter_content)
最後我們只需要在外面加一個檔案寫入操作,將每一次讀出的正文內容寫入進去就好了。
with open('%s.txt'%title,'w') as f: f.write(title) f.write('\n') f.write(author) f.write('\n')
list index out of range報錯的處理
看著是一切都完成了,可是在我最後來下載的時候,經常在不同的章節出現這樣的錯誤。
這一次可能是在第四章出現問題,下一個可能是在第十章出現問題,總之不固定。我查詢了一下這種錯誤一般會有兩種情況
- list[index]index超出範圍
- list是一個空的,沒有一個元素,進行list[0]就會出現錯誤!
雖說查詢到了原因,這兩種情況都不能應該出現隨機章節出現報錯呀,我還是沒有找到原因,如果有大神看到了可以指定一二。
但是我找到一個規避的措施,就是既然它是隨機章節報錯,那就是我一旦檢測到報錯之後就再重新請求一次url,重新通過正則校驗一次。為此我拎出來一個這樣的函式。
def find(pattern,string,url): try: chapter_content = re.findall(pattern, string, re.S)[0] return chapter_content except Exception as e: print(e) time.sleep(1) chapter_response = requests.get(url) chapter_html = chapter_response.text print(chapter_html) print(url) i = find(pattern,chapter_html,url) return i
執行之後果然可行,我一直執行著,現在已經下載了一百多章了
現在看來唯一的缺點就是有點慢,原諒菜鳥小白還沒有怎麼弄過多執行緒和多程序,下次我們再來改進吧。