天天看点

python爬虫案例——小说

hello大家好,相信对于刚入坑python的同学来说写一个爬虫程序并且完美运行一定是想要去做并且完成后很有成就感的事。

首先,我们要选取一个小说网站(你懂的)

\

python爬虫案例——小说

这里我踩了各种坑,市面上比较流行的小说网站,他们的源码简直坑到爆,没错,就是你们知道的某阁某屋那一类的,我都试了一边。

源码乱,然后爬取的时候还各种索引越界,然后打断点查吧查到了对应的索引,再单独去查这个索引却又能查到东西,检查了半天是因为访问的时候有的章节链接会出现503,你敢信!!!

python爬虫案例——小说

好的,废话到此为止,下面开始正文。

首先,确定我们要爬取的小说网站,这里我就做个好人把我最终爬成功的网站贴出来,大家可以用这个,也可以自己去研究你们想爬的网站:

http://www.ouoou.com/

OK,网站确认完毕,我们找一本书点进去,然后右键查看源码(这个应该都知道吧)

首页源码打开以后,我们确认找一个比较好爬取书名的标签

python爬虫案例——小说
可以看到这个网站在这个

`标签下就很明显就有且只有书名,再ctrl+f查看下这一页源码有没有别的

<h1>

标签,如果没有,那就可以用这个,基本来说一个网页只会有一个

<h1>`标签。

# 获取书名
# <h1>星门  
m1 = re.compile(r'(.+)  ')

# 打印书名
book = m1.findall(txt)[0]
print(book.center(30, '='))           

书名获取到之后,我们要接着获取章节链接,为了后面跳转章节使用

python爬虫案例——小说

基本所有的小说网站最规范的就是章节链接这里的标签了,统一格式,容易读取,但是这个网站的章节链接是不全的,缺少了前面的网站主页,所以需要拼接上主页链接。

有的网站缺少小说首页链接,有的网站章节链接很完整不需要拼接,这种都在爬网站内容前注意看下,具体的改下链接这一块代码就行。

# 网站首页,方便后面拼接章节链接(适用于章节链接缺少主页的网站)
url2 = 'http://www.ouoou.com/'
txt = requests.get(url).content.decode("utf-8")

# 正则表达式:获取章节链接
m2 = re.compile(r'<dd><a rel="nofollow" href="(.+)" title="(.+)">(.+)</a></dd>')

# 将txt变量解析出来的内容通过m2正则处理
raw = m2.findall(txt)[0]

# i[0]为每章节的内容链接
SHJ = [url2 + i[0] for i in raw]           

章节链接拿到之后,就可以点击进入某一章节内查看章节的源码了。

章节源码打开后,要看两个地方,一个是章节名的标签,一个是正文的标签,有的网站章节名或者正文获取复杂,网站内部有的添加了一些乱七八糟的内容,有的是标签不唯一。

如果是章节名有这种情况的话,能处理就处理,不能处理的话可以考虑在章节链接那一并获取,把章节名跟章节链接作为元组存放到集合中,后面再利用索引查询获取章节链接和章节名。

而如果是正文内容标签复杂的话,如果能处理可以考虑处理,如果不好处理甚至不能处理的话,那就直接换个网站吧(等多踩几次坑的时候就知道我选的这个网站源码有多简洁方便了)

python爬虫案例——小说

同样,章节名这里也是以``标签为主体的,可以直接获取

# 正则表达式:章节标题
m4 = re.compile(r'<h1>(.+)')
t1 = requests.get(i).content.decode("utf-8")
# 章节标题获取
title = m4.findall(t1)[0]           

章节名获取完之后,整个小说需要我们获取的就剩下正文了,我们看下正文的标签

一般普通的网站正文开始标签是

div id="content" name="content"&gt;

,结束标签弄个什么

&lt;center&gt;

或者别的,其实如果是这两个倒还好,还挺好读取的,但是有的网站正文开始那里的标签还行,规规矩矩,但是正文结束那里就各种妖魔鬼怪了。

python爬虫案例——小说

其实我选的这个网站正文结束这里也是有一堆难以读取解析的标签,本来都准备放弃这个网站再重新找了,但是:

python爬虫案例——小说
python爬虫案例——小说

在这里就要好好夸夸这个网站的程序员了,竟然在正文外部写了

&lt;!--章节内容开始--&gt;

,

&lt;!--章节内容结束--&gt;

这两个注释标签,简直太人道了。

有了这两个傻子估计都能看懂的标签,还BB什么,开搞!

# 正则表达式:小说章节内容
m3 = re.compile(r'<!--章节内容开始-->(.+)<!--章节内容结束-->', re.S)
t1 = requests.get(i).content.decode("utf-8")
# 章节内容去除特殊字符
nrl = m3.findall(t1)[0].replace('<br />', '').replace('&nbsp;&nbsp;&nbsp;&nbsp;', '    ').replace('\n', '')           

代码中在正文获取的时候我做了一些处理,心细的同学可能会注意到,在我上面截的正文图里,每行正文都有一串特殊符号

和一个无用的标签

&lt;br /&gt;

这里我用re的replace方法把

&lt;br /&gt;

替换成了

''

,而

其实是四个空格,作为文章的缩进使用,在html里就写成了这个形式,所以在我们的代码里,我们给他还原回去,同样的用replace变成四个空格。

处理到这里就可以爬取了,但是爬完之后会发现,正文行与行之间爬下来之后空行很多,那这里就再次用到replace方法,将换行符替换掉:

replace('\n', '')

代码搞定,接下来就是运行代码,走起:

python爬虫案例——小说

可以看到,代码运行完成,在我的电脑上也生成了一个文本文件,打开里面就是我们的内容了。

import os
import re
import requests

# 获取书首页链接
url = "http://www.ouoou.com/ou_46550/"

# 网站首页,方便后面拼接章节链接(适用于章节链接缺少主页的网站)
url2 = 'http://www.ouoou.com/'
sy = requests.get(url).content.decode("utf-8")

# 获取书名
# 星门  
re1 = re.compile(r'(.+)  ')

# 打印书名
book = re1.findall(sy)[0]
print(book.center(30, '='))

# 正则表达式:获取章节链接
# <dd><a rel="nofollow" href="/ou_46550/40047071.html" title="第1章 巡检司">第1章 巡检司</a></dd>
re2 = re.compile(r'<dd><a rel="nofollow" href="(.+)" title="(.+)">(.+)</a></dd>')

# 将sy变量解析出来的内容通过re2正则处理
raw = re2.findall(sy)

# 删除无用章节
num = []
zj = re.compile('第(.+)章')
for i in range(len(raw)):
    if len(zj.findall(raw[i][1])) != 0:
        num.append(i)

rn = [raw[i] for i in num]

# i[0]为每章节的内容链接
zwurl = [url2 + i[0] for i in rn]

# 正则表达式:小说章节内容
re3 = re.compile(r'<!--章节内容开始-->(.+)<!--章节内容结束-->', re.S)

# 正则表达式:章节标题
re4 = re.compile(r'(.+)')

# 保存地址 小说同名的文件夹,若没有则创建
save_path = './' + book
folder = os.path.exists(save_path)
if not folder:
    os.makedirs(save_path)

# 开始写入
with open(save_path + '/' + book + '.txt', "a") as f:
    for i in zwurl:
        # 每章节小说内容获取
        t1 = requests.get(i).content.decode("utf-8")
        # 章节标题获取
        title = re4.findall(t1)[0]
        # 章节内容去除特殊字符
        nrl = re3.findall(t1)[0].replace('<br />', '').replace('&nbsp;&nbsp;&nbsp;&nbsp;', '    ').replace('\n', '')
        print("开始下载--->", title)
        f.write(title)
        f.write("\n\n")
        f.write(nrl)
        f.write("\n")
print("下载完毕!")
           
url = input('请输入小说网址链接:')           

只要把一开始的获取url写死改成input输入就行,测试之后是完全ok的。