目标站点 有声小说-有声读物-电台广播在线听书-蜻蜓FM

python爬虫实战搞的是PC端,移动端可能有更加方便的接口,欢迎大家留意讨论反正是练手就随便抓一下pc端的包好了

主要内容
  • 1.post请求登录
  • 2.hmacMD5算法的简单使用

这个例子的登录非常简单没有任何加密直接post就行真的是一点加密和未知参数都没有

python实现,注意此处是类的一个方法不完整无法直接运行
def login(self,user_id,password):data = {'account_type': '5','device_id': 'web','user_id': user_id,'password': password}response = self.session.post(self.login_url,data=data)if response.status_code==200:temp = response.json()errorno = temp['errorno']errormsg = temp['errormsg']if errorno == 0:print('login successful!','登录成功!')data = temp['data']self.qingting_id = data['qingting_id']self.access_token = data['access_token']else:print('Login failed','登录失败')print(errormsg)

录成功后我们把access_token和qingting_id拿到,相当于一个登录后的标志如果账号是会员相当于一个会员标志

音频的真实地址请求了这样一个url:
https://audio.qingting.fm/audiostream/redirect/294280/11604885

其中294280是专辑id,

11604885是当前音频的id
其中还带了一些参数比如access_token,qingting_id(登录成功的response中有,上图没有登录所有是空的),另外还有一些比如t是时间戳,

device_id=MOBILESITE(不变)

关键就在于sign(尝试过不加sign会返回一个签名错误)

 

可以通过全局搜索试一下是哪个js生成的这个sign我全局搜索了一下

device_id

mian.一大堆.js 找到了生成sign的函数(需要自己分辨一下是一个device_id: "MOBILESITE"的)

搜索其他关键字应该也是可以顺利找到的
这里的sign是u这个变量它是由c这个变量通过一堆加密处理得到的

我们可以控制台输出一下u和c
所以我们就知道了sign实际是加密了请求的其他参数

一开始我误以为是单纯的MD5所以卡了好久(还进入函数内部看他具体是怎么实现的看的一头雾水)

其实代码已经告诉用的是

createHmac("md5", "fpMn12&38f_2e")
查了下Hmac发现就是一种现成的算法,还有不同的模式MD5是其中一种,需要一个秘钥

这里什么都告诉你了,用Hmac-md5秘钥是fpMn12&38f_2e

找个在线加密的网站试了下,果然和刚才控制台输出的一样
python的话需要import

hmac这个库
import hmac
import timebase_url = "https://audio.qingting.fm"
bookid = "294280"
id = "11590788"
access_token = ""
qingting_id =""
timestamp = str(round(time.time()*1000))
data = f"/audiostream/redirect/{bookid}/{id}?access_token={access_token}&device_id=MOBILESITE&qingting_id={qingting_id}&t={timestamp}"
message = data.encode('utf-8')
key = "fpMn12&38f_2e".encode('utf-8')
sign = hmac.new(key, message, digestmod='MD5').hexdigest()
whole_url = base_url+data+"&sign="+sign
print(whole_url)
得到一个音频可以做到了剩下的就是得到一堆了,其实我们得到每个音频的id就可以了

 

我请求的是这个接口
info_api = 'https://i.qingting.fm/capi/channel/{self.bookid}/programs/{self.version}?curpage={str(page)}&pagesize=30&order=asc'

version在声书主页的源代码中,只要改curpage就可以翻页了
完整源码
import requests
import re
import hmac
import time
from tqdm import tqdm
from bs4 import BeautifulSoup
import os
import json
import sys
import urllib3
urllib3.disable_warnings()class QingTing():def __init__(self,user_id,password,bookurl,ifLogin):self.ifLogin = ifLoginself.user_id = user_idself.password = passwordself.session = requests.session()    self.session.headers.update({'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36'})self.login_url = "https://u2.qingting.fm/u2/api/v4/user/login"self.qingting_id = ''self.access_token = ''self.bookurl = bookurl# self.bookurl = 'https://www.qingting.fm/channels/257790'self.bookid = self.bookurl.split('/')[-1]self.version = ''self.qingtinghost = 'https://audio.qingting.fm'self.save_path = ''self.bookname = ''def login(self,user_id,password):data = {'account_type': '5','device_id': 'web','user_id': user_id,'password': password}response = self.session.post(self.login_url,data=data,verify=False)if response.status_code==200:temp = response.json()errorno = temp['errorno']errormsg = temp['errormsg']if errorno == 0:print('login successful!','登录成功!')data = temp['data']self.qingting_id = data['qingting_id']self.access_token = data['access_token']else:print('Login failed','登录失败')print(errormsg)time.sleep(10)sys.exit(0)def __get_version(self):response =  self.session.get(url=self.bookurl,verify=False)if response.status_code==200:soup = BeautifulSoup(response.text,'lxml')temp_bookname = soup.select('div.album-info-root > div.top > div.info.right > h1')[0].stringreplaced_pattern = '[\\\/:\*\?\"<>|]'self.bookname = re.sub(replaced_pattern,' ',temp_bookname,flags=re.M +re.S)if not os.path.exists(self.bookname):os.makedirs(self.bookname)matched = re.search('\"version\":\"(\w+)"',response.text,re.S)if matched:version = matched.group(1)self.version = version# return versiondef __get_total_page(self):self.__get_version()page = 1info_api = f'https://i.qingting.fm/capi/channel/{self.bookid}/programs/{self.version}?curpage={str(page)}&pagesize=30&order=asc'response =  self.session.get(info_api,verify=False)if response.status_code==200:temp =  response.json()total = temp['data']['total']total_page = int(int(total)/30)+1return total,total_pagedef get_book_info(self):total,total_page = self.__get_total_page()print(self.bookname,'共{}集'.format(total))for page in range(1,total_page+1):info_api = f'https://i.qingting.fm/capi/channel/{self.bookid}/programs/{self.version}?curpage={str(page)}&pagesize=30&order=asc'response =  self.session.get(info_api,verify=False)programs = response.json()['data']['programs']for program in programs:# print(program['id'],program['title'])yield programdef get_src(self,id):bookid = self.bookidaccess_token = self.access_tokenqingting_id =self.qingting_idtimestamp = str(round(time.time()*1000))data = f"/audiostream/redirect/{bookid}/{id}?access_token={access_token}&device_id=MOBILESITE&qingting_id={qingting_id}&t={timestamp}"message = data.encode('utf-8')key = "fpMn12&38f_2e".encode('utf-8')sign = hmac.new(key, message, digestmod='MD5').hexdigest()whole_url = self.qingtinghost+data+"&sign="+signreturn whole_urldef downloadFILE(self,url,name):resp = self.session.get(url=url,stream=True,verify=False)if resp.headers['Content-Type'] =='audio/mpeg':content_size = int(int(resp.headers['Content-Length'])/1024)with open(name, "wb") as f:print("Pkg total size is:",content_size,'k,start...')for data in tqdm(iterable=resp.iter_content(1024),total=content_size,unit='k',desc=name):f.write(data)print(name , "download finished!")else:errorno = resp.json()['errorno']errormsg = resp.json()['errormsg']print('没有权限下载,请登录已购此音频的账号。')print('errorno:',errorno,errormsg)def run(self):if self.ifLogin:self.login(self.user_id,self.password)programs =  self.get_book_info()count = 0for program in programs:count+=1try:id = program['id']title = str(count).zfill(4)+' '+program['title']+'.m4a'if not self.bookname =='':title = os.path.join(self.bookname,title)whole_url =  self.get_src(id)self.downloadFILE(whole_url,title)except Exception as e:print(e)with open('log.txt','a',encoding='utf-8') as f:f.write(str(count)+str(e)+'\n')def get_config_info():with open('config.json','r',encoding='utf-8') as f:config = json.loads(f.read())return configif __name__ == "__main__":# pyinstaller -F -i ico.ico QingTingFM.pyconfig = get_config_info()if config["ifLogin"]:bookurl = input('请输入要下载音频的主页链接:(如[url=https://www.qingting.fm/channels/257790]https://www.qingting.fm/channels/257790[/url])')isvalid = re.search('https://www.qingting.fm/channels/\d+',bookurl)if isvalid:q  = QingTing(config["user_id"],config["password"],bookurl,1)q.run()else:print("输入的主页格式错误")else:# 不登录bookurl = input('请输入要下载音频的主页链接:(如[url=https://www.qingting.fm/channels/257790]https://www.qingting.fm/channels/257790[/url])')isvalid = re.search('https://www.qingting.fm/channels/\d+',bookurl)if isvalid:q  = QingTing(config["user_id"],config["password"],bookurl,0)q.run()else:print("输入的主页格式错误")

配置文件部分
{   "ifLogin":1,"user_id":"135########","password":"pwd########"
}

源码下载
https://www.lanzoux.com/i2xT2g85tmf

Python 蜻蜓fm有声书批量下载 支持账号登录 原创源码相关推荐

  1. python+selenium爬取蜻蜓FM有声小说链接

    爬取蜻蜓FM有声小说链接 1 为什么说是链接而不是音频呢? 原因是我只是一个刚开始学习的小白,因为这个是动态加载的数据,我还不会提取这个Network中的链接,写这个只是为了记录学习过程, 由于是第一 ...

  2. 如何使用python批量下载-用Python调用迅雷实现后台批量下载

    迅雷9.10实测可用,老版本迅雷应该也可以用,不推荐迅雷极速版 写在前面 最近在学习python的网络爬虫,想要爬取某个网站上的上百万条链接,批量下载链接所指向的图片.文档.视频等内容.大部分的小文件 ...

  3. python webdriver save_Python + Selenium +Chrome 批量下载网页代码修改【新手必学】

    Python + Selenium +Chrome 批量下载网页代码修改 主要修改以下代码可以调用 本地的 user-agent.txt 和 cookie.txt 来达到在登陆状态下 批量打开并下载网 ...

  4. 【Python】利用Python爬虫实现网页图片批量下载

    本文爬取的是豆瓣的网站,爬虫有规则,爬虫需谨慎.文章末附效果图 源码下载地址:https://github.com/Seichung/Python/blob/master/Python_Practic ...

  5. 用Python调用迅雷实现后台批量下载

    迅雷9.10实测可用,老版本迅雷应该也可以用,不推荐迅雷极速版 写在前面 最近在学习python的网络爬虫,想要爬取某个网站上的上百万条链接,批量下载链接所指向的图片.文档.视频等内容.大部分的小文件 ...

  6. 豆瓣FM加心音乐批量下载

    如何批量下载豆瓣电台加红心歌曲 注:批量从豆瓣电台抓取歌曲列表的功能(来自@牛牛 微博) 1.登陆豆瓣电台 2.进入加红星的网页或者输入网址http://douban.fm/mine?type=lik ...

  7. 用python脚本实现JRA-55数据批量下载

    今天开完组会,小小放松一下哈哈,更新一下许久没更新的CSDN(登陆太少,好多私信和评论都没回复,尴尬哈哈) 我之前下载JRA-55的monthly数据,上ftp用手点!用手点!!![破音] 太惨了,简 ...

  8. 【Python开发】ComicDownloader(漫画批量下载)

    ComicDownloader(漫画批量下载) 自制漫画批量下载工具 点击下载 使用步骤: 搜索关键字. 选中搜索结果. 选择下载章节,下载. 等待下载完成. 支持 manhuadb.com hhim ...

  9. 使用python实现高清壁纸批量下载

    一.高清壁纸批量下载 1.概述 此代码是使用python多线程批量下载高清壁纸的一个小脚本,代码略为简陋. 此代码仅供学习与交流,请不要用于违法用途. import requests from lxm ...

最新文章

  1. 1000+ 常用 Python 库一览
  2. 网络与服务器编程框架库 acl_3.0.13 发布
  3. php 获取搜狗微信 sn,PHP 获取百度和搜狗收录量 代码 可用于EMLOG
  4. spring boot 热更新,热部署
  5. PHP文件函数 记录日志功能
  6. 数据结构 【实验7 二叉树基本操作】
  7. html 模板配置,模板文件配置
  8. mysql高并发不用事务_Mysql高并发加锁事务处理
  9. MySQL数据库主键与外键
  10. Epub,Mobi,Azw3电子书格式的区别,有什么好用的安卓epub阅读器
  11. jeesit1.27使用(2)-图片处理
  12. 小尺寸笔记本将走向何方 — X280 长测
  13. 关于彻底卸载手心输入法的终极操作
  14. C# Win10缩放导致Winform字体模糊的解决方法
  15. 邮件助手工具哪个好用?哪个企业群发邮件的软件好用?
  16. 泛微OA流程明细表取值并校验
  17. Linux基础:破解root密码(rd.break)
  18. 2110449-02-8,2110449-02-8巯基反应性PEG
  19. 设计模式之设配器模式、外观模式
  20. SAP创建供应商及采购订单

热门文章

  1. 轻触开源(二)-Gson项目源码解析_壹
  2. 中国工程师最喜欢的10大TWS耳机电源管理芯片,钰泰ETA9084名列其中
  3. openresty出现socket read/write busy的原因及解决方法
  4. 电位器和编码器的区别
  5. selenium 火狐下载弹框去除
  6. Linux服务器域名配置
  7. 58——FFA-Net: Feature Fusion Attention Network for Single Image Dehazing
  8. 我的世界java版复仇双持_我的世界战备双持2mod整合包
  9. Java分布式跟踪系统Zipkin(五):Brave源码分析-Brave和SpringMVC整合
  10. c语言spawning c1.exe,在VC++6.0中,总是出现一个叫error spawning c1.exe的错误,怎么回事?...