本教程仅限研究学习,不得用于任何违法以及损害他人权利的行为,所做出的任何行为与作者无关

需要安装的第三方库:

  • requests
  • BeautifulSoup4
  • lxml(非必须,但推荐使用)

打开终端输入:

pip install requests beautifulsoup4

本文的目的是爬取久久小说网全站的小说,首先打开首页看一看。

浏览一下就能发现,可以通过上面的分类访问到所有小说。现在就进入一个分类具体分析。

打开浏览器的开发者工具,可以看到每一条小说的信息都分别包含在<div class="listbg"></div>当中。其中的<a>标签就有我们想要的所有信息:

  • 属性href="/txt/71515.html"就是小说详情页的链接,后续只需拼接成"https://www.txt909.com/txt/71515.html"即可
  • 属性title="斗罗之躺平麒麟,比比东偷听心声"就是小说的名字,后续保存时用来命名

虽然已经能够获取每条小说详情页信息了,但是还需要获取到下载链接才行,所以继续进入小说的详情页。

进去后发现了”进入下载列表“的按钮,继续点开。

进入下载界面后,有一个”下载TXT“的按钮,点进去发现就能下载小说了(这网站真良心,没有跳各种广告,也没有关注什么公众号就能下载),链接为http://www.vbiquge.co/api/txt_down.php?articleid=71515&articlename=斗罗之躺平麒麟,比比东偷听心声

分析一下链接

  • 基础链接为:http://www.vbiquge.co/api/txt_down.php
  • 参数有:
    • articleid=71515
    • articlename=斗罗之躺平麒麟,比比东偷听心声

第一个参数是文章ID,有没有发现这个ID似曾相识,不难发现,这就是文章详情页链接/txt/71515.html中的数字。第二个参数是文章的名字。正常说来,应该通过ID就能下载到小说,我们试着把articlename参数去掉,直接访问http://www.vbiquge.co/api/txt_down.php?articleid=71515。不出所料,小说同样被下载下来了,只是文件名为空,articlename参数的作用只是提供保存的文件名。

至此,工作已经完成一半了,从头开始分析一下。

  1. 我们先从某一个分类页面下手,通过<div class="listbg"></div>标签中的<a>标签来获取小说详情页链接小说名
  2. 因为最后下载小说仅需要提供ID,即小说详情页链接中的数字,所以中间访问详情页、访问下载页的操作都可以略去。
  3. 最后用第一步获取的小说名给文件命名。

现在开始写代码:

首先导入requests库用于网页请求以及获取响应,导入BeautifulSoup模块用于解析网页源码。

import requests
from bs4 import BeautifulSoup

整个程序可以用获取id和名字下载小说两部分组成,结构如下:

# 定义一个函数,需要分类页面的链接作为参数传入
def get_details(url):
    '''返回小说的名字和id'''
    pass

# 定义一个函数来下载小说,参数为下载链接和小说的名字
def download(id, title):
    '''下载小说,并以小说名保存文件'''
    pass

def main():
    '''主程序'''
    pass

if __name__ == '__main__':
    main()

下面来完善返回小说名字和id的函数:

def get_details(url):
    '''返回小说的名字和下载链接'''
    # 访问分类页面,获得响应
    resp = requests.get(url, headers=headers)
    # 从响应中获取源码,采用utf-8编码
    html = resp.content.decode('utf-8')
    # 创建BeautifulSoup对象,解析器设置为lxml,如果没有也可以使用Python自带的html-parser
    soup = BeautifulSoup(html, 'lxml')
    # 获取到所有<div class="listbg"></div>标签,返回一个列表
    divs = soup.find_all('div', class_='listbg')
    # 创建一个字典,key为小说名,value为ID
    novel_dic = {}
    # 这里采用for循环来写,如果熟悉字典生成式可以一行代码搞定
    for div in divs:
        # 此处的div也是一个BeautifulSoup对象
        # 获取到<a>标签,返回一个BeautifulSoup对象
        a = div.find('a')
        # 获取<a>标签的title属性
        title = a.attrs['title']
        # 获取<a>标签的href属性
        href = a.attrs['href']
        # 在href中截取数字部分
        article_id = href[5:-5]
        # 组成字典
        novel_dic[title] = article_id
    return novel_dic

如果不太明白可以将代码复制到本地,自行传入一个分类页面链接进行调用,或者进行单步调试查看结果

print(get_details('https://www.txt909.com/html/chuanyue/'))

将会得到类似于以下的结果

{'锦绣农家之福嫁天下': '77360', '宁城李子怡': '66923', '退婚后!玄学大佬靠算命轰动世界': '78502', '我妈才是穿越主角': '78196', '疯批暴君被福运农女喊去种田': '78142', '柯南之
魔童降世': '76904', '八零替嫁辣妻有空间': '78180', '穿越五零:末世夫妻咸鱼躺赢!': '73020', '重生农家:她带着拖油瓶逆袭': '78410', '九爷的心肝又杀出重围了': '78455', '我,签
到百年,被美女师尊曝光了': '76921', '惊!疯批狐王哭着求我摸尾巴': '78501', '穿越古代去
逃荒随身带着时空门': '78509', '修仙女配改拿龙傲天剧本': '77620', '钢铁苏联': '7383', '
海贼从岛主到国王': '76639', '道主有点咸': '76320', '寒门祸害': '1970', '踹了明爷后,他
每晚哭着求我抱!': '77176', '穿越后,我被竹马拖累成了皇后': '70294', '重生年代:炮灰长
姐带妹逆袭': '77565', '为什么正常夺舍的只有我': '76104', '斗罗之躺平麒麟,比比东偷听心
声': '71515', '修仙女配要上天': '76120', '每天都在醋自己[快穿]': '77066', '最强终极兵王宁城李子怡': '66922', '半妖农女有空间': '78323'}

接着完成download函数

def download(id, title):
    '''下载小说,并以小说名保存文件'''
    # 有的名字中带有问号,保存文件时会出错,直接替换掉
    title = title.replace('?', '')
    # 合成下载链接
    url = f'http://www.vbiquge.co/api/txt_down.php?articleid={id}'
    resp = requests.get(url, headers=headers)
    # 将文件储存为"分类/小说名.txt"
    with open(f'{category}/{title}.txt', 'a', encoding='utf-8') as f:
        f.write(resp.text)
    print(f'{title}下载成功')

此时,只需再修改主程序的代码,就能完成第一页的小说下载了。

还需导入os模块来判断目录是否存在

import os

def main():
    '''主程序'''
    # 判断分类目录是否存在,若不存在则创建
    if not os.path.exists('./'+category):
        os.mkdir('./'+category)
    # 接受函数返回的数据
    novel_dic = get_details(categories[category])
    # 遍历字典,对每一条数据调用download函数
    for title, novel_id in novel_dic.items():
        download(novel_id, title)

完整代码如下:

# 定义一个函数,需要分类页面的链接作为参数传入
import requests
from bs4 import BeautifulSoup
import os


def get_details(url):
    '''返回小说的名字和下载链接'''
    # 访问分类页面,获得响应
    resp = requests.get(url, headers=headers)
    # 从响应中获取源码,采用utf-8编码
    html = resp.content.decode('utf-8')
    # 创建BeautifulSoup对象,解析器设置为lxml,如果没有也可以使用Python自带的html-parser
    soup = BeautifulSoup(html, 'lxml')
    # 获取到所有<div class="listbg"></div>标签,返回一个列表
    divs = soup.find_all('div', class_='listbg')
    # 创建一个字典,key为小说名,value为ID
    novel_dic = {}
    # 这里采用for循环来写,如果熟悉字典生成式可以一行代码搞定
    for div in divs:
        # 此处的div也是一个BeautifulSoup对象
        # 获取到<a>标签,返回一个BeautifulSoup对象
        a = div.find('a')
        # 获取<a>标签的title属性
        title = a.attrs['title']
        # 获取<a>标签的href属性
        href = a.attrs['href']
        # 在href中截取数字部分
        article_id = href[5:-5]
        # 组成字典
        novel_dic[title] = article_id
    return novel_dic

# 定义一个函数来下载小说,参数为下载链接和小说的名字
def download(id, title):
    '''下载小说,并以小说名保存文件'''
    # 有的名字中带有问号,保存文件时会出错,直接替换掉
    title = title.replace('?', '')
    # 合成下载链接
    url = f'http://www.vbiquge.co/api/txt_down.php?articleid={id}'
    resp = requests.get(url, headers=headers)
    # 将文件储存为"分类/小说名.txt"
    with open(f'{category}/{title}.txt', 'a', encoding='utf-8') as f:
        f.write(resp.text)
    print(f'{title}下载成功')


def main():
    '''主程序'''
    # 判断分类目录是否存在,若不存在则创建
    if not os.path.exists('./'+category):
        os.mkdir('./'+category)
    # 接受函数返回的数据
    novel_dic = get_details(categories[category])
    # 遍历字典,对每一条数据调用download函数
    for title, novel_id in novel_dic.items():
        download(novel_id, title)
    print('下载完成')


# 定义几个全局变量,方便使用
    # 设置user agent,以免有反爬机制
headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36'
}
# 所有分类以及分类所对应的页面链接
categories = {
    '穿越小说': 'https://www.txt909.com/html/chuanyue/',
    '言情小说': 'https://www.txt909.com/html/yanqing/',
    '现代都市': 'https://www.txt909.com/html/dushi/',
    '耽美百合': 'https://www.txt909.com/html/baihe/',
    '历史架空': 'https://www.txt909.com/html/lishi/',
    '美文同人': 'https://www.txt909.com/html/tongren/',
    '武侠仙侠': 'https://www.txt909.com/html/wuxia/',
    '玄幻小说': 'https://www.txt909.com/html/xuanhuan/',
    '惊悚悬疑': 'https://www.txt909.com/html/jingsong/',
    '科幻小说': 'https://www.txt909.com/html/kehuan/',
    '网游竞技': 'https://www.txt909.com/html/wangyou/'}
# 要爬取的分类
category = '言情小说'  # 指定下载分类

if __name__ == '__main__':
    main()

输出如下:

自律的我简直无敌了下载成功
霸天龙帝下载成功
入赘王婿下载成功
超级修真弃少下载成功
至尊保安下载成功
空间之归园田居下载成功
柯南之敬酒不吃吃罚酒下载成功
·
·
·
下载完成

到此为止,第一部分教程结束,有不明白的地方可在评论区提出,建议自行复制代码到本地运行。

第二部分教程将讲解如何爬取所有页面,实现流式传输,多进程下载以及细节优化。