本帖最后由 事燃cs释然 于 2020-9-13 17:08 编辑
应论坛中一些朋友的要求,已将代码打包成了exe程序,发布在另一个帖子中,不懂得python的同学可以直接绕路,附上另一个帖子链接:https://www.52pojie.cn/forum.php?mod=viewthread&tid=1265020&page=1&extra=#pid34083564
初学者,写了个可以把网上的小说保存的爬虫,暂时就只能在笔趣阁用
附上代码,希望大佬前来指正:
[Python] 纯文本查看 复制代码 import requests
import re
import json
import os.path
header = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36'
}
#定义全局变量,用于保存所有获取到的小说内容
story_all = []
#获取标题及章节链接地址
def main():
url = input("请输入小说目录页地址(暂时仅支持‘http://www.xbiquge.la/’站内小说):")
print("-----爬取开始-----")
#获取目录页的HTML文本
text = requests.get(url,header).content.decode('utf-8')
#获取书名
book_name = re.findall(r'<div id="info".*?h1>(.*?)<',text,re.DOTALL)[0]
#获取每个章节的章节名
title = re.findall(r'<dd>.*?<a.*?>(.*?)</a>',text,re.DOTALL)
#获取每个章节的链接地址
loca = re.findall(r"<dd>.*?='(.*?)' >",text,re.DOTALL)
all_info = have_stort(book_name, title, loca)
if all_info:
title = all_info['title']
loca = all_info['loca']
#因为title和loca的长度相同,所以以索引的方式遍历,方便取值
for i in range(len(title)):
#这里还是改一下吧,f""的形式,py3.6.2之后的版本才支持
#所以就把它改成%s的占位符形式
content(title[i],'http://www.xbiquge.la%s'%loca[i])
#保存为json防止程序突然中断也方便为以后更新
with open('%s.json'%book_name,'w',encoding='utf-8')as fp:
json.dump(story_all,fp,ensure_ascii=False)
#小说爬取完毕,开始保存
print("@"*500)
with open(r'%s.txt'%book_name, 'w',encoding='utf-8')as file:
#遍历每一项,按顺序保存章节名和章节内容
for story in story_all:
file.write(story['title']+'\n')
print(story['title'])
file.write(story['story'])
#解析章节内容并保存
def content(title,url):
#获取章节页的HTML文本
text = requests.get(url,header).content.decode('UTF-8')
#因为之前写过直接爬取所有内容的,爬取出来的文本都带有\r不好处理
#所以就一句一句的获取了
story_content = re.findall(r' (.*?)<br',text,re.DOTALL)
#因为有一个网友提出了一个bug:就是如果某个章节的内容只有一两句话,那么网站是不会进行首行缩进的,所以这里进行一次判断
have_nav = re.findall(r'<div id="content">(.*?)<b',text,re.DOTALL)
if not have_nav == []:
have_nav = re.sub(r'\ufeff','',have_nav[0])
have_nav = re.match(r"[ ]",have_nav[0])
if not (have_nav):
story_content = ["本章节内容无意义,可以跳过"]
#因为章节名中有“”空格,没办法作为文件名,所以把空格去掉
title = re.sub(' ','-',title)
#有时候不知道为什么小说内容会爬取到一个空数组,所以这里添加了一个检测程序
#如果爬取到的为空,就重新爬取,直到获取到为止
if story_content==[]:
content(title,url)
return 0
story=""
#前面提到,因为我是一句一句爬取的,所以这里做一下拼接,顺便去空格
for story_contents in story_content:
story = story+story_contents.strip()+'\n'
#将章节名称和章节内容保存为一个字典
this_story = {
"title":title,
"story":story
}
print(this_story['title'])
#将字典添加到开头定义的全局变量中
story_all.append(this_story)
#判断该小说是否已经保存,如果已经保存则遍历章节过滤已保存章节
def have_stort(book_name,title,loca):
global story_all
#判断此小说是否保存过
if os.path.isfile('%s.json'%book_name):
#打开之前保存的json用以对照
with open('%s.json'%book_name,'r',encoding='utf-8')as fp:
storys_all=json.load(fp)
have_index = 0
#遍历,判断最后的一章
if not storys_all == []:
for index,story in enumerate(storys_all):
for title_this in title:
title_this = re.sub(' ', '-', title_this)
if title_this == story['title']:
have_index = index+1
#将已保存的章节的标题删除
del title[:have_index]
del loca[:have_index]
story_all = storys_all
print("本书已保存至'%s',将从此章之后开始保存"%story_all[have_index-1]['title'])
all_info = {
'title':title,
'loca':loca
}
#返回处理后的title和loca列表
return all_info
if __name__ == "__main__":
main()
最后说一下使用步骤:
1、前往http://www.xbiquge.la/,找到要保存的小说,复制那个小说的目录页链接
2、按要求输入链接地址和小说名
3、爬取开始
(因为是单线程运行,爬取速度略慢大概1-2秒一章)
4、爬取结束后,会将所有章节内容整合成一个txt文件
最后求一波热心值
2020/9/11 15:10 第一次更新:当某章节只有一两行文本时,正则表达式无法匹配
2020/9/12 16:32 第二次更新:如果保存的是已经保存一次的小说,会从上一次保存的基础上保存,防止浪费时间
2020/9/13 17:02 第三次更新:每保存一章就会及时保存json,这样如果程序在运行期间被关闭或中断,下次爬取同一个小说是会自动识别已保存记录继续保存 |