首页 » 技术分享 » 爬虫 (7)—— 爬取网络小说,详细分析及代码

爬虫 (7)—— 爬取网络小说,详细分析及代码

 

声明

1、 刚刚开始学习爬虫,写这个纯属兴趣,代码会有很多不严谨
2、 如果要转载,请标记出来源
爬取网站:顶点小说
获取书库资源
1、先查找搜索时的规律:
搜索大道朝天时网站为:https://www.118book.com/book/39/,代号39
搜索永恒圣王时网站为:https://www.118book.com/book/10393/,代号10393
可以得出每一个数字都代表一本书,因此可以使用循环获取某个范围内的所有书名
2、查看网页源代码,查找书名位置,从以下图片可以看出,书名位于id为info的div标签中的h1标签中
在这里插入图片描述
3、建立一个字典bookNames,来存放书名以及对应的编号
代码如下:

import requests
from bs4 import BeautifulSoup
import bs4

bookNames = {}

def getBookName(bookNames, number):
    for i in range(number):
        url = 'https://www.118book.com/book/'+str(i)
        try:
            r = requests.get(url, timeout=30)
            r.raise_for_status
            r.encoding = r.apparent_encoding
            demo = r.text
            soup=BeautifulSoup(demo,'html.parser')
            for tag in soup.find(id='info').children:
                    if(tag.name=='h1'):
                           bookNames[i]=tag.string           
        except:
            print("爬取失败")

getBookName(bookNames, 3)
print(bookNames)

输出结果:

{0: '我们是洪荒玩家', 1: '超级募兵仓库', 2: '僵君令'}

搜索指定书名
搜索书名是在bookNames字典中查找,如果存在返回书籍的编号,否则返回-1

def searchBook(bookNames):
    name = input("输入要搜索的书名:")
    id = -1
    for key, value in bookNames.items():
        if name == str(value):
            id = key
    return id


getBookName(bookNames, 3)
print(bookNames)
id = searchBook(bookNames)
print(id)

注: 循环中valuse的类型是 'bs4.element.NavigableString,而name的类型是String,比较是否相等时要进行类型转换,否则一直返回-1

结果:

{0: '我们是洪荒玩家', 1: '超级募兵仓库', 2: '僵君令'}
输入要搜索的书名:僵君令
2

获取书籍的章节目录
1、该方法要获取书籍的章节目录以及每一章节对应的网址,并将其保存,为之后的书籍下载做准备这一部分应该是最重要的地方
2、分析网页源码
在这里插入图片描述
从网页源码中可以看出,每一个class为_chapter中包含3个小章节,所有要获取所有的class为_chapter的ul,然后再遍历其中的子节点
注: 这里有关问题class是python的关键字,不能在这里使用只能先获取id为list的div,然后在获取ul
代码

def getChapter(chapters, bookNames):
    id = searchBook(bookNames)
    url = 'https://www.118book.com/book/'+str(id)
    try:
        r = requests.get(url, timeout=30)
        r.raise_for_status
        r.encoding = r.apparent_encoding
        demo = r.text
        soup = BeautifulSoup(demo, 'html.parser')
        string=''
        print(type(demo))
        for uls in soup.find(id='list').children:  # 获取所有的ul
           string+=str(uls)     # 注意类型
        soup=BeautifulSoup(string,'html.parser')
        for a in soup.find_all('a'):    # 获取所有a标签
               chapters[a.attrs['href']]=a.string    # 注意href是a标签的一个属性,不能直接a.href

    except:
        print("章节获取失败")

bookNames = {}    # 存储获取的所有书名
chapters = {}      # 存储指定小说的章节

getBookName(bookNames, 3)
getChapter(chapters, bookNames)
print(chapters)

结果:
在这里插入图片描述
下载小说
1、最后一个阶段将小说保存的本地,想法是小说名作为文件名,每一章节都是一个单独的以章节名为命名的txt文件
2、随便打开一个章节,可以得到网址,例如:https://www.118book.com/book/2/6.html,可以得出规律只需要在https://www.118book.com/book/2/拼接上对应的编号即可打开每一章节
3、查看源代码,获取小说内容所在的标签
在这里插入图片描述
从源代码中可以看出只需要获得id为content的div标签即可

def saveNovel(bookNames, chapters, flog):
    i = -1
    id = searchBook(bookNames)
    getChapter(chapters, bookNames, id)
    url = 'https://www.118book.com/book/'+id+'/'
    for key, value in chapters.items():
        i += 1
        if(flog == True and i == 3):
            break
        try:
            href = url+key
            r = requests.get(href, timeout=30)
            r.raise_for_status
            r.encoding = r.apparent_encoding
            demo = r.text
            soup = BeautifulSoup(demo, 'html.parser')
            div = soup.find_all(id='content')
            text = (str(div)).replace('<br/>', '\n')  # 替换换行符的形式
            path = 'D:/'+bookNames[int(id)]       # 存放小说的文件夹
            if not os.path.exists(path):   # 检测文件夹是否存在
                os.mkdir(path)
            file = open(path+'/'+value+'.txt', 'a', encoding="utf-8")
            file.write(text)
            file.close()

        except Exception as re:
            print(re)
    print("下载完成")

注: 如果只是单纯下载某一个页面的小说可以使用以下代码

import requests
from bs4 import BeautifulSoup
import bs4
import os

url = 'https://www.118book.com/book/2/6.html'  # 这是每一章节对应的网址
try:
    r = requests.get(url, timeout=30)
    r.raise_for_status
    r.encoding = r.apparent_encoding
    demo = r.text
    soup = BeautifulSoup(demo, 'html.parser')
    div = soup.find_all(id='content')
    div = (str(div)).replace('<br/>', '\n')
    path = 'D:/'+'1'
    file=open(path+'/a.txt','a',encoding="utf-8")
    file.write(div)
    file.close() 
    print('wc')
except Exception as re:
    print(re)

完整代码
偷个懒,代码还可以简单整理以下,就不整理了
1、可以加一个main函数
2、以下代码有些重复,可以单独定义成一个init函数

r = requests.get(url, timeout=30)
r.raise_for_status
r.encoding = r.apparent_encoding
demo = r.text
soup = BeautifulSoup(demo, 'html.parser')

3、完整代码:

import requests
from bs4 import BeautifulSoup
import bs4
import os

# 获取书库
def getBookName(bookNames, number):
    for i in range(number):
        url = 'https://www.118book.com/book/'+str(i)
        try:
            r = requests.get(url, timeout=30)
            r.raise_for_status
            r.encoding = r.apparent_encoding
            demo = r.text
            soup = BeautifulSoup(demo, 'html.parser')
            for tag in soup.find(id='info').children:
                if(tag.name == 'h1'):
                    bookNames[i] = tag.string

        except:
            print("爬取失败")


# 搜索指定书籍
def searchBook(bookNames):
    name = input("输入要搜索的书名:")
    id = -1
    for key, value in bookNames.items():
        if name == str(value):
            id = key
    return str(id)


# 获取所有的章节
def getChapter(chapters, bookNames, id):
    url = 'https://www.118book.com/book/'+id
    try:
        r = requests.get(url, timeout=30)
        r.raise_for_status
        r.encoding = r.apparent_encoding
        demo = r.text
        soup = BeautifulSoup(demo, 'html.parser')
        string = ''
        for uls in soup.find(id='list').children:  # 获取所有的ul
            string += str(uls)     # 注意类型
        soup = BeautifulSoup(string, 'html.parser')
        for a in soup.find_all('a'):    # 获取所有a标签
            # 注意href是a标签的一个属性,不能直接a.href
            chapters[a.attrs['href']] = a.string

    except:
        print("章节获取失败")


# 下载小说
def saveNovel(bookNames, chapters, flog):
    i = -1
    id = searchBook(bookNames)
    getChapter(chapters, bookNames, id)
    url = 'https://www.118book.com/book/'+id+'/'
    for key, value in chapters.items():
        i += 1
        if(flog == True and i == 3):
            break
        try:
            href = url+key
            r = requests.get(href, timeout=30)
            r.raise_for_status
            r.encoding = r.apparent_encoding
            demo = r.text
            soup = BeautifulSoup(demo, 'html.parser')
            div = soup.find_all(id='content')
            text = (str(div)).replace('<br/>', '\n')  # 替换换行符的形式
            path = 'D:/'+bookNames[int(id)]       # 存放小说的文件夹
            if not os.path.exists(path):   # 检测文件夹是否存在
                os.mkdir(path)
            file = open(path+'/'+value+'.txt', 'a', encoding="utf-8")
            file.write(text)
            file.close()

        except Exception as re:
            print(re)
    print("下载完成")


bookNames = {}    # 存储获取的所有书名
chapters = {}      # 存储指定小说的章节

getBookName(bookNames, 3)
print(bookNames)
saveNovel(bookNames, chapters, True)

注: 因为运行速度有些慢,当soveNovel的参数为true时,只下载3章,如果要全部下载设置为false即可
运行结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结

1、 感觉写这个程序非常累,写了很久
2、 写程序过程中发现自己不扎实,要翻书、看笔记
3、 要注意类型,代码因为类型问题,出现了很多错误

转载自原文链接, 如需删除请联系管理员。

原文链接:爬虫 (7)—— 爬取网络小说,详细分析及代码,转载请注明来源!

0