Python3爬虫之爬取网络小说

一、准备工作

涉及到的库及对应的作用:

  • requests:用于获取get请求
  • Beautiful Soup4:用于网页解析
  • re:正则表达式
  • os:系统相关操作
  • time:获取的时间
  • 1.安装BS4:在命令窗口的D:\Python\Scripts目录下(此处的路径为你Pyhon的安装目录里面的Scripts文件夹),输入pip install beautifulsoup4回车,得到如图1说明安装成功
    Python3爬虫之爬取网络小说_第1张图片
    2.安装requests:同样的在cmd窗口中输入pip install requests,然而这里我之前已经安装好了,提示如图2:
    Python3爬虫之爬取网络小说_第2张图片
    导入库:
import  requests
from bs4 import BeautifulSoup
import re
import os
import time

二、思路分析

1.思路分析:
这次我爬取的是笔趣阁里面的小说武动乾坤,我们先进入小说网 http://www.biquyun.com,对网站的网址和结构进行分析,
对网址进行分析,主页如图3:
Python3爬虫之爬取网络小说_第3张图片
输入武动乾坤打开后,对比主页发现在主页网址基础上加上武动乾坤的编号为/1_1872/,如图4
Python3爬虫之爬取网络小说_第4张图片
对网站结构进行分析,按F12检查网页源代码,如图5,我们仅需要的是Request Headers的内容,把里面的内容取出来放到字典中,其中关键的只有"User-Agent"。
Python3爬虫之爬取网络小说_第5张图片

#请求头字典
req_header={
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'Cookie': '__jsluid=f1ec49461c81456159185cd595593079; dsa=1; asdplan13482=1',
'Host': 'm.biquyun.com',
'Referer': 'http://www.biquyun.com/1_1872/1114034.html',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Mobile Safari/537.36'
}

每一本小说多有对应的章节网页,也就说每一章都有对应的网页,
我们以第一章为例,其地址信息为http://m.biquyun.com/wapbook/1872_1114034.html,其中“1872_1114034.html”就是该章节的网页名称,
第二章为http://m.biquyun.com/wapbook/1872_1114036.html
第三章为http://m.biquyun.com/wapbook/1872_1114038.html
我们发现:每一章都是1114034+2n(n为自然数)。点击开发者工具中的 Element 选项,以下是对应的截图信息(图7),通过分析,小说章节信息的路径为:#wrapper .content_read .box_con (PS:其中“#wrapper”号表示id为wrapper的项,“.content_read”表示class为content_read的项,按照此顺序放在一起就表示id为wrapper的项中的class为content_read的项中的class为con_box的相关信息,三者为树形关系。)
Python3爬虫之爬取网络小说_第6张图片
在该路径下,我们需要的信息主要有三项,以下是对应的class内容以及对应的说明:

  • bookname:可获取章节名称
  • content:可获取章节内容
  • bottom2:可获取下一章节地址

三、获取单章内容并将获取的文本信息写入txt文件中

以下是获取单章章节内容的代码:

#获取单章节小说
#小说主页地址
req_url_base='http://www.biquyun.com/'
#单独一本小说地址
req_url=req_url_base+'1_1872/'
#武动乾坤第一章页面地址
txt_section='1114034.html'

#请求当前章节页面  params为请求参数
r=requests.get(req_url+str(txt_section),params=req_header)
r.encoding = 'gbk' 
#soup转换
soup=BeautifulSoup(r.text,"html.parser")    
#获取章节名称                                    
section_name=soup.select('#wrapper .content_read .box_con .bookname h1')[0]        
#获取章节文本
section_text=soup.select('#wrapper .content_read .box_con #content')[0]           
#按照指定格式替换章节内容,运用正则表达式
section_text=re.sub( '\s+', '\r\n\t', section_text.text).strip('\r\n')          

print('章节名:'+section_name.text)
print("章节内容:\n"+section_text)

#打开小说文件
fo = open('1.txt', "ab+")
# 以二进制写入章节题目 需要转换为utf-8编码,否则会出现乱码
fo.write(('\r' + section_name.text + '\r\n').encode('UTF-8'))  
# 以二进制写入章节内容
fo.write((section_text).encode('UTF-8'))
#关闭小说文件
fo.close()

输出如图:
Python3爬虫之爬取网络小说_第7张图片
以.txt格式保存文件到桌面如图:
Python3爬虫之爬取网络小说_第8张图片
这里注意要解码格式是gbk,之前我以为笔趣阁的请求编码是UTF-8导致乱码如图:

r.encoding = 'gbk' 

Python3爬虫之爬取网络小说_第9张图片

四、获取整本小说并把文本写入一个txt文件中

通过前面几个步骤,我们知道了如何获取单章小说相关信息写入txt中,接下来获取整本小说内容就是在其基础上进行改进的,我们将通过一个函数来实现获取整本内容, 以下是获取整本书内容的代码:

#获取整本小说
#小说下载函数
#id:小说编号
#txt字典项介绍
# title:小说题目
# first_page:第一章页面
# txt_section:章节地址
# section_name:章节名称
# section_text:章节正文
# section_ct:章节页数
def get_txt(txt_id):
    txt={}
    txt['title']=''
    txt['id']=str(txt_id)
    try:
        print("请输入需要下载的小说编号:")
        txt['id']=input()
        req_url=req_url_base+ txt['id']+'/'                        #根据小说编号获取小说URL
        print("小说编号:"+txt['id'])
        res=requests.get(req_url,params=req_header)             #获取小说目录界面
        res.encoding = 'gbk' 
        soups=BeautifulSoup(res.text,"html.parser")           #soup转化
        #获取小说题目
        txt['title']=soups.select('#wrapper .box_con #maininfo #info h1')[0].text     
        txt['author']=soups.select('#wrapper .box_con #maininfo #info p')
        #获取小说最近更新时间
        txt['update']=txt['author'][2].text                                                       
        #获取最近更新章节名称
        txt['lately'] = txt['author'][3].text                                                     
        #获取小说作者
        txt['author']=txt['author'][0].text                                                       
        #获取小说简介
        txt['intro']=soups.select('#wrapper .box_con #maininfo #intro')[0].text.strip()            
        print("编号:"+'{0:0>8}   '.format(txt['id'])+  "小说名:《"+txt['title']+"》  开始下载。")
        print("正在寻找第一章页面。。。")
        #获取小说所有章节信息
        first_page=soups.select('#wrapper .box_con #list dl dd a')                          
        #获取小说总章页面数
        section_ct=len(first_page)                                                                  
        #获取小说第一章页面地址
        first_page = first_page[0]['href'].split('/')[2]                                
        print("小说章节页数:"+str(section_ct))
        print("第一章地址寻找成功:"+ first_page)
        #设置现在下载小说章节页面
        txt_section=first_page                                                                  
        #打开小说文件写入小说相关信息
        fo = open('{0:0>8}-{1}.txt.download'.format(txt['id'],txt['title']), "ab+")         
        fo.write((txt['title']+"\r\n").encode('UTF-8'))
        fo.write((txt['author'] + "\r\n").encode('UTF-8'))
        fo.write((txt['update'] + "\r\n").encode('UTF-8'))
        fo.write((txt['lately'] + "\r\n").encode('UTF-8'))
        fo.write(("*******简介*******\r\n").encode('UTF-8'))
        fo.write(("\t"+txt['intro'] + "\r\n").encode('UTF-8'))
        fo.write(("******************\r\n").encode('UTF-8'))
        #进入循环,写入每章内容
        while(1):
            try:
                #请求当前章节页面
                r=requests.get(req_url+str(txt_section),params=req_header)
                r.encoding = 'gbk' 
                #soup转换
                soup=BeautifulSoup(r.text,"html.parser")       
                #获取章节名称                                 
                section_name=soup.select('#wrapper .content_read .box_con .bookname h1')[0]
                section_text=soup.select('#wrapper .content_read .box_con #content')[0]
                #获取章节文本
                section_text=re.sub( '\s+', '\r\n\t', section_text.text).strip('\r\n')
                #获取下一章地址
                txt_section=soup.select('#wrapper .content_read .box_con .bottem2 a')[3]['href'].split('/')[2]  
                #判断是否最后一章,当为最后一章时,会跳转至目录地址,最后一章则跳出循环               
                if(txt_section==''):                                                          
                    print("编号:"+'{0:0>8}   '.format(txt['id'])+  "小说名:《"+txt['title']+"》 下载完成")
                    break
                #以二进制写入章节题目
                fo.write(('\r'+section_name.text+'\r\n').encode('UTF-8'))                                
                #以二进制写入章节内容
                fo.write((section_text).encode('UTF-8'))                        
                print(txt['title']+' 章节:'+section_name.text+'     已下载')
                #print(section_text.text.encode('UTF-8'))
            except:
                print("编号:"+'{0:0>8}   '.format(txt['id'])+  "小说名:《"+txt['title']+"》 章节下载失败,正在重新下载。")
        fo.close()
        os.rename('{0:0>8}-{1}.txt.download'.format(txt['id'],txt['title']), '{0:0>8}-{1}.txt'.format(txt['id'],txt['title']))
    except:     #出现错误会将错误信息写入dowload.log文件,同时打印出来
        fo_err = open('dowload.log', "ab+")
        try:
            fo_err.write(('['+time.strftime('%Y-%m-%d %X', time.localtime())+"]:编号:" + '{0:0>8}   '.format(txt['id']) + "小说名:《" + txt['title'] + "》 下载失败。\r\n").encode('UTF-8'))
            print('['+time.strftime('%Y-%m-%d %X', time.localtime())+"]:编号:"+'{0:0>8}   '.format(txt['id'])+  "小说名:《"+txt['title']+"》 下载失败。")
            os.rename('{0:0>8}'.format(txt['id']) + '-' + txt['title'] + '.txt.download',
                  '{0:0>8}'.format(txt['id']) + '-' + txt['title'] + '.txt.error')
        except:     
            fo_err.write(('['+time.strftime('%Y-%m-%d %X', time.localtime())+"]:编号:"+'{0:0>8}   '.format(txt['id'])+"下载失败。\r\n").encode('UTF-8'))
            print('['+time.strftime('%Y-%m-%d %X', time.localtime())+"]:编号:"+'{0:0>8}   '.format(txt['id'])+"下载失败。")
        finally: #关闭文件
            fo_err.close()

我们以其他小说《狙影》为例,其编号为20_20303(其实是狙影章节比较少,武动乾坤章节太多下全dowmload下来比较慢),运行结果如图:
Python3爬虫之爬取网络小说_第10张图片
以.txt格式保存文件到桌面如图:
Python3爬虫之爬取网络小说_第11张图片
注:若要把整本书一章一张内容分别放到一个txt文件中,就需要用到多线程的库,即

pip install threading

这里不过多描述,想了解的朋友可以阅读以下文章

  • 多线程

你可能感兴趣的:(Python3爬虫之爬取网络小说)