Python3网络爬虫--爬取有声小说(附源码)
看过我的在线小说播放器博文的朋友问我,能不能详细介绍一下小说播放链接的获取。本篇博文将要介绍解密有声小说反爬,重点在于获得小说真实播放地址。
一.目标
1.首页
这是一个可以在线播放有声小说的网站,通过选择书籍,选择剧集最后实现有声小说的在线收听。
2.网页源代码
通过查看网页源代码,发现此网站为静态网站,所有网页内容都能在源代码中找到。
(网页源代码)
二.爬取详情页
1.查看详情页
可以看到,网页从上到下大致分为三部分,小说详情,小说简介,播放列表。
2.小说详情
打开开发者工具,摁下键盘组合键Ctrl+Shift+M,使用鼠标点击小说详情确定元素所在html标签,可以确定,小说详情在第一个class为book的div标签里。在这个标签中能得到小说封面、名称、类型、等级、状态、更新时间。
3.小说简介
在第二个class为book的div标签中能得到小说简介、作者、播音。
4.播放列表
在id为playlist的div标签中,能得到小说的播放列表,每集小说都在对应的li标签中,li标签下的a标签中包含小说剧集和播放网页地址(并非真正音频地址)。
三.爬取小说音频
1.确定数据加载方式
随便点击一个剧集,网页就会跳转到音频播放页面。
使用Ctrl+U查看网页源代码,未发现类似.mp3、.m4a格式音频地址,此时可以确定真实音频地址被加密了,或者是通过单独的接口异步加载进入网页。
2.寻找真实音频播放地址
开发者模式别关,刷新网页,点击网页的播放键,开始播放音频,将开发者工具筛选从All(所有)改成Media(媒体)。
通过筛选,发现此音频真实播放地址为:
3.URL解码
上面的地址是什么哦,好乱啊,不要着急,这是URL编码,可以使用在线工具进行编码转换。
哦,原来网页将中文进行了编码转化。(我用的URL解码网站:http://www.jsons.cn/urlencode/)。
4.加密方式
回到网页源代码,下面这串Js吸引了我的注意。
于是去开发者工具中进行搜索函数名:FonHen_JieMa
发现此函数先是将传入的参数进行了字符串切割,然后遍历切割后的数组,使用String.fromCharCode()函数进行处理后,返回结果。
因为对Js了解不多,特地查了一下:
JavaScript fromCharCode()方法:
将Unicode 编码转为一个字符
var n = String.fromCharCode(65);
输出结果:A
此函数会将一个ASCII(Unicode)编码转成字符。
5.解密
将加密字符以*为分隔符进行切割,得到:
['', '51', '48', '49', '51', '48', '47', '121', '111', '117', '115', '104', '101', '110', '103', '47', '29572', '24187', '22855', '24187', '47', '26007', '32599', '22823', '-27066', '51', '-24679', '29579', '20256', '-29708', '95', '-29346', '25196', '47', '48', '48', '48', '49', '46', '109', '112', '51', '38', '57', '53', '53', '38', '116', '99']
去除掉空字符串,将数字输入到ASCII编码转换网站上,进行验证。
验证了前三位,再随机选取几个有符号数输入进行验证:
这里解释一下,为什么会有“负数”,此负数为有符号数,需要转化成原码然后进行还原:
对应的Python代码为:
chr((int(~int(s.replace("-", '')) & 0xffff) + 1))
非有符号数可以直接使用
chr(int(s))
直接获取对应的 ASCII 字符。
原码,补码和反码的知识可以参考:
四.代码思路
针对加密参数,提出我的撰写代码思路。
五.源代码
Tingshubao_Spider.py
import requests
import re
from urllib.parse import urljoin
import urllib3
from lxml import etree
urllib3.disable_warnings()#解决warning
class Tingshu_bao_spider:
def do_get_request(self,url):
"""
发送网络请求,获取网页源代码
:param url:
:return:
"""
headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36",
"Referer":url}
try:
r=requests.get(url,headers=headers,timeout=6)
if r.status_code==200:
r.encoding=r.apparent_encoding
html=r.text
return html
else:
return False
except:
return False
def get_novel_detail(self,sound_link):
"""
获取小说详情
:param sound_link:
:return:
"""
novel_detail_item={}
html=self.do_get_request(sound_link)
if html:
res=etree.HTML(html)
name=res.xpath('//div[@class="book-cell"]/h1[@class="book-title"]/text()')
if name:
novel_detail_item['novel_name']=name[0].split("有声小说简介:")[0]
else:
novel_detail_item['novel_name']="未知"
cover=res.xpath('//div[@class="book"]/img[@class="book-cover"]/@src')
if cover:
novel_detail_item['novel_cover']=urljoin(sound_link,cover[0])
else:
novel_detail_item['novel_cover']="未知"
datas=res.xpath('//div[@class="book-rand-a"]//text()')
if datas:
novel_detail_item['novel_type'] = datas[1]
novel_detail_item['novel_status'] = datas[3]
novel_detail_item['novel_update_time'] = datas[-1]
else:
novel_detail_item['novel_type']="未知"
novel_detail_item['novel_status'] = "未知"
novel_detail_item['novel_update_time'] = "未知"
#作者
data2 = res.xpath('//div[@class="book-des"]/p/a/text()')
if data2:
novel_detail_item['novel_author'] = data2[0]
novel_detail_item['novel_anchor'] = data2[-1]
else:
novel_detail_item['novel_author']="未知"
novel_detail_item['novel_anchor']="未知"
introduce = res.xpath('//div[@class="book-des"]/text()')
if introduce:
novel_detail_item['novel_introduce'] = introduce[0]
else:
novel_detail_item['novel_introduce']="未知"
selector=res.xpath('//div[@id="playlist"]/ul/li')
play_list=[]
for data in selector:
play_item={}
novel_play_name=data.xpath("./a/@title")
if novel_play_name:
play_item["play_name"]=novel_play_name[0]
else:
play_item["play_name"]="NULL"
novel_play_link = data.xpath("./a/@href")
if novel_play_name:
play_item["play_link"] = urljoin(sound_link,novel_play_link[0])
else:
play_item["play_link"]="NULL"
play_list.append(play_item)
novel_detail_item['play_list']=play_list
return novel_detail_item
else:
return False
def get_audio_play_link(self,detail_intro_link):
"""
获取小说播放链接地址
:param detail_intro_link:
:return:
"""
html=self.do_get_request(detail_intro_link)
if html:
base_url="https://t3344t.tingchina.com/"
aim_asciis=re.findall("FonHen_JieMa\('(.*?)'",html)
if aim_asciis:
sp = aim_asciis[0].split("*")
res = ""
for s in sp:
if s != "":
if "-" in s:
res += chr((int(~int(s.replace("-", '')) & 0xffff) + 1))
else:
res += chr(int(s))
aim_suffix = "/" + res.split('&')[0].split('/', 1)[-1]
play_url=urljoin(base_url,aim_suffix)
return play_url
else:
return False
else:
return False
if __name__ == '__main__':
t=Tingshu_bao_spider()
aim_url='http://m.tingshubao.com/book/2267.html'
print(t.get_novel_detail(aim_url))
print(t.get_audio_play_link('http://m.tingshubao.com/video/?2267-0-0.html'))
六.结果
1.详情页
2.音频播放地址
有了真实播放地址,就能写代码,下载音频了。
七.总结
本次分析了一个有声小说网站,重点在于分析其小说详情页、音频播放地址,加密方式判断。思路、代码方面有什么不足欢迎各位大佬指正、批评!
Python3网络爬虫--爬取有声小说(附源码)的更多相关文章
- 如何利用Python网络爬虫爬取微信朋友圈动态--附代码(下)
前天给大家分享了如何利用Python网络爬虫爬取微信朋友圈数据的上篇(理论篇),今天给大家分享一下代码实现(实战篇),接着上篇往下继续深入. 一.代码实现 1.修改Scrapy项目中的items.py ...
- 2019-04-23-Python爬取有声小说
目录 Python爬取有声小说 摘要 1.获取下载链接 2.分析规律,循环爬取 3.保存到本地,批量命名 4.界面设计 5.效果展示 Python爬取有声小说 通过python爬取网站的资源,实现批量 ...
- 利用Python网络爬虫爬取学校官网十条标题
利用Python网络爬虫爬取学校官网十条标题 案例代码: # __author : "J" # date : 2018-03-06 # 导入需要用到的库文件 import urll ...
- 使用scrapy爬虫,爬取17k小说网的案例-方法一
无意间看到17小说网里面有一些小说小故事,于是决定用爬虫爬取下来自己看着玩,下图这个页面就是要爬取的来源. a 这个页面一共有125个标题,每个标题里面对应一个内容,如下图所示 下面直接看最核心spi ...
- 使用scrapy爬虫,爬取起点小说网的案例
爬取的页面为https://book.qidian.com/info/1010734492#Catalog 爬取的小说为凡人修仙之仙界篇,这边小说很不错. 正文的章节如下图所示 其中下面的章节为加密部 ...
- Jsoup-基于Java实现网络爬虫-爬取笔趣阁小说
注意!仅供学习交流使用,请勿用在歪门邪道的地方!技术只是工具!关键在于用途! 今天接触了一款有意思的框架,作用是网络爬虫,他可以像操作JS一样对网页内容进行提取 初体验Jsoup <!-- Ma ...
- 04 Python网络爬虫 <<爬取get/post请求的页面数据>>之requests模块
一. urllib库 urllib是Python自带的一个用于爬虫的库,其主要作用就是可以通过代码模拟浏览器发送请求.其常被用到的子模块在Python3中的为urllib.request和urllib ...
- 如何用Python网络爬虫爬取网易云音乐歌曲
今天小编带大家一起来利用Python爬取网易云音乐,分分钟将网站上的音乐down到本地. 跟着小编运行过代码的筒子们将网易云歌词抓取下来已经不再话下了,在抓取歌词的时候在函数中传入了歌手ID和歌曲名两 ...
- 使用scrapy爬虫,爬取17k小说网的案例-方法二
楼主准备爬取此页面的小说,此页面一共有125章 我们点击进去第一章和第一百二十五章发现了一个规律 我们看到此链接的 http://www.17k.com/chapter/271047/6336386 ...
- python网络爬虫&&爬取网易云音乐
#爬取网易云音乐 url="https://music.163.com/discover/toplist" #歌单连接地址 url2 = 'http://music.163.com ...
随机推荐
- js var
var x= new Number(); alert(x)//0 x=new Object(); alert(JSON.stringify(x)) //{} x=new Boolean(); aler ...
- 读取数组树下的某值,并返回其父级下的任何值 vue
1 // 遍历树 获取对应 id的项中的值 2 queryTree(tree, value) { 3 let stark = []; 4 stark = stark.concat(tree); 5 w ...
- chatGPT-meta抗衡版本
chatGPT-meta抗衡版本 链接:https://mp.weixin.qq.com/s/MbZTfVgxx221Eo9pl1h80w 内置 git代码 LLaMA 项目地址:https://gi ...
- 线上服务Java进程假死快速排查、分析
引用 https://zhuanlan.zhihu.com/p/529350757 最近我们有一台服务器上的Java进程总是在运行个两三天后就无法响应请求了,具体现象如下: 请求业务返回状态码502, ...
- MARKDEEP.js-一个轻松在HTML中输入MD代码的JavaScript库
MARKDEEP.js-一个轻松在HTML中输入MD代码的JavaScript库 http://casual-effects.com/markdeep/ 引入: <style class=&qu ...
- python多线程的问题
参考:https://stackoverflow.com/questions/20939299/does-python-support-multithreading-can-it-speed-up-e ...
- MulVAL攻击图的推理规则
MulVAL ( multihost, multistage, vulnerability analysis) 是由普林斯顿大学的 Ou 等开发的 Linux 平台开源攻击图生成工具,基于 Nessu ...
- Python用telnet设置,抓UDP抓采样点并显示
====main.bat==== echo off rem "d:\Program\WiresharkPortable64\App\Wireshark\tshark.exe" -- ...
- SqlSugar 代码生成 数据库及表
在实际开发中如何在sqlsugar中通过model生成数据表呢? 废话不说上代码 一.引入sqlsugarcore 二.编写Model代码 先写一个model举例 namespace 用户管理.Mod ...
- Uncaught ReferenceError: Vue is not defined(之一)
报错信息 Uncaught ReferenceError- Vue is not defined 报错代码示例 <body> <div id="app"> ...