前言
動态頁面相對于靜态頁面的解析來說,更加簡單直接,因為動态頁面傳回的ajax資料基本都是json格式或者經過去頭或者去尾變成json,根本不需要依賴BeautifulSoup,如下為需要處理的json:
隻要找到請求的規律,後續就會水到渠成
分析請求
本次依然以上篇文章中提到的網站為例,該網站可以點選"全文閱讀"實作滾動滑鼠閱讀,很明顯是動态加在的,不廢話,打開小說頁面,點選全文閱讀
按下F12,點選Network,過濾設定為XHR,滑鼠往下滾動,攔截到:
點選Response,可以看到傳回的是标準json資料:
可以看到,傳回的json資料中,章節名為
response['data']['chapterName']
,文章内容為
response['data']['content']
,但是文章内容中帶有p标簽,簡單,用re正則去掉!
文章内容解析成功了,如何請求下一章的内容呢?
我們翻回來看一下攔截的Headers,往下翻,可以看到ajax請求的參數:
再結合網頁的網址http://xxx.com/chapter/898410/58676024.html
你會發現bookId就在網址上:
url.split('/')[-2]
,那
chapterId
呢?此時再連續翻兩章,攔截兩個包來對比一下,有心的你就會發現,上一章攔截的
response['data']['nexCid']
為下一章Headers請求參數裡面的
chapterId
,好,下一章的
chapterId
也知道了,那
_:1578574655825
這個是個啥呢?對,經驗告訴我們這個參數很可能是時間戳,格式化一下看看!
嗯,的确是時間戳了!
那如何判斷最後一章呢,從倒數第二章開始全文閱讀,拉到最後,攔截請求,可以看到,最後的**
response['data']['nexCid']
值為0,就把它作為循環結束的條件。
實作
至此,邏輯非常清楚了:
章節名:
response['data']['chapterName']
文章内容:
response['data']['nexCid']
下一章請求頭的chapterId:
response['data']['nexCid']
剩下的就是實作了:
import requests
import os
import re
import time
import json
def spiderBookdynamic(url: str):
nexCid = url.split('/')[-1].replace('.html', '')
bookid = url.split('/')[-2]
path = 'E:/Ebooks2/' + bookid
if not os.path.exists(path):
os.makedirs(path)
pathAllinOne: str = path + '/' + bookid + '(合并).txt'
while True:
# 13位時間戳
timestamp = int(round(time.time() * 1000))
# 構造ajax頭
url = 'http://book.zongheng.com/api/chapter/chapterinfo'
params = {
'bookId': bookid,
'chapterId': nexCid,
'_': timestamp
}
res = requests.get(url, params=params)
res.encoding = 'utf-8'
response = json.loads(res.text)
chaptername = '\n' + response['data']['chapterName']+ '\n\n\n'
content = chaptername + '\n'.join(re.findall('<p>(.*?)</p>', response['data']['content'], re.S))
nexCid = response['data']['nexCid']
# 寫入章節
with open(path + '/' + chaptername.strip() + '.txt', 'w') as f:
f.write(content)
print("已儲存章節:" + chaptername.strip())
# 寫入合并
with open(pathAllinOne, 'a') as f:
f.write(content)
# 最後一章
if nexCid == 0:
return
if __name__ == '__main__':
url = 'http://xxx.com/chapter/898410/58676024.html'
spiderBookdynamic(url)