欢迎光临散文网 会员登陆 & 注册

python爬虫爬取小说

2023-04-25 22:58 作者:一把江湖刀sss  | 我要投稿

注:本教程仅限交流学习,支持小说作者,请上起点中文网订阅。 

因为爬虫涉及到的知识有点多,所以不建议零基础的同学学习,但是可以通过对我的代码的修改去爬取自己需要的小说,请注意,不要直接拉到最下面,这个帖子我会详细的说明各个代码的作用,以及出错会导致的问题,如果不去仔细看的话,代码一旦出问题你就会手足无措,无从下手。 

推荐粒粒的python基础和爬虫教程:

 https://www.bilibili.com/video/BV1d54y1g7db/?share_source=copy_web&;vd_source=717e252d12ec490be1cd613be97ab875

本代码使用的是pycharm编辑器,如果不会安装的请百度,python不会配置的也去百度。 

代码:

链接:https://pan.baidu.com/s/1KNmNHSiubDAT3u4ogD5VYw?pwd=1453 

提取码:1453 

1.第一步我们要做的是导入我们要用到的python包,分别是: 

bs4、requests、time、os、random 

看到陌生的包不用担心,在代码的编写中,我会一一介绍他们的作用。 

下面开始导入包: 

 

 

 

在经历了漫长的等待中,终于下好了第一个包,下载成功的标志是:出现successfully........语句 

然后用相同的方法下载其他包,其中time、os、radom包是python内置,不需要用pip下载,因此我们只需要下载requests包 

 

现在我们下好了所需要的包 

2.第二步我们就要开始敲代码了,我们首先导入需要的包: 

 

因为我们这个爬虫代码的目的是爬取小说所以我们先来打开我们要爬取的网站:

https://www.biqukan8.cc/

这是一个盗版小说网站,我们今天的目的就是从里面爬取到《一念永恒》这本小说。(再次声明支持耳根大大) 

我们先来打开一念永恒的第一章: 

https://www.biqukan8.cc/1_1094/5403177.html

 

这就是一念永恒第一章的界面了,我们首先尝试爬取第一章的内容,然后再拓展到每一章节。 

首先我们来编写代码把这个网页文件爬取下来,然后进行分析,提取出我们真正想要的——章节内容,代码如下: 

 

通过requests包中的get函数来获取网页文件,其中get函数的url参数是网页的地址,并给网页文件创建req对象存储,同时通过.status_code函数打印出网页状态码,来判断是否成功连接。如果状态码为200,则证明成功连接,如果是其他状态码,如著名的404,则表示没有正确连接. 

 

好的,接下来我们运行代码,果然不出所料,报错了: 

 

代码报错,大眼一看很是吓人,但是只要分析所给的错误代码,再去找度娘,基本都能解决,那我们这个为什么报错呢?答案是请求头,正常通过浏览器向服务器发送请求会在请求头上显示浏览器的信息,但是通过python爬虫程序发送请求,在请求头上会有python的字样,会被服务器驳回请求,这是一种非常常见的反爬虫措施。 

那我们怎么办呢?只需要通过给get函数传入一个header参数进行请求头的伪装即可,问题是我们要伪装成什么呢?其实我们只需要伪装我们自己的浏览器即可: 

 

打开浏览器控制台,在网络栏目,打开一个文件,然后在他的标头栏目里,下滑找到user-agent,里面的就是你浏览器的请求头。 

然后我们在代码中进行请求头的伪装: 

 

可以发现请求头是以字典的形式输入的参数,因为除了user-agent还有其他的参数可以伪装,在这里我们不做讨论。 

我们运行尝试一下: 

 

 

可以看到打印出的状态码是200,证明我们请求成功。 

此时req对象已经包含了网页文件的内容,通过,text函数可以提取出网页文件: 

 

运行结果如下图: 

 

可以看到这和我们在浏览器控制台左下角的网页源代码相同,可以确定就是我们需要的网页文件,但是我们需要的是第一章的内容,而不是网页源代码。 

3.第三步我们就开始对第一章的内容进行爬取了: 

在将章节文件提取出来之前,我们需要先对网页文件进行一些方便我们阅读和控制的操作,这时候就要用到我们的Beautifulsoup类了: 

 

代码运行结果如下: 

 

好吧,和之前确实没有什么方便阅读,但是他的主要作用是对网页文件进行操作: 

我们首先在浏览器控制台寻找章节内容对应的标签: 

 

 

可以看到我们需要的只是这一div标签下的内容,我们就需要把这一div标签截取下来,但是我们可以发现网页文件中有很多的div标签,那怎么把这一div标签取出来呢? 

我们可以看到,这一div标签具有一个class属性,而他的class属性的值是唯一的showtxt,我们就可以通过这一点,唯一的识别并截取这一div标签: 

具体操作是BeautifulSoup类的findall方法: 

代码如下: 

 

其中findAll方法的class参数因为要与python的calss关键字分开,参数名是class_ 

代码运行结果如下: 

 

这是一个很长的列表,其中只有一个元素,因为class属性是showtxt的div标签只有这一个,列表中的这一个元素即为div标签下的所有内容。 

但是这里面还是有除了我们想要的章节内容以外的很多符号,我们可以使用 .text函数来取出其中的文本文件(注意,使用.text的对象是text_1[0],因为text_1是一个列表,我们操作的只是他的第一个元素),代码如下: 

 

运行结果如下: 

 

可以看到目的已经基本实现了,但是每一段之间是由很多个看似空格的东西组成的,我们复制到代码里面会发现,这是一些奇怪的东西,但我们只需要把他们换成换行符,使用replace函数即可。 

代码如下: 

 

运行结果: 

 

实际上,这一大堆奇怪的东西可以用:'\xa0' * 8代替(我也不知道为什么),替换之后的代码: 

 

不管怎么样,看样子是美观了不少,运行结果如下: 

 

嗯,结果是一样的。 


我们已经爬取了一念永恒的第一章,接下来我们的目标是:

1.读取出整本小说的每一章节 

2.把他们保存为文本格式(.txt) 

3.每一章的文件名就是章名 

好的,接下来我们就开始一条条实现喽: 

1.要想读取出每一章节,最重要的是什么呢?我们现在只需要第一章的网页链接,就可以爬取第一章的内容,如果我们有第二章的网页链接,既可以爬取第二章,以此类推。当然,我们不可能直接手动输入每一章的网页链接,那么我们就得想办法把每一章的网页链接爬取出来,那么从哪里可以获得每一章的网页链接呢?没错,就是这本书的目录界面,因为我们可以从目录点击任一一章的章名跳转到该章的网页: 

 

那我们打开浏览器的开发者工具来查看网页源代码: 

 

 

我们可以看到,每一章的章名在一个dd标签里面,而所有的dd标签在一个大的div标签里面,所以,我们想要提取到每一章的网页1链接的话,只需要提取到这个div标签,那这一标签是怎么和其他div标签区分的呢?没错,就是class = "listmain",这和我们之前讲的是一样的,那么让我们来写代码: 

因为网页链接的爬取和章内容的爬取并关联,所以我们新建一个py文件,最后再和之前的组合使用: 

 

前面的代码和之前的差不多,只是网页链接的不同,但是当我们1运行之后,就会发现第一个有意思的bug了: 

 

可以看到,打印出的网页源代码中居然有很多乱码,我们回到浏览器,看一下浏览器开发者工具的源代码: 

 

经过对比可以发现,乱码的部分正是每一章的章名,但是我们的章名还是有用的,即保存为tex格式的文件名要命名为章名,那么这些中文究竟是为什么乱码的呢? 

本来我也是一头雾水,然后在我搜索度娘之后得到了答案: 

让我们打开浏览器的开发者界面: 

 

可以看到,我们随便点一个文件之后,发现他的请求头里面有一项accept-encoding里面有一个gzip,这就是导致中文乱码的元凶,因为浏览器返回给服务器时为了节省流量会压缩后发送,然后压缩后的文件被python爬虫爬取下来,所以导致了中文乱码,解决方法也很简单,首先我们看一下究竟改成了什么编码方式: 

 

使用encoding方法就可以查看该文本的编码方式,我们发现编码方式时ISO-8859-1,我们只需要把他转换为我们通常使用的UTF-8或者gbk即可,由于pycharm终端默认编码方式为gbk,所以我们把他转换为gbk格式: 

 

结果正常输出,需要注意的时:此时我们的爬虫文件编码方式为UTF-8,如果换成gbk会报错(我也不知道为什么) 

好了,我们现在已经把目录网页文件的源代码打印到终端上了,我们接下来就要提取其中包括每一章的章名和链接的位置了: 

 

和之前的代码一样,现在我们又得到了一个只有一个元素的列表: 

 

(姑且不去理会这些乱码的中文) 

我们已经得到了需要的div标签下的内容,然后我们需要获得里面的a标签(不用管dd标签,因为他们都是一样的),只需要再次使用BeautufulSoup和findALL: 

 

 

我们已经得到了一个具有很多元素的列表,接下来需要循环遍历出每一个章节的网页链接和章名: 

 

 

我们已经得到了这一堆的网页链接和章名,接下来通过对他们的处理就可以得到我们想要得到东西了: 

对于章名的处理非常简单,因为只有章名是文本文件: 

 

 

运行结果中,我们已经成功的把章名打印出来了,接下来处理网页链接: 

 

网页链接被储存在href标签下,我们只要用get函数将其取出即可,运行结果: 

 

可以看到我们已经成功的获得了网页链接,但是会有人说:不对啊啊,这和我平常看到的网页链接长得不一样啊,其实这只是网页链接的后半部分,我们只需要在前面加上该网站的域名就可以进行访问了: 

 

 

我们已经得到了这一堆的网页链接和章名,接下来通过对他们的处理就可以得到我们想要得到东西了: 

对于章名的处理非常简单,因为只有章名是文本文件: 

 

 

运行结果中,我们已经成功的把章名打印出来了,接下来处理网页链接: 

 

网页链接被储存在href标签下,我们只要用get函数将其取出即可,运行结果: 

 

可以看到我们已经成功的获得了网页链接,但是会有人说:不对啊啊,这和我平常看到的网页链接长得不一样啊,其实这只是网页链接的后半部分,我们只需要在前面加上该网站的域名就可以进行访问了: 

 

 

好的我们现在拥有了章名和网页链接,和先前的代码组合使用,就可以进行正本小说的爬取,代码如下: 

 

我们已经两个代码粘在一起并把重复的变量名替换,但是这并不完善,因为我们要把这些写入到文本文件里面并保存在电脑中,代码如下: 

 

最后的time.sleep(1)指每次循环结束睡眠一秒继续1下一次循环,为了防止我们请求过快被服务器拒绝响应 

运行之后,只是不断的提示警告: 

 

但是打开我们设置的文件目录之后,就能发现已经输出了我们想要的小说内容: 

 

那我们的教程到这里就结束了? 

当然不是,因为还有一个问题没有解决:当我们爬取的章数过多时(大概是三四百章)服务器会识别出爬虫程序或者干脆直接认为是ddos攻击,然后就会把我们的请求头给禁掉,我们的程序也就会终止,如下图: 

 

 

 

 

这些是比较有用的报错信息。 

接下来我们尝试继续用该请求头访问该网站后会发现该请求头已经被禁止了 

那么这种问题有解决的方法吗?有的: 

我们只需要弄一大堆的请求头然后每次爬取就随机使用一个请求头即可解决: 

 

这就是一个请求头列表,里面有很多很多的请求头, 

 

通过random包里面的choice随机取一个请求头赋值给header 

但是这样做只能随机一开始连接目录时的请求头,一旦爬虫开始运行,就会一直使用该请求头,并没有达到我们想要的目的,那怎么解决呢? 

我们只需要在for循环的结尾(可以是time的前面,也可以是后面)再次把请求头随机赋值一次即可,代码如下: 

 

好了我们现在可以重新运行代码了,但是此时还是有很小很小的概率会被禁止,然而我们现在重新运行一次之后,还是会从第一章开始下载,那么这个问题怎么解决呢? 

还有我们终端一直弹出的警告怎么回事,怎么解决呢? 

下载文本的过程中没有任何提示是否不太友好呢? 

如果我想要换一本小说下载,就需要重新研究一边代码将其中的某些东西进行改变,这又该怎么解决呢? 

这一切,请听下回分解。 

下面我们来依次解决: 

1.首先请求头被禁止的问题暂时没有好的解决方法,但是我们可以使用代码把开始下载的章节设置为最新的一章,但是我们不能第二次运行的过程中读取到第一次运行后的结果与变量,那么我们该怎么去读取上次下载的最后一章呢?答案是去读取我们下载到的文件夹里面的最新章节,代码如下: 

 

 

代码已经正常开始下载,但是为我们注意到,他是从最新章节的前面十几章开始下载的,那这是为什么呢? 

答案是小说网站会把最新的十几章放在最前面看下图: 

 

我们打开开发者工具,查看一些源代码: 

 

发现果然和我们想的一样,这也是为什么我们上面代码的for循环里面有一个判断num是否小于1300,因为新的几章都在1300之后且距离不远。 

接下来只需要在下标索引的开始索引里面加上这几章的数量即可: 

 

但是我们试运行之后发现还是少了三章的距离,这是为什么呢? 

我也不清楚,但是这三章的距离还是勉强可以接受的,总算不用重新开始下载了(有强迫症的话可以num+16) 

2.解决终端警告问题: 

这个警告从我们开始用BeautifulSoup就开始出现,但是由于没有对我们的代码运行造成影响,我也就没去管他,那我把他复制下来经过搜索后发现,他的大致意思是:GuessedAtParserWarning:未明确指定解析器,因此我正在为此系统使用最佳的HTML解析器(“ html.parser”) 

解决方法很简单的,给BreatifulSoup类传入一个html.parser即可: 

 

我们再次运行,发现果然没有了警告: 

 

但是新的问题很快就来了,就是在终端界面什么都没有打印出来,代码运行到哪个阶段我也不知道,这确实不太友好,那么我们就来解决第三个问题: 

3.要解决这个问题其实很简单,我们只需要在每一章下载完之后手动打印一些XXXX章下载完毕即可,代码如下: 

 

我们再来看一下终端,是不是就友好很多了呢? 

 

好的,那么我就就只剩下最后一个问题了: 

4.解决每一本小说都要往下翻找修改1代码: 

解决方法就是把我们需要改变的网址,链接,保存地址等通过变量命名的形式放在最上面,我们只需要在最上面几行代码进行修改即可,代码如下: 

 

 

 

那我们接下来尝试一下换一本小说下载: 

 

我们就在该站主页随便点一个元尊吧: 

 

把目录网址复制一下,还有文件保存路径: 

注意该路径必须手动创建好,不然会报错: 

成功运行,但是我们遇到了问题,就是他是从第二章开始下载的: 

 

我推测是num+13太大了,我们改成+12试试: 

注意,此时要把所有已经下载的删除,不然代码会从最新章节往后下载: 

 

已经解决,说起来刚刚运行时突然报错,我又运行了一下又正常了,不出意外是随机到不能用的请求头了。 

那我们今天的教程就到此结束了吗? 

本来应该是这样的,但是我又想到,我们能不能做的更厉害一点,把他包装成一个exe可执行文件呢? 

实际上是可行的,那么我们面就来做这个吧!

我们刚才留下的目标是把他打包成一个exe可执行文件,但是在把他打包成可执行文件之前,我们还需要对他进行一些调整,因为可打包之后就不能随便的看到源代码,也就没办法更改我们头的两个参数,所以我们就需要用户把更改的参数传入进来,代码如下: 

 

 

我们的代码主要分为三个部分: 

默认参数: 

 

由于每本小说的目录完全不同,所以目录网址没有默认参数。 

用户赋值: 

 

条件判断: 

 

用户输入的能用的就替换掉默认的,不能用的就使用默认的。 

这样之后基本框架就完毕了,但是我们为了用户(如果有的话)的体验,我们还要提示他一些东西,比如把盗版网站的网址打印出来让他自己去访问,比如提示他如果代码运行出错(即随机到的错误的请求头)就重新运行一遍..... 

 

写完也就是这个样子了,接下来我们就要开始去把他做成exe文件了: 

打包py文件需要用的pyinstaller包: 

我们现在cmd界面下载他,等等,你不会连cmd都不会打开吧? 

首先按住键盘上的win+r键: 

 

在里面输入:cmd回车: 

 

就进入了控制台,也就是我们常说的cmd: 

然后和在pycharm终端装包的操作一样: 

输入:pip3 install pyinstaller 

 

(不要看我上面的报错嗷,报错的话自己解决) 

安装完之后,我们打开我们的py文件存放的地方: 

 

在这个界面,点击上面的目录位置: 

 

输入cmd然后回车: 

这是什么意思呢?就是从这个文件目录里面进入cmd,然后这个文件夹下的文件就成了根目录(也是大多数程序的默认目录)里的文件: 

然后输入指令:pyinstaller -F xiaoshuopaqu.py回车运行 

xiaoshuopaqu.py是你的py文件的名字 

 

运行之后回到我们的代码目录下面: 

 

会发现多了两个文件夹,打开里面的dist文件夹: 

 

这就是我们做好的exe文件了 

可以看到我们的原代码只有10k,然而这个可执行文件却有12mb,这是因为打包过程中把python的解释器和各种包也都打包进去了,这也意味着,这个可执行程序并不需要使用者拥有python解释器,我们也就可以随便的分享给任何一个人。 

我们来运行一些这个文件: 

 

完美运行,好的,我们的教程也就到这里结束了。 

 

附加:这个可执行文件还可以加一个骚操作,那就是把他的图标换成你想要的样子,因为默认的实在是太丑了: 

只需要打包过程中加入一个参数: 

首先把自己制作的ico文件放到和代码一个目录里面: 

 

然后再cmd打包过程中输入: 

pyinstaller -F -i dao.ico xiaoshuopaqu.py 

其中dao.ico是你的ico文件的名字 

 

然后再次查看dist文件夹: 

 

发现图标并没有变! 

难道是我们出错了? 

不是的,我们只需要把他复制到桌面就可以发现: 

 

他已经变成了图标的样子。 

好了我们的教程到这里也就结束了,整个教程写了三天,主要是需要一步步的推导,而不是说我遇到一个问题就解决一个问题,总的来说,虽然只是一个简单的教程,但是我投入的时间和精力确实很多,估计我以后写教程也不会这么详细了,因为实在是太累了...... 

(来一把简单又快乐的骑砍怎么样:)) 

—————————————————————————————————————————

该教程是我在学习完爬取小说之后写的,其中有些地方借鉴了一篇教程,但是还由于现在找不到了链接了,无法引用,深感愧疚……

此教程是之前写的,现在发在B站主要目的是方便给别人发链接,有什么问题评论区留言哦~




python爬虫爬取小说的评论 (共 条)

分享到微博请遵守国家法律