Python3 網絡爬蟲(二):下載小說的正確姿勢(2020年最新版)

點贊再看,養成習慣,微信公衆號搜索【JackCui-AI】關注一個在互聯網摸爬滾打的潛行者。

一、前言

網路爬蟲,一般爬取的東西無非也就四種:文字、圖片、音樂、視頻。

這是明面上,能想到的東西,除了這些還有一些危險的操作,容易被請喝茶的,就不討論了。

咱們循序漸進,先談談如何下載文字內容。

PS:文中出現的所有代碼,均可在我的 Github 上下載:點擊查看

二、詭祕之主

說到下載文字內容,第一個想到的就是下載小說了。

在曾經的以《一念永恆》小說爲例進行講解的 CSDN 文章中,有網友留言道:

那麼,今天我就再安利一本小說《詭祕之主》。

起點中文網,它的月票基本是月月第一。

這篇文章其實是在教大家如何白嫖,不過有能力支持正版的朋友,還是可以去起點中文網,支持一下作者的,畢竟創作不易。

三、準備工作

話不多說,直接進入我們今天的正題,網絡小說下載。

1、背景介紹

小說網站,“新筆趣閣”:

https://www.xsbiquge.com/

盜版小說網站有很多,曾經爬過“筆趣看”,這回咱換一家,爬“新筆趣閣”,雨露均沾嘛!

“新筆趣閣”只支持在線瀏覽,不支持小說打包下載。本次實戰就教大家如何“優雅”的下載一篇名爲《詭祕之主》的網絡小說。

2、爬蟲步驟

要想把大象裝冰箱,總共分幾步?

要想爬取數據,總共分幾步?

爬蟲其實很簡單,可以大致分爲三個步驟:

  • 發起請求:我們需要先明確如何發起 HTTP 請求,獲取到數據。
  • 解析數據:獲取到的數據亂七八糟的,我們需要提取出我們想要的數據。
  • 保存數據:將我們想要的數據,保存下載。

發起請求,我們就用 requests 就行,上篇文章已經介紹過。

解析數據工具有很多,比如xpath、Beautiful Soup、正則表達式等。本文就用一個簡單的經典小工具,Beautiful Soup來解析數據。

保存數據,就是常規的文本保存。

3、Beautiful Soup

簡單來說,Beautiful Soup 是 Python 的一個第三方庫,主要幫助我們解析網頁數據。

在使用這個工具前,我們需要先安裝,在 cmd 中,使用 pip 或 easy_install 安裝即可。

pip install beautifulsoup4
# 或者
easy_install beautifulsoup4

安裝好後,我們還需要安裝 lxml,這是解析 HTML 需要用到的依賴:

pip install lxml

Beautiful Soup 的使用方法也很簡單,可以看下我在 CSDN 的講解或者官方教程學習,詳細的使用方法:

我的 Beautiful Soup 講解:點擊查看

官方中文教程:點擊查看

四、小試牛刀

我們先看下《詭祕之主》小說的第一章內容。

URL:https://www.xsbiquge.com/15_15338/8549128.html

我們先用已經學到的知識獲取 HTML 信息試一試,編寫代碼如下:

import requests

if __name__ == '__main__':
    target = 'https://www.xsbiquge.com/15_15338/8549128.html'
    req = requests.get(url = target)
    req.encoding = 'utf-8'
    print(req.text)

這也就是爬蟲的第一步“發起請求”,得到的結果如下:

可以看到,我們很輕鬆地獲取了 HTML 信息,裏面有我們想要的小說正文內容,但是也包含了一些其他內容,我們並不關心 div 、br 這些 HTML 標籤。

如何把正文內容從這些衆多的 HTML 標籤中提取出來呢?

這就需要爬蟲的第二部“解析數據”,也就是使用 Beautiful Soup 進行解析。

現在,我們使用上篇文章講解的審查元素方法,查看一下我們的目標頁面,你會看到如下內容:

不難發現,文章的所有內容都放在了一個名爲div的“東西下面”,這個"東西"就是 HTML 標籤。HTML 標籤是 HTML 語言中最基本的單位,HTML 標籤是 HTML 最重要的組成部分。不理解,沒關係,我們再舉個簡單的例子:

一個女人的包包裏,會有很多東西,她們會根據自己的習慣將自己的東西進行分類放好。鏡子和口紅這些會經常用到的東西,會歸放到容易拿到的外側口袋裏。那些不經常用到,需要注意安全存放的證件會放到不容易拿到的裏側口袋裏。

HTML 標籤就像一個個“口袋”,每個“口袋”都有自己的特定功能,負責存放不同的內容。顯然,上述例子中的 div 標籤下存放了我們關心的正文內容。這個 div 標籤是這樣的:

<div id="content" style="font-size: 10pt;">

細心的朋友可能已經發現,除了 div 字樣外,還有 id 。id 就是 div 標籤的屬性,content是屬性值,一個屬性對應一個屬性值。

屬性有什麼用?它是用來區分不同的 div 標籤的,因爲 div 標籤可以有很多,id 可以理解爲這個 div 的身份。

這個 id 屬性爲 content 的 div 標籤裏,存放的就是我們想要的內容,我們可以利用這一點,使用Beautiful Soup 提取我們想要的正文內容,編寫代碼如下:

import requests
from bs4 import BeautifulSoup

if __name__ == '__main__':
    target = 'https://www.xsbiquge.com/15_15338/8549128.html'
    req = requests.get(url = target)
    req.encoding = 'utf-8'
    html = req.text
    bs = BeautifulSoup(html, 'lxml')
    texts = bs.find('div', id='content')
    print(texts)

代碼很簡單,bf.find('div', id='content') 的意思就是,找到 id 屬性爲 content 的 div 標籤。

可以看到,正文內容已經順利提取,但是裏面還有一些 div 和 br 這類標籤,我們需要進一步清洗數據。

import requests
from bs4 import BeautifulSoup

if __name__ == '__main__':
    target = 'https://www.xsbiquge.com/15_15338/8549128.html'
    req = requests.get(url = target)
    req.encoding = 'utf-8'
    html = req.text
    bs = BeautifulSoup(html, 'lxml')
    texts = bs.find('div', id='content')
    print(texts.text.strip().split('\xa0'*4))

texts.text 是提取所有文字,然後再使用 strip 方法去掉回車,最後使用 split 方法根據 \xa0 切分數據,因爲每一段的開頭,都有四個空格。

程序運行結果如下:

所有的內容,已經清洗乾淨,保存到一個列表裏了。

小說正文,已經順利獲取到了。要想下載整本小說,我們就要獲取每個章節的鏈接。我們先分析下小說目錄:

URL:https://www.xsbiquge.com/15_15338/

審查元素後,我們不難發現,所有的章節信息,都存放到了 id 屬性爲 list 的 div 標籤下的 a 標籤內,編寫如下代碼:

import requests
from bs4 import BeautifulSoup

if __name__ == '__main__':
    target = 'https://www.xsbiquge.com/15_15338/'
    req = requests.get(url = target)
    req.encoding = 'utf-8'
    html = req.text
    bs = BeautifulSoup(html, 'lxml')
    chapters = bs.find('div', id='list')
    chapters = chapters.find_all('a')
    for chapter in chapters:
        print(chapter)

bf.find('div', id='list') 就是找到 id 屬性爲 list 的 div 標籤,chapters.find_all('a') 就是在找到的 div 標籤裏,再提取出所有 a 標籤,運行結果如下:

可以看到章節鏈接和章節名我們已經提取出來,但是還需要進一步解析,編寫如下代碼:

import requests
from bs4 import BeautifulSoup

if __name__ == '__main__':
    server = 'https://www.xsbiquge.com'
    target = 'https://www.xsbiquge.com/15_15338/'
    req = requests.get(url = target)
    req.encoding = 'utf-8'
    html = req.text
    bs = BeautifulSoup(html, 'lxml')
    chapters = bs.find('div', id='list')
    chapters = chapters.find_all('a')
    for chapter in chapters:
        url = chapter.get('href')
        print(chapter.string)
        print(server + url)

可以看到,chapter.get('href') 方法提取了 href 屬性,並拼接出章節的 url,使用 chapter.string 方法提取了章節名。

每個章節的鏈接、章節名、章節內容都有了。接下來就是整合代碼,將內容保存到txt中即可。編寫代碼如下:

import requests
import time
from tqdm import tqdm
from bs4 import BeautifulSoup

def get_content(target):
    req = requests.get(url = target)
    req.encoding = 'utf-8'
    html = req.text
    bf = BeautifulSoup(html, 'lxml')
    texts = bf.find('div', id='content')
    content = texts.text.strip().split('\xa0'*4)
    return content

if __name__ == '__main__':
    server = 'https://www.xsbiquge.com'
    book_name = '詭祕之主.txt'
    target = 'https://www.xsbiquge.com/15_15338/'
    req = requests.get(url = target)
    req.encoding = 'utf-8'
    html = req.text
    chapter_bs = BeautifulSoup(html, 'lxml')
    chapters = chapter_bs.find('div', id='list')
    chapters = chapters.find_all('a')
    for chapter in tqdm(chapters):
        chapter_name = chapter.string
        url = server + chapter.get('href')
        content = get_content(url)
        with open(book_name, 'a', encoding='utf-8') as f:
            f.write(chapter_name)
            f.write('\n')
            f.write('\n'.join(content))
            f.write('\n')

下載過程中,我們使用了 tqdm 顯示下載進度,讓下載更加“優雅”,如果沒有安裝 tqdm,可以使用 pip 進行安裝,運行效果:

可以看到,小說內容保存到“詭祕之主.txt”中,小說一共 1416 章,下載需要大約 20 分鐘,每秒鐘大約下載 1 個章節。

下載完成,實際花費了 27 分鐘。

20 多分鐘下載一本小說,你可能感覺太慢了。想提速,可以使用多進程,大幅提高下載速度。如果使用分佈式,甚至可以1秒鐘內下載完畢。

但是,我不建議這樣做

我們要做一個友好的爬蟲,如果我們去提速,那麼我們訪問的服務器也會面臨更大的壓力。

以我們這次下載小說的代碼爲例,每秒鐘下載 1 個章節,服務器承受的壓力大約 1qps,意思就是,一秒鐘請求一次。

如果我們 1 秒同時下載 1416 個章節,那麼服務器將承受大約 1416 qps 的壓力,這還是僅僅你發出的併發請求數,再算上其他的用戶的請求,併發量可能更多。

如果服務器資源不足,這個併發量足以一瞬間將服務器“打死”,特別是一些小網站,都很脆弱。

過大併發量的爬蟲程序,相當於發起了一次 CC 攻擊,並不是所有網站都能承受百萬級別併發量的。

所以,寫爬蟲,一定要謹慎,勿給服務器增加過多的壓力,滿足我們的獲取數據的需求,這就夠了。

你好,我也好,大家好纔是真的好。

五、總結

  • 本文講解了網絡爬蟲的三個步驟:發起請求、解析數據、保存數據。
  • 注意併發量,勿給服務器帶來過多的壓力。

參考鏈接(我參考我自己):

  • https://blog.csdn.net/c406495762/article/details/78123502
  • https://blog.csdn.net/c406495762/article/details/71158264

創作不易,點贊支持一下吧~您的點贊,是對我最大的支持!

點贊再看,養成習慣,微信公衆號搜索【JackCui-AI】關注一個在互聯網摸爬滾打的潛行者。

掃碼關注微信公衆號
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章