Python爬取小说电子书全文并保存到本地

1 解析章节列表

1 设定章节列表所在页面url
2 检查列表所在的元素id或类名
3 取得所有列表a链接并写入列表中

带有分页的章节列表 - 有规律可循时
根据章节链接的规律来自定义列表,就不再解析列表页的请求了

from lxml import etree
import requests

# 网页访问
header = {
    'User-agent':
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36 Edg/100.0.1185.29'
}
mSession = requests.session()

aList = [] # 定义章节列表变量

def getList(url): # 根据章节列表url获取所有章节a链接
    global aList  # 声明全局使用变量
    
    try:
        mResponse = mSession.get(url, headers=header)
        if (mResponse.ok):
            # 格式化页面源码
            mHtml = etree.HTML(mResponse.content)
            # xpath 获取目标节点内容,返回结果为列表形式,通过索引进行访问
            mTables = mHtml.xpath('//*[@id="list"]')
            if (len(mTables) <= 0):
                print("找不到章节列表")
                return
            mTable = mTables[0]
            aList = mTable.xpath('.//a')  # 取得所有 a 链接
    except Exception as e:
        print("获取章节列表失败:\n" + e)
       

2 循环列表

解析 a 链接

result = ""
baseUrl = "https://xxx.com"
getList("https://xxx.com/5/5552/1/")
for a in aList:
    href = baseUrl + a.xpath('@href')[0]  # 取得 a 链接的 URL
    print(href) # 打印到控制台以便查看进行到第几章
    txt = a.xpath('text()')[0]  # 取得 a 链接的文本内容,一般为章节标题
    print(txt) # 打印到控制台以便查看进行到第几章
    # break # 通过首页来分析是否解析成功,解析成功后即可注释掉
    
    # Sub
    result += txt + "\n" # 将章节标题写入到结果中
    getDetail(href=href) # 根据章节链接获取章节内容
    # print(result) # 打印解析的单个章节内容分析是否成功
    # break # 如果解析成功,则注释掉使其跑循环

如果列表中是自定义好的a链接列表,则直接执行sub块内容即可

setList()
for a in aList:
    getDetail(href=a) # 根据章节链接获取章节内容

是否存在需要跳过的章节
根据需要进行添加启用

j = 1
for a in aList:
    if (j <= 15):
        j = j + 1
        continue

写内容

result = ""
i = 1

def writeContent(str):
    with open("temp.txt", 'a', encoding='utf-8') as f: # 以append的模式累加内容
        f.write(str)
        
for a in aList:
    
    # Sub
    result += txt + "\n" # 将章节标题写入到结果中
    getDetail(href=href) # 根据章节链接获取章节内容
    
    ''' 每 10 章写入一次文本 '''
    if (i == 10):
        writeContent(result)
        i = 1
        result = ""
        continue
    i = i + 1

''' 写入剩余文本 '''
if (result != ""):
    writeContent(result)

3 获取单个章节内容

1 解析文章链接

def getDetail(href): # 参数传入待解析的文章链接
    # Sub
    try:
        mResponse = mSession.get(href, headers=header)
        if(mResponse.ok):
            mHtml = etree.HTML(mResponse.content)
            mContents = mHtml.xpath('//div[@id="chaptercontent"]') # 分析内容块,获取合适的path路径
            if (len(mContents) <= 0): 
                print("找不到章节内容")
                return # 如果解析不成功,则代表找不到内容块,可能链接有误,跳出
            mContent = mContents[0]
            getContent_div(content=mContent)
            checkNextPage(html=mHtml)
	except Exception as e:
    	print(e)

2 解析文章内容

def getContent_div(content):  # 内容直接存放在 div 中
    global result # 声明result是全局变量,以便在内部修改,外部调用
    
    txts = content.xpath("./text()")
    for txt in txts:
        result += txt + "\n"

def getContent_p(content):  # 正文内容存放于 p 标签中
    global result # 声明result是全局变量,以便在内部修改,外部调用
    
    pList = content.xpath('.//p')
    for p in pList:
        result += p.xpath('text()')[0]
        
def getContent_divAll(content):  # 获取整个 div 内容
    global result # 声明result是全局变量,以便在内部修改,外部调用
    
    txt = etree.tounicode(mTable)
    # # 替换掉 html 标签 import re
    # txt = re.sub('(<p.*?>)|(</p>)|(&#13;)|(<strong.*?>)|(</strong>)', "", txt)
    result += txt + "\n"

检查是否包含下一页

def checkNextPage(html):
    ''' 检查是否包含下一页 '''
    mNextPages = html.xpath('//div[@class="section-opt m-bottom-opt"]')
    if (len(mNextPages) <= 0):
        return  # 不包含下一页标签,直接跳出
    mNextPage = mNextPages[0]
    aAll = mNextPage.xpath('.//a')
    for a in aAll:
        txt = a.xpath('text()')[0]
        if (txt == "下一页"):
            nextPage = a.xpath('@href')[0]
            getDetail(href=nextPage)

完整模板代码

from lxml import etree
import requests

# 网页访问
header = {
    'User-agent':
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36 Edg/100.0.1185.29'
}
mSession = requests.session()
aList = []  # 定义章节列表变量
result = ""  # 定义解析到的章节内容


def getList(url):  # 根据章节列表url获取所有章节a链接
    global aList  # 声明全局使用变量

    try:
        mResponse = mSession.get(url, headers=header)
        if (mResponse.ok):
            # 格式化页面源码
            mHtml = etree.HTML(mResponse.content)
            # xpath 获取目标节点内容,返回结果为列表形式,通过索引进行访问
            mTables = mHtml.xpath('//*[@id="list"]')
            if (len(mTables) <= 0):
                print("找不到章节列表")
                return
            mTable = mTables[0]
            aList = mTable.xpath('.//a')  # 取得所有 a 链接
    except Exception as e:
        print("获取章节列表失败:\n" + e)


def writeContent(str):
    with open("temp.txt", 'a', encoding='utf-8') as f:  # 以append的模式累加内容
        f.write(str)


def getContent_div(content):  # 内容直接存放在 div 中
    global result  # 声明result是全局变量,以便在内部修改,外部调用

    txts = content.xpath("./text()")
    for txt in txts:
        result += txt + "\n"


def getContent_p(content):  # 正文内容存放于 p 标签中
    global result  # 声明result是全局变量,以便在内部修改,外部调用

    pList = content.xpath('.//p')
    for p in pList:
        result += p.xpath('text()')[0]


def getContent_divAll(content):  # 获取整个 div 内容
    global result  # 声明result是全局变量,以便在内部修改,外部调用

    txt = etree.tounicode(content)
    result += txt + "\n"


def getDetail(href):  # 参数传入待解析的文章链接
    # Sub
    try:
        mResponse = mSession.get(href, headers=header)
        if (mResponse.ok):
            mHtml = etree.HTML(mResponse.content)
            mContents = mHtml.xpath(
                '//div[@id="chaptercontent"]')  # 分析内容块,获取合适的path路径
            if (len(mContents) <= 0):
                print("找不到章节内容")
                return  # 如果解析不成功,则代表找不到内容块,可能链接有误,跳出
            mContent = mContents[0]
            getContent_div(content=mContent)
            checkNextPage(html=mHtml)
    except Exception as e:
        print(e)


def checkNextPage(html):
    ''' 检查是否包含下一页 '''
    mNextPages = html.xpath('//div[@class="section-opt m-bottom-opt"]')
    if (len(mNextPages) <= 0):
        return  # 不包含下一页标签,直接跳出
    mNextPage = mNextPages[0]
    aAll = mNextPage.xpath('.//a')
    for a in aAll:
        txt = a.xpath('text()')[0]
        if (txt == "下一页"):
            nextPage = a.xpath('@href')[0]
            getDetail(href=nextPage)


#################################################################################
# 自定义章节列表时使用
# setList()
# for a in aList:
#     getDetail(a)  # 根据章节链接获取章节内容
baseUrl = "https://xxx.com"
getList("https://xxx.com/5/5552/1/")
i = 1  # 分批写入文件
j = 1  # 跳过章节的起始页
for a in aList:
    # # 跳过前面章节
    # if (j <= 15):
    #     j = j + 1
    #     continue

    # 解析 a 链接
    href = baseUrl + a.xpath('@href')[0]  # 取得 a 链接的 URL
    print(href)  # 打印到控制台以便查看进行到第几章
    txt = a.xpath('text()')[0]  # 取得 a 链接的文本内容,一般为章节标题
    print(txt)  # 打印到控制台以便查看进行到第几章
    # break # 通过首页来分析是否解析成功,解析成功后即可注释掉

    # Sub
    result += txt + "\n"  # 将章节标题写入到结果中
    getDetail(href)  # 根据章节链接获取章节内容
    # print(result) # 打印解析的单个章节内容分析是否成功
    # break # 如果解析成功,则注释掉使其跑循环

    ''' 每 10 章写入一次文本 '''
    if (i == 10):
        writeContent(result)
        i = 1
        result = ""
        continue
    i = i + 1

''' 写入剩余文本 '''
if (result != ""):
    writeContent(result)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值