顶点小说

装xpath helper

GitHub - mic1on/xpath-helper-plus: 这是一个xpath开发者的工具,可以帮助开发者快速的定位网页元素。

Question:加载完插件点击没反应

Answer:将开发人员模式关闭即可

爬虫介绍

分类:

  • 搜索引擎:爬取范围广
  • 聚焦爬虫:爬取范围聚焦

介绍:

程序发起请求(request),获取响应(response),解析response中的数据

URL

即统一资源定位符

组成:

  • 协议

    • http
    • https:新增SSL协议(证书验证),之前花钱,现在开源了,所以大部分网站都是https,据说性能损耗,但忽略不计
  • 主机IP地址(有时也包括端口号)
  • 主机资源具体地址:如目录和文件名等

静态网站和动态网站

  1. 静态网站:数据在页面源代码中
  2. 动态网站:数据在接口中,网站通过ajax请求接口获取数据,再通过js镶在页面中

结构化与非结构化数据

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

xpath

概念:即为XML路径语言(XML Path Language),用于确定XML文档中某部分位置的语言,python可以使用xpath的语法定位html文档中某部分的位置,并进行抽取

示例:xpath是抽取静态网站数据的常用方法

Question:动态网站可以用xpath进行解析吗?

Answer:

动态网站采用了ajax技术,ajax发起请求对页面进行替换分为 整块替换和 部分替换,部分替换则接口返回数据格式为Json,整块替换则接口返回html文档

如果返回html文档,则可用xpath进行解析,如果返回Json数据,则不可用xpath进行解析

总结:xpath是否可进行解析取决于数据是否为结点数据(是否具有结点),JSON为字符串,肯定不可用xpath进行解析

语法:

  • /:从文档根目录开始选取
  • //:全局进行查找选取,//代表前面有东西,但不重要,相当于正则表达式的 .*?
  • //li/a/text():可以获取小说的所有书名,然后通过python进行切片获取具体的个别数据
  • //li//text():可以获取 li 标签下的所有文字(不区分什么标签),只限深度为1
  • //a[@class="poptext"]:可以选取带有 class属性 的 a标签
  • @href:可以获取此元素的 href属性值
  • *:匹配任何元素结点,如//*、/bookstore/*
  • |:类似and,都获取,如//book/title | //book/price

案例:顶点小说抓取

  1. 导包,定义headers(有的小说网站对headers无要求,有的有要求)
    import requests
    from lxml import etree
    import pymysql # headers
    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/")
    # print(type_lists)
    return type_lists
  3. 获取最大页
    # 获取最大页
    def get_max_page(first_page_url):
    source = requests.get(url=first_page_url, headers=headers).content.decode('utf-8')
    # print(source)
    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
    # print((book_id, book_name, new_chapter, author, update_time, font_num, summary))
    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:
    # print(chapter_url)
    chapter_info = get_chapter_info(chapter_url)
    print(chapter_info)
    print(chapter_info[0])
    print(chapter_info[1])
    # print(f"title:{chapter_info[0]}")
    # print(f"content:{chapter_info[1]}")

:关注我,后续会陆续出爬虫内容(包括但不仅限于顶点小说进阶:数据入库、多线程多进程爬取数据)

更多精致内容,关注公众号:[CodeRealm]

《从零开始学习Python爬虫:顶点小说全网爬取实战》的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. VNC 远程桌面很卡,替代方案如下

    VNC 远程桌面是一款古老的远程桌面软件,是基于 Unix 和 Linux 操作系统的免费的开源软件.免费开源很好,但是 VNC 也存在一些缺点. 1.VNC 远程桌面很卡 想白嫖 VNC,就要接受卡 ...

  2. C语言:实现数组的删除和增加

    /*      删除方法:     如:12  32  56  84  95     用覆盖的方法     若删除第三个,则第四个要覆盖第三个,第五个要覆盖第四个     覆盖完:12  32  84 ...

  3. kubernets之带有limit的资源

    一  pod中容器的limits属性的作用 1.1  创建一个带有资源limits的pod apiVersion: v1 kind: Pod metadata: name: limited-pod s ...

  4. [渗透测试] HTB_Surveillance WriteUp [上]

     靶机:Surveillance (from Hack The Box)  工具:Kali Linux  目标:拿到user和root的一串32位hex字符串 ## 配置hosts 环境启动后,要设置 ...

  5. 记录一次由nginx配置引发出来的一系列的缓存问题

    问题描述: 在做一个企业微信的移动端项目时,每次修改代码后并且打包.部署完毕,再次打开页面总是会有上一次的缓存,一开始以为是cookie和webStorage缓存导致的,然后每次清除还是有缓存,后来把 ...

  6. 基于docker的cicd

    基于docker的cicd 飞书链接: https://dlk2qiw7lh.feishu.cn/docs/doccnyu14HTaamVzASIXreCSNjf 相关软件 链接:https://pa ...

  7. 算法金 | 一文读懂K均值(K-Means)聚类算法

    ​大侠幸会,在下全网同名[算法金] 0 基础转 AI 上岸,多个算法赛 Top [日更万日,让更多人享受智能乐趣] 1. 引言 数据分析中聚类算法的作用 在数据分析中,聚类算法用于发现数据集中的固有分 ...

  8. JavaSE 关键字和标识符

    目录 关键字 标识符 标识符命名规则 标识符命名规范 字面值 关键字 具有特殊含义的 命名时不可以与关键字重名 标识符 也就是名字,对类名,变量名称,方法名称,参数名称等修饰 标识符命名规则 以字母, ...

  9. .net formwork WebApi 跨域问题

    背景: ASP.NET Formwork  Api / ASP.Net Core Api  做比较. 有关  Global.asax.FilterConfig.cs 和 RouteConfig.cs ...

  10. js随机数 比较运算符

       // 生成一个随机数 1 - 100 范围内的随机数         // 大家先记住 JavaScript 生成随机数值的 公式         // 如果要 生成 a - b  范围内的数值 ...