用Python爬取小说

废话部分:

前些日子在网易云音乐,偶然的机会入坑了有声书《北派盗墓笔记》,后来一边看原文,一边听小说,收费之后就只看了。
本来在手机上看,后来想在kindle上看。但是由于小说还没有更新完,就只能隔一段时间,下载一部分,复制到kindle上,然后继续重复这个操作。
网上没有现成的txt可以下载,那么就只能复制粘贴,然后做成awz文件。鉴于重复的机械性工作很无聊,就写了Python做爬虫将小说爬取下来。

正文部分:

爬取分为两种思路:
1.找到小说目录页面,然后通过目录里提供的章节链接一个一个的保存内容
2.找到一篇内容,通过下一页的按钮的链接,一个个的保存下一篇的内容
在网上随手一搜就有很多现成的项目,于是我就复制了一个代码,然后进行修改
参考的文章:https://www.jianshu.com/p/2fd0739c2df2
这个采用的是第二个思路,然后这个网址有一个问题,它会把一个章节,分割成两个章节,进而变成两个网页很不方便,于是就换了一个网站作为书籍的来源

话不多说,上代码吧

# -*- coding: utf-8 -*-
"""
Created on Mon Sep 19 10:14:00 2022

@author: Martin
"""
import re
import requests
import parsel  # 网页提取文字xpath、re、css
from unicodedata import normalize  # normalize方法将Unicode字符转换为正常字符
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 Edg/83.0.478.45'}

def paper_download(url):
    """
    适用网站:https://www.exiaoshuo.com
    """
    response = requests.get(url=url, headers=headers)
    selector = parsel.Selector(response.text.encode('gbk').decode('gbk', 'ignore'))
    title = selector.css('h1::text').extract_first()  # 章节名
    title = title.strip()  # 去除头尾空字符
    content = selector.css('#content').getall()[0]  # 正文内容
    content = content.replace('<br>','')  #去除换行符
    content = re.findall(r">(.*)<",content,re.S)
    content = [re.sub(r'\xa0?', "", content[0]).replace('\r\r','\r')]
    aaa = selector.css('.page_chapter li')
    next_url = [item.css('::attr(href)').get() for item in aaa if item.css('::text').get() == '下一章'][0]   # 下页链接
    next_url = next_url.strip()
    text = ''
    for i in content:
        text += i.strip() + '\n'
    text = normalize('NFKC', text)  # 将Unicode字符转换为正常字符
    return title, text, next_url

def paper_save(filepath, start_url, end_url):
    """
    适用网站:https://www.exiaoshuo.com
    :param str filepath: 小说文件保存完整路径
    :param str start_url: 小说开始下载页链接
    :param str end_url: 小说正文的结束页/最后一页链接
    """
    base_url = r'https://www.exiaoshuo.com'
    now_url = start_url
    while True:
        url = base_url + now_url
        pd = paper_download(url)
        with open(filepath, 'a', encoding='gbk') as f:  # 同上面编码是gbk
            f.write(pd[0])  # 章节名
            f.write('\n')  #换行
            f.write('\n')  #换行
            f.write(pd[1])  # 正文内容首行自带空行
            f.write('\n')  #换行
            #break  # 单次测试
        if now_url != end_url:
            now_url = pd[2]
        else:
            print('下载失败:{}< 或 >最后一章下载完成'.format(now_url))
            break

if __name__ == '__main__':
    filename = r'E:\北派.txt'
    start_url = r'/beipaidaomubiji/36610541/'  #https://www.exiaoshuo.com/beipaidaomubiji/36610541/
    end_url = r'/beipaidaomubiji/366105441/'
    paper_save(filename, start_url, end_url)

主要的改动就是解析网页内小说内容的部分了,这里面用到了“parsel ”的库,我又加进去了正则来解析。

这个代码 的思路就是,设置一个开始的章节的链接,设置一个结束章节的链接,然后程序不停的点击下一页,直到遇见结束的链接。

心得:

代码部分没什么好说的,在这次修改代码的过程中,parsel 这个库真的是太好用了,可以通过网页的div的id来定位,也可以通过网页的内容来定位
网上找了这个代码作参考,最后修改好了我的解析小说的程序

from parsel import Selector

html = '''
<html>
 <head>
  <base href='http://example.com/' />
  <title>Example website</title>
 </head>
 <body>
  <div id='images'>
   <a href='image1.html'>Name: My image 1 <br /><img src='image1_thumb.jpg' /></a>
   <a href='image2.html'>Name: My image 2 <br /><img src='image2_thumb.jpg' /></a>
   <a href='image3.html'>Name: My image 3 <br /><img src='image3_thumb.jpg' /></a>
   <a href='image4.html'>Name: My image 4 <br /><img src='image4_thumb.jpg' /></a>
   <a href='image5.html'>Name: My image 5 <br /><img src='image5_thumb.jpg' /></a>
  </div>
 </body>
</html>
'''

selector = Selector(html)  # 初始化Selector()对象

'''使用xpath方法获取id为images下的所有a标签'''
items = selector.xpath('//div[@id="images"]/a')
texts = items.getall()  # 实际上这个就是默认给了一个循环罢了,和下面一样【可通过查看源码看出】
print(texts)
result_text = [item.xpath('./text()').get() for item in items]  # 获取节点文字内容
result_href = [item.xpath('./@href').get() for item in items]  # 获取节点属性
print(type(items))
print(items)
print(result_text)
print(result_href)

# 运行结果
# ['<a href="image1.html">Name: My image 1 <br><img src="image1_thumb.jpg"></a>', '<a href="image2.html">Name: My image 2 <br><img src="image2_thumb.jpg"></a>', '<a href="image3.html">Name: My image 3 <br><img src="image3_thumb.jpg"></a>', '<a href="image4.html">Name: My image 4 <br><img src="image4_thumb.jpg"></a>', '<a href="image5.html">Name: My image 5 <br><img src="image5_thumb.jpg"></a>']
# <class 'parsel.selector.SelectorList'>
# [<Selector xpath='//div[@id="images"]/a' data='<a href="image1.html">Name: My image ...'>, <Selector xpath='//div[@id="images"]/a' data='<a href="image2.html">Name: My image ...'>, <Selector xpath='//div[@id="images"]/a' data='<a href="image3.html">Name: My image ...'>, <Selector xpath='//div[@id="images"]/a' data='<a href="image4.html">Name: My image ...'>, <Selector xpath='//div[@id="images"]/a' data='<a href="image5.html">Name: My image ...'>]
# ['Name: My image 1 ', 'Name: My image 2 ', 'Name: My image 3 ', 'Name: My image 4 ', 'Name: My image 5 ']
# ['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']

'''使用css方法获取id为images下的所有a标签'''
print('\n')
items = selector.css('#images > a')
result_text = [item.css('::text').get() for item in items]  # 获取节点文字内容
result_href = [item.css('::attr(href)').get() for item in items]  # 获取节点属性
print(type(items))
print(items)
print(result_text)
print(result_href)
# 运行结果
# <class 'parsel.selector.SelectorList'>
# [<Selector xpath="descendant-or-self::*[@id = 'images']/a" data='<a href="image1.html">Name: My image ...'>, <Selector xpath="descendant-or-self::*[@id = 'images']/a" data='<a href="image2.html">Name: My image ...'>, <Selector xpath="descendant-or-self::*[@id = 'images']/a" data='<a href="image3.html">Name: My image ...'>, <Selector xpath="descendant-or-self::*[@id = 'images']/a" data='<a href="image4.html">Name: My image ...'>, <Selector xpath="descendant-or-self::*[@id = 'images']/a" data='<a href="image5.html">Name: My image ...'>]
# ['Name: My image 1 ', 'Name: My image 2 ', 'Name: My image 3 ', 'Name: My image 4 ', 'Name: My image 5 ']
# ['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']

结束:

最后的最后,附上一个链接:aliyundrive.com/s/z3P1Q9ynYcj

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
青葱年少的头像青葱年少普通用户
上一篇 2023年6月25日
下一篇 2023年6月25日

相关推荐