《从零开始学习Python爬虫:顶点小说全网爬取实战》
顶点小说
装xpath helper
GitHub - mic1on/xpath-helper-plus: 这是一个xpath开发者的工具,可以帮助开发者快速的定位网页元素。
Question:加载完插件点击没反应
Answer:将开发人员模式关闭即可
爬虫介绍
分类:
- 搜索引擎:爬取范围广
- 聚焦爬虫:爬取范围聚焦
介绍:
程序发起请求(request),获取响应(response),解析response中的数据
URL
即统一资源定位符
组成:
- 协议
- http
- https:新增SSL协议(证书验证),之前花钱,现在开源了,所以大部分网站都是https,据说性能损耗,但忽略不计
- 主机IP地址(有时也包括端口号)
- 主机资源具体地址:如目录和文件名等
静态网站和动态网站
- 静态网站:数据在页面源代码中
- 动态网站:数据在接口中,网站通过ajax请求接口获取数据,再通过js镶在页面中
结构化与非结构化数据
- 结构化数据:可以用关系型数据库表示和存储,表现为二维形式的数据
- 非结构化数据:数据结构不规则,不方便用二位逻辑来表现,如办公文档、图片、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
案例:顶点小说抓取
导包,定义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"
}
获取小说分类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
获取最大页
# 获取最大页
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
获取每个分类的每一页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)
获取小说列表页信息
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
获取章节列表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
获取章节详情信息
# 获取章节详情信息
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
整合
# 获取小说分类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爬虫:顶点小说全网爬取实战》的更多相关文章
- 简单物联网:外网访问内网路由器下树莓派Flask服务器
最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...
- 利用ssh反向代理以及autossh实现从外网连接内网服务器
前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...
- 外网访问内网Docker容器
外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...
- 外网访问内网SpringBoot
外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...
- 外网访问内网Elasticsearch WEB
外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...
- 怎样从外网访问内网Rails
外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...
- 怎样从外网访问内网Memcached数据库
外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...
- 怎样从外网访问内网CouchDB数据库
外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...
- 怎样从外网访问内网DB2数据库
外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...
- 怎样从外网访问内网OpenLDAP数据库
外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...
随机推荐
- 解锁高效创新:IPD策略如何重塑产品开发流程
IPD(集成产品开发)涵盖了产品从创意提出到研发.生产.运营等,包含了产品开发到营销运营的整个过程.围绕产品(或项目)生命周期的过程的管理模式,是一套生产流程,更是时下国际先进的管理体系.IPD(集成 ...
- 2024-05-15:用go语言,考虑一个整数 k 和一个整数 x。 对于一个数字 num, 在其二进制表示中, 从最低有效位开始, 我们计算在 x,2x,3x 等位置处设定位的数量来确定其价值。
2024-05-15:用go语言,考虑一个整数 k 和一个整数 x. 对于一个数字 num, 在其二进制表示中, 从最低有效位开始, 我们计算在 x,2x,3x 等位置处设定位的数量来确定其价值. 举 ...
- java学习之旅(day.14)
可变字符串 StringBuffer:可变长字符串,运行效率慢,线程安全 StringBuilder:可变长字符串,运行效率快,线程不安全 package com.zhang.lei; //Strin ...
- 【U8】bom全阶 点击展开按钮,无法获得叶子子阶
经查看 是因为 子件的失效日期与生效日期是相同一天,延后子件的失效日期就可以在点击展开按钮后,看到子阶bom了.
- mit 6.824 lab1 思路贴
前言 为遵守 mit 的约定,这个帖子不贴太多具体的代码,主要聊聊自己在码代码时的一些想法和遇到的问题. 这个实验需要我们去实现一个 map-reduce 的功能.实质上,这个实验分为两个大的板块,m ...
- 如何用 Unity 做出一只赛博宠物
推荐的一些学习资料 unity 官方文档:Unity 用户手册 (2019.4LTS) - Unity 手册 视频教程:https://www.bilibili.com/video/BV1zB4y1C ...
- 7.22考试总结(NOIP模拟23)[联·赛·题]
不拼尽全力去试一下,又怎么会知道啊 前言 又是被细节问题搞掉的一天. T1 的话,与正解相差无几,少打了两个 else 一个 ls 打成了 rs,然后就爆零了(本来还有 45pts 的),然后加了一个 ...
- 鸿蒙HarmonyOS实战-ArkTS语言基础类库(概述)
一.概述 1.什么是语言基础类库 语言基础类库,也称为标准库或核心库,是编程语言提供的一组内置的基础功能和常用工具的集合.它通常包含了各种数据结构.算法.输入输出处理.字符串处理.日期时间处理.文件操 ...
- 使用python获取房价信息
从贝壳网获取房价信息. 基本的步骤和我的这篇博文一样:https://www.cnblogs.com/mrlayfolk/p/12319414.html.不熟悉的可参考一下. 下面的代码是获取3000 ...
- java中以字符分隔的字符串与字符串数组的相互转换
1.字符串数组拼接成一个以指定字符(包括空字符)分隔的字符串--String.join(),JDK8的新特性 String[] strArray = {"aaa","bb ...