天天看點

python bs4+多線程爬取一整部小說(小白第一篇部落格)

今天與大家分享一下,學了bs4和多線程之後的第一次實踐。今天爬取的目标是縱橫中文網的小說《元尊》。

目标連結

bs4,正規表達式,xpath是初學者易學易上手的三大神器,其中re的速度最快,xpath其次,bs4最後,bs4和xpath需要對html标簽有一定的了解,這個可以去菜鳥教程了解一下,上手很快。多線程,說話我學了一個星期,還是沒學太明白,自學的就是這樣,沒有人授業解惑,一個小問題自己百度可能一兩個小時也沒解決。bs4大家可以去官方文檔學習,今天用到的都是非常簡單的,看下代碼中的注釋應該可以了解,我就不上bs4的教程了,好了步入今天的正題。

網頁分析

python bs4+多線程爬取一整部小說(小白第一篇部落格)

說是爬取一整部其實是大概前90多章,因為後面的都是花錢的,這是正版網站。爬取盜版網站可以,for循環改下數字就ok了。

python bs4+多線程爬取一整部小說(小白第一篇部落格)
python bs4+多線程爬取一整部小說(小白第一篇部落格)

谷歌浏覽器F12->All->左邊選擇第一個->response往下拉可以看到小說正文在一個class="content"的div标簽的子标簽p标簽裡。第二張圖我們可以看到标題在一個class="title_txtbox"的div标簽裡。

上代碼,先爬取一章

import requests
url = 'http://book.zongheng.com/chapter/685640/38883752.html'
#UA在上圖的Headers裡面下拉可以找到複制粘貼即可
headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36'
        }
response = requests.get(url,headers = headers)
#第一個參數是response傳回的text,第二個是使用html解析
soup = BeautifulSoup(response.text,'html.parser')
#findAll方法是找到所有符合要求的内容,傳回的是一個清單
div = soup.findAll("div",class_ = "content")
#找到每一章的title
title = soup.findAll("div",class_ = "title_txtbox")
#strip方法可以去掉首尾特定的字元,是以就确定了标題
souptitle = BeautifulSoup(str(title),'html.parser').text.strip("[]")
#最終要寫入檔案的小說内容
#因為findAll傳回的是清單,bs4隻能解析str是以強轉一下
#得到是一行結束的小說内容,五哦一我們用replace以一個句号為一段落
souptext = BeautifulSoup(str(div),'html.parser').text.strip("[]").replace("。","。\n")
#把我們爬取到的内容寫入檔案就大功告成啦!
f = open("C:/f.txt","a")
f.write(str(souptitle)+'\r')
f.write(str(souptext)+'\r')
f.close()

           

我們寫入到text的小說可以添加到小說軟體中,可以識别并有序排版

python bs4+多線程爬取一整部小說(小白第一篇部落格)

爬取全部!

分析:

python bs4+多線程爬取一整部小說(小白第一篇部落格)
python bs4+多線程爬取一整部小說(小白第一篇部落格)

比較第一張圖檔和第二張圖檔的url可以看出,不同章節的url隻是最後的那一串數字不同,通常這種情況下,這些東西都在網頁的html代碼中。

python bs4+多線程爬取一整部小說(小白第一篇部落格)

在第一章的網頁源代碼中我們可以看到nextchaterid=“38885173”正是我們要找的第二章的url中的末尾的那一串數字,這樣我們可以通過bs4爬取到這一串數字,然後就可以拼接第二章的url,以此類推所有的章節的url都可以得到,整本小說也就爬取到了

def main():
	#第一章小說的末尾數字串
    a = ['38883752']
    for i in range(90):
        url = "http://book.zongheng.com/chapter/685640/{}.html".format(a[i])
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36'
        }
        response = requests.get(url, headers=headers)
        soup = BeautifulSoup(response.text, 'html.parser')
        # 小說内容在div标簽裡
        nextpage = soup.body['nextchapterid']
        #爬取90章小說的末尾數字串,放到清單中
        a.append(nextpage)
    return a
           

90章小說+多線程,有很多需要優化的地方,望留言更改

import threading
import requests
from bs4 import BeautifulSoup
import time
import sys
#多線程
class myThreading(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):

        getUrl(main())

def getUrl(page):
    i=1
    for nextpage in page:
        url = "http://book.zongheng.com/chapter/685640/{}.html".format(nextpage)
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36'
        }
        response = requests.get(url,headers = headers)

        soup = BeautifulSoup(response.text,'html.parser')
        div = soup.findAll("div",class_ = "content")
        title = soup.findAll("div",class_ = "title_txtbox")
        #最終的标題
        souptitle = BeautifulSoup(str(title),'html.parser').text.strip("[]")
        #最終要寫入檔案的小說内容
        souptext = BeautifulSoup(str(div),'html.parser').text.strip("[]").replace("。","。\n")

        f = open("C:/f.txt","a")
        f.write(str(souptitle)+'\r')
        f.write(str(souptext)+'\r')
        f.close()
        #列印進度條
        sys.stdout.write("\r已經完成:{}%".format(i/len(page)*100))
        sys.stdout.flush()
        time.sleep(0.1)
        i = i+1

def main():
    a = ['38883752']
    for i in range(90):
        url = "http://book.zongheng.com/chapter/685640/{}.html".format(a[i])
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36'
        }
        response = requests.get(url, headers=headers)
        soup = BeautifulSoup(response.text, 'html.parser')
        # 小說内容在div标簽裡
        nextpage = soup.body['nextchapterid']
        a.append(nextpage)
    return a

if __name__ == '__main__':
    strattime = time.time()
    thread1 = myThreading()
    thread1.start()
    thread1.join()
    print("")
    print("爬取完成")
    endtime = time.time()
    print("耗時:{}s".format(endtime - strattime))