python爬虫爬取后下载小说实现思路及源码分享
这几天朋友说想看电子书,但是只能在网上看,不能下载到本地后看,问我有啥办法?我找了好几个小说网址看了下,你只能直接在网上看,要下载txt要冲钱买会员,而且还不能在浏览器上直接复制粘贴。之后我就想到python的爬虫不就可以爬取后下载吗?
思路:
首先,选择网址:http://www.yznnw.com/files/article/html/1/1129/index.html 这个是全本免费小说网上《龙血战神》的网址:
F12,分析网页元素,可以看到,在此页的 .zjlist4 li a 下存放了所有章节的URL,首先我们要获取这些url放在一个数组里。然后循环遍历下载
有了这些网址后开始分析具体的每一章:
书名:
章节名:
内容:
下一章:
有了这些信息我们就可以开始爬取了(其实这里可以不爬取下一章的,主要我之前的思路是:下载小说的第一章后,返回小说的下一章,之后不断递归直到最后一页,这么做后下载速度慢,不能并发,还有就是一直递归占用资源大,一直请求服务器会断开连接,导致失败)
所以我换成了这种思路:就是先获取所有的章节的网页连接,再用线程(你也可以用进程)开始下载,果然速度上升了好多,
但是,仔细分析后发现,其实有些章节是作者的感言啥的,这些是不用下载的,而真正的章节的标题一定含有:****章*****,所以要用正则排除掉(这个要具体分析,不一定每个作者的感言标题都是这样的,不过直接使用此程序也可以,这样也没啥)
代码如下:
#coding:utf-8 import urllib import urllib.request import multiprocessing from bs4 import BeautifulSoup import re import os import time def get_pages(url): soup="" try: # 创建请求日志文件夹 if 'Log' not in os.listdir('.'): os.mkdir(r".\Log") # 请求当前章节页面 params为请求参数 request = urllib.request.Request(url) response = urllib.request.urlopen(request) content = response.read() data = content.decode('gbk') # soup转换 soup = BeautifulSoup(data, "html.parser") except Exception as e: print(url+" 请求错误\n") with open(r".\Log\req_error.txt",'a',encoding='utf-8') as f: f.write(url+" 请求错误\n") f.close() return soup # 通过章节的url下载内容,并返回下一页的url def get_ChartTxt(url,title): soup=get_pages(url) # 获取章节名称 subtitle = soup.select('#htmltimu')[0].text # 获取章节文本 content = soup.select('#htmlContent')[0].text # 按照指定格式替换章节内容,运用正则表达式 content = re.sub(r'\(.*?\)', '', content) content = re.sub(r'\r\n', '', content) content = re.sub(r'\n+', '\n', content) content = re.sub(r'<.*?>+', '', content) # # 下一页 # pageDown = soup.select('#htmlxiazhang')[0].attrs['href'] # pageDown = base + pageDown # 写入这一章 try: # 判断是否有感言 if re.search(r'.*?章',subtitle) is not None: with open(r'.\%s\%s.txt' % (title, subtitle), 'w', encoding='utf-8') as f: f.write(subtitle + content) f.close() print(subtitle, '下载成功') except Exception as e: print(subtitle, '下载失败',url) with open(".\%s\error_url.txt",'a',encoding='utf-8') as f: f.write(subtitle+"下载失败 "+url+'\n') # return pageDown return # 通过首页获得该小说的所有章节链接后下载这本书 def thread_getOneBook(indexUrl): soup = get_pages(indexUrl) # 获取书名 title = soup.select('#htmldhshuming')[0].text # 根据书名创建文件夹 if title not in os.listdir('.'): os.mkdir(r".\%s" % (title)) print(title, "文件夹创建成功———————————————————") # 加载此进程开始的时间 print('下载 %s 的PID:%s...' % (title, os.getpid())) start = time.time() # 获取这本书的所有章节 charts_url = [] # 提取出书的每章节不变的url indexUrl = re.sub(r'index.html', '', indexUrl) charts = soup.select(".zjlist4 li a") for i in charts: # print(j+i.attrs['href']) charts_url.append(indexUrl + i.attrs['href']) # 创建下载这本书的进程 p = multiprocessing.Pool() for i in charts_url: p.apply_async(get_ChartTxt, args=(i,title)) print('等待 %s 所有的章节被加载......' % (title)) p.close() p.join() end = time.time() print('下载 %s 完成,运行时间 %0.2f s.' % (title, (end - start))) return # 创建下载多本书书的进程 def process_getAllBook(base): # 输入你要下载的书的首页地址 print('主程序的PID:%s' % os.getpid()) book_indexUrl=[ 'http://www.yznnw.com/files/article/html/1/1129/index.html', 'http://www.yznnw.com/files/article/html/17/17455/index.html' ] print("开始下载..............") p=[] for i in book_indexUrl: p.append(multiprocessing.Process(target=thread_getOneBook,args=(i,))) print("等待所有的主进程加载完成........") for i in p: i.start() for i in p: i.join() print("全部下载完成") return if __name__=="__main__": # # 主页 base = 'http://www.yznnw.com' # 下载指定的书 process_getAllBook(base)
如果要下载其他书的话,找到书的首页,添加到如下位置:
找书的首页URL,随便点开一章,删除后面的***.html,后回车,就是这本书的首页URL。
运行结果:
请求URL失败的网页放在,Log\req_error.txt中
爬取失败的章节存放在这本书的目录下的error_url.txt中
之后,你使用电子书生成器,生成就好
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法