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(媒體)。
在這里插入圖片描述
通過篩選,發現此音頻真實播放地址為:

https://t3344t.tingchina.com/yousheng/%E7%8E%84%E5%B9%BB%E5%A5%87%E5%B9%BB/%E6%96%97%E7%BD%97%E5%A4%A7%E9%99%863%E9%BE%99%E7%8E%8B%E4%BC%A0%E8%AF%B4_%E8%B5%9E%E6%89%AC/0001.mp3?key=e3f84d5d80bd806ae8b954cbf601978d_693500777

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.音頻播放地址

在這里插入圖片描述
有了真實播放地址,就能寫代碼,下載音頻了。

七.總結

本次分析了一個有聲小說網站,重點在於分析其小說詳情頁、音頻播放地址,加密方式判斷。思路、代碼方面有什么不足歡迎各位大佬指正、批評!
請添加圖片描述


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM