從零開始寫Python爬蟲 --- 1.7 爬蟲實踐: 熱門排行榜小說批量下載 Ehco 5 個月前
本來只是準備做一個爬起點小說名字的爬蟲,後來想了一下,為啥不順便把小說的內容也爬下來呢。於是我就寫了這個爬蟲,他爬下了各類小說熱門排行榜上的所有章節內容,並儲存到本地。仔細想了一下,各種盜版小說閱讀器,是不是就是這樣做的呢。 目標分析:
首先來看看我們熱門排行榜的地址:
http://www.qu.la/paihangbang/
我們的目的很明確:
找到各類排行旁的的每一部小說的名字,和在該網站的連結: 觀察一下網頁的結構:
我們很容易就能發現,每一個分類都是包裹在:
<div class="index_toplist mright mbottom">
之中
這種調理清晰的網站,大大方便了我們爬蟲的編寫 小說標題和連結:
我們在剛才那個div裡自己尋找:
<div class="index_toplist mright mbottom"><div class="toptab" id="top_all_1"><span>玄幻奇幻排行</span><div><div class="topbooks" id="con_o1g_1" style="display: block;"><ul><li><span class="hits">05-06</span><span class="num">1.</span><a href="/book/168/" title="擇天記" target="_blank">擇天記</a></li> <li><span class="hits">05-06</span><span class="num">2.</span><a href="/book/176/" title="大主宰" target="_blank">大主宰</a></li> <!--中間省略了不少 --> <li><span class="hits">05-06</span><span class="num">3.</span><a href="/book/4140/" title="太古神王" target="_blank">太古神王</a></li> <li><span class="hits">05-06</span><span class="num">4.</span><a href="/book/5094/" title="雪鷹領主" target="_blank">雪鷹領主</a></li> <li><span class="hits">05-01</span><span class="num">15.</span><a href="/book/365/" title="武動乾坤" target="_blank">武動乾坤</a></li> </ul></div>
發現所有的小說都是在一個個列表裡,並且裡面清晰的定義了:
標題:title = div.a['title']
連結:link = 'http://www.qu.la/' + div.a['href']
這樣一來,我們只需要在當前頁面找到所有小說的串連,並儲存在列表就行了。 列表去重的小技巧:
資訊的同學會發現,就算是不同類別的小說,也是會重複出現在熱門排行榜的。
這樣無形之間就會浪費我們很多資源,尤其是在面對爬大量網頁的時候。
那麼我們如何從抓取的url列表裡去重呢。
剛學Python的小夥伴可能會去實現一個迴圈演算法,來去重,
但是Python的強大之處就在於他可以通過及其優美的方式來解決很多問題,這裡其實只要一行代碼就能解決:
url_list = list(set(url_list))
這裡我們調用了一個list的建構函式set:這樣就能保證列表裡沒有重複的元素了。是不是很簡單。 單個小說所有章節連結:
首先我們從前面擷取到的小說url串連選取一個做實驗:
比如我最愛的擇天記:
http://www.qu.la/book/168/
依然是無比清晰的網頁結構,點個贊:
<div class="box_con"><div id="list"><dl><dt>《擇天記》本文</dt> <dd> <a style="" href="/book/168/1748915.html">序 下山</a></dd> <dd> <a style="" href="/book/168/1748916.html">第一章 我改主意了</a></dd> <dd> <a style="" href="/book/168/1748917.html">第二章 為什麼</a></dd> <!-- 中間章節省略了 --> <dd> <a style="" href="/book/168/1748924.html">第九章 我有做錯什麼嗎?</a></dd> </div>
我們可以很容易的找到對應章節的串連:
這個代碼是節選,不能直接用。後面會有說明
link='http://www.qu.la/' + url.a['href']
好的,這樣我們就能把一篇小說的所有章節的連結爬下來了。
剩下最後一步:爬取文章內容: 文章內容的爬取:
首先我們開啟一章,並查看他的原始碼:
我們能發現所有的本文內容,都儲存在:
<div id='content'>
所有的章節名就更簡單了:
<h1> 第一章 我改主意了</h1>
那我們通過bs4庫的各種標籤的尋找方法,就能很簡單的找到啦
好了,讓我們看看具體代碼的實現: 代碼的實現:
模組化,函數式編程是一個非常好的習慣,我們堅持把每一個獨立的功能都寫成函數,這樣會使你的代碼簡單又可複用。 網頁抓取頭:
def get_html(url): try: r = requests.get(url, timeout=30) r.raise_for_status # 我手動測試了編碼。並設定好,這樣有助於效率的提升 r.encoding = ('utr-8') return r.text except: return "Someting Wrong。"
擷取熱門排行榜小說及其連結:
def get_content(url): ''' 爬取每一類型小說熱門排行榜, 按順序寫入檔案, 檔案內容為 小說名字+小說連結 將內容儲存到列表 並且返回一個裝滿url連結的列表 ''' url_list = [] html = get_html(url) soup = bs4.BeautifulSoup(html, 'lxml') # 由於小說排版的原因,曆史類和完本類小說不在一個div裡 category_list = soup.find_all('div', class_='index_toplist mright mbottom') history_finished_list = soup.find_all( 'div', class_='index_toplist mbottom') for cate in category_list: name = cate.find('div', class_='toptab').span.string with open('novel_list.csv', 'a+') as f: f.write("\n小說種類:{} \n".format(name)) # 我們直接通過style屬性來定位總熱門排行榜 general_list = cate.find(style='display: block;')