独家首发:零门槛掌握网络爬虫,打造你的专属小说数据库

225 阅读6分钟

网络爬虫实战:从零开始爬取顶点小说全攻略

在当今数据为王的时代,网络爬虫技术已成为获取海量网络信息的重要工具。无论是数据分析师、程序开发者,还是对网络数据感兴趣的普通用户,掌握基础的爬虫技能都能让您在信息获取方面事半功倍。本文将通过顶点小说网站的实例,带您系统了解网络爬虫的开发流程与核心技术。

一、爬虫基础知识

1、爬虫的分类与原理

网络爬虫按照爬取范围可分为两大类:

  • 搜索引擎爬虫:爬取范围广泛,如百度、Google等搜索引擎使用的爬虫
  • 聚焦爬虫:针对特定网站或特定内容进行定向爬取

爬虫的基本原理非常简单:程序发起请求(request),获取响应(response),然后解析 response 中的数据。这个过程模拟了人类使用浏览器访问网页的行为。

2、URL 的组成部分

URL(统一资源定位符)是互联网上标准资源的地址,通常由以下几部分组成:

  • 协议

    • http:超文本传输协议
    • https:在 http 基础上新增 SSL 协议(证书验证),提高安全性。现在大部分网站都采用 https 协议,虽然有轻微的性能损耗,但可以忽略不计
  • 主机 IP 地址:有时也包括端口号

  • 主机资源具体地址:如目录和文件名等

3、静态网站与动态网站

理解网站类型对爬虫开发至关重要:

  1. 静态网站:数据直接存在于页面源代码中,爬取相对简单
  2. 动态网站:数据存储在接口中,网站通过 ajax 请求获取数据,再通过 JavaScript 渲染到页面,爬取难度较大

4、结构化与非结构化数据

爬虫获取的数据可分为:

  1. 结构化数据:可以用关系型数据库表示和存储,表现为二维形式的数据
  2. 非结构化数据:数据结构不规则,不方便用二维逻辑表现,如办公文档、图片、HTML、音频和视频等

二、爬虫开发工具准备

1、XPath Helper 插件安装

XPath Helper Plus 是一个非常实用的浏览器插件,可以帮助开发者快速定位网页元素。

安装提示: 如果加载完插件后点击没有反应,请将浏览器的开发人员模式关闭即可。

XPath Helper 插件界面

2、XPath 语法介绍

XPath(XML Path Language)是用于确定 XML 文档中某部分位置的语言。Python 可以使用 XPath 语法定位 HTML 文档中的元素并进行数据抽取。

常用语法

  • /:从文档根目录开始选取
  • //:全局进行查找选取,相当于正则表达式的 .*?
  • //li/a/text():获取所有 li 下 a 标签的文本内容
  • //li//text():获取 li 标签下所有文本(不区分标签),仅限深度为 1
  • //a[@class="poptext"]:选取带有 class 属性值为 "poptext" 的 a 标签
  • @href:获取元素的 href 属性值
  • *:匹配任何元素节点,如 //*/bookstore/*
  • |:组合多个 XPath 表达式,如 //book/title | //book/price

动态网站解析说明: 动态网站能否使用 XPath 解析取决于数据返回格式。如果接口返回 HTML 文档,则可用 XPath 解析;如果返回 JSON 数据,则不能使用 XPath。本质上,XPath 是否可用取决于数据是否为节点数据(是否具有 DOM 结构)。

三、顶点小说爬取实战

1、环境准备与基础设置

首先导入必要的库,并设置请求头:

 import requests
 from lxml import etree
 import pymysql
 ​
 # 设置请求头,模拟浏览器访问
 headers = {
     "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0"
 }

2、获取小说分类 URL

 # 获取小说分类 URL
 def get_type():
     url = "https://www.cdbxs.com/sort/"
     source = requests.get(url=url, headers=headers).content.decode('utf-8')
     href_lists = etree.HTML(source).xpath('//ul[@class="nav"]/li/a/@href')[2:-4]
     type_lists = []
     for href in href_lists:
         type_lists.append(f"{url}{href.split('/')[2]}/1/")
     return type_lists

3、获取分类页面的最大页数

 # 获取最大页数
 def get_max_page(first_page_url):
     source = requests.get(url=first_page_url, headers=headers).content.decode('utf-8')
     max_page = etree.HTML(source).xpath('//a[13]/text()')
     return max_page

4、获取每个分类的分页 URL

 # 获取小说分类 URL
 type_lists = get_type()
 # 分类 URL 默认为第一页
 for first_page_url in type_lists:
     # 获取分类 URL 的前半部分
     type_url = first_page_url.split('1')[0]
     # 获取此分类下最大页数
     max_page = get_max_page(first_page_url)
     # 生成此分类下每一页 URL
     for every_page in range(1, int(max_page[0])+1):
         every_page_url = f"{type_url}{every_page}/"
         print(every_page_url)

5、获取小说列表页信息

 def get_book_info(every_page_url):
     source = requests.get(url=every_page_url, headers=headers).content.decode('utf-8')
     book_lists = []
 ​
     lis = etree.HTML(source).xpath("//ul[@class='txt-list txt-list-row5']/li")
     for li in lis:
         book_id_url = li.xpath("span[@class='s2']/a/@href")[0]
         book_id = book_id_url.split('/')[3]
         # 书名
         book_name = li.xpath("span[@class='s2']/a/text()")[0]
         # 最新章节
         new_chapter = li.xpath("span[@class='s3']/a/text()")[0]
         # 作者
         author = li.xpath("span[@class='s4']/text()")[0]
         # 更新时间
         update_time = li.xpath("span[@class='s5']/text()")[0]
 ​
         source = requests.get(url=f"https://www.cdbxs.com{book_id_url}", headers=headers).content.decode('utf-8')
         # 字数
         font_num = etree.HTML(source).xpath("//p[6]/span/text()")[0]
         # 摘要
         summary = etree.HTML(source).xpath("//div[@class='desc xs-hidden']/text()")[0]
 ​
         # 以元组形式添加至 book_lists
         book_lists.append((book_id, book_name, new_chapter, author, update_time, font_num, summary))
     return book_lists

6、获取章节列表 URL

 # 获取章节列表 URL
 def get_chapter_urls(chapter_list_url):
     source = requests.get(url=chapter_list_url, headers=headers).content.decode('utf-8')
     # 章节 URL
     chapter_urls = map(lambda x: "https://www.cdbxs.com" + x, etree.HTML(source).xpath("//div[@class='section-box'][2]/ul[@class='section-list fix']/li/a/@href | //div[@class='section-box'][1]/ul[@class='section-list fix']/li/a/@href"))
 ​
     return chapter_urls

7、获取章节详情信息

 # 获取章节详情信息
 def get_chapter_info(chapter_url):
     source = requests.get(url=chapter_url, headers=headers).content.decode('utf-8')
     # 标题
     title = etree.HTML(source).xpath("//h1[@class='title']/text()")
     # 正文
     content = ''.join(etree.HTML(source).xpath("//div[@id='nb_content']/dd//text()"))
     if title:
         return title[0], content
     else:
         return '', content

8、整合爬虫流程

 # 获取小说分类 URL
 type_lists = get_type()
 # 分类 URL 默认为第一页
 for first_page_url in type_lists:
     # 获取分类 URL 的前半部分
     type_url = first_page_url.split('1')[0]
     # 获取此分类下最大页数
     max_page = get_max_page(first_page_url)
     # 生成此分类下每一页 URL
     for every_page in range(1, int(max_page[0]) + 1):
         every_page_url = f"{type_url}{every_page}/"
         # 获取小说列表页信息
         book_info_lists = get_book_info(every_page_url)
         # 获取章节列表 URL
         for book_info in book_info_lists:
             print(f"爬取小说:{book_info[1]}...")
             book_id = book_info[0]
             chapter_urls = get_chapter_urls(f"https://www.cdbxs.com/booklist/b/{book_id}/1")
             for chapter_url in chapter_urls:
                 chapter_info = get_chapter_info(chapter_url)
                 print(chapter_info[0])  # 打印章节标题
                 print(chapter_info[1])  # 打印章节内容

四、爬虫技术进阶方向

本教程介绍了基础的爬虫开发流程,但在实际应用中,还可以进一步优化:

  1. 数据存储:将爬取的数据存入 MySQL、MongoDB 等数据库
  2. 多线程/多进程:提高爬取效率,大幅减少爬取时间
  3. 反爬处理:应对网站的反爬机制,如 IP 代理池、Cookie 池、请求延时等
  4. 分布式爬虫:利用多台服务器协同工作,进一步提升爬取效率

五、小结与展望

本文通过顶点小说网站的实例,详细介绍了网络爬虫的基本原理和开发流程。从 URL 结构、XPath 定位到数据提取,系统地展示了爬虫开发的各个环节。掌握这些基础知识后,您可以根据自己的需求,开发出适用于不同网站的爬虫程序。

关注公众号【码途有你】,后续将为大家带来更多爬虫进阶内容,包括但不限于数据入库、多线程多进程爬取、反爬机制应对等技术内容!