前些日子在网易云音乐,偶然的机会入坑了有声书《北派盗墓笔记》,后来一边看原文,一边听小说,收费之后就只看了。
本来在手机上看,后来想在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('
','') #去除换行符
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 = '''
Example website
'''
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)
# 运行结果
# ['Name: My image 1
', 'Name: My image 2
', 'Name: My image 3
', 'Name: My image 4
', 'Name: My image 5
']
#
# [, , , , ]
# ['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)
# 运行结果
#
# [, , , , ]
# ['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