动态页面相对于静态页面的解析来说,更加简单直接,因为动态页面返回的ajax数据基本都是json格式或者经过去头或者去尾变成json,根本不需要依赖BeautifulSoup,如下为需要处理的json:
jQuery110208565583287844201_1578312396626({
"tag": "全部","ptagOneCount": "10","xxx":"yyy" })
只要找到请求的规律,后续就会水到渠成
本次依然以上篇文章中提到的网站为例,该网站可以点击"全文阅读"实现滚动鼠标阅读,很明显是动态加在的,不废话,打开小说页面,点击全文阅读
按下F12,点击Network,过滤设置为XHR,鼠标往下滚动,拦截到:
点击Response,可以看到返回的是标准json数据:
可以看到,返回的json数据中,章节名为response['data']['chapterName']
,文章内容为response['data']['content']
,但是文章内容中带有p标签,简单,用re正则去掉!
re.findall('<p>(.*?)</p>', response['data']['content'], re.S)
文章内容解析成功了,如何请求下一章的内容呢?
我们翻回来看一下拦截的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)
卸载命令:sudo yum remove code联网状态下安装命令1, sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc2 ,sudo sh -c 'echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.mic...
有的时候在公司,我们连接上了一个共享文件夹,一般是IT帮忙设置的,我们并不知道用户名和密码,但是一旦断开想要重新连接,找IT总是麻烦。下面一个工具就可以很好的解决这个问题。下载:注意,微软默认的杀毒软件会阻止打开次文件,临时关闭即可。Recover lost Windows 10/7/8/Vista/XP network passwords (Credentials file)...
学会解决问题的能力,我们才能够
问题描述:请编写程序,实现以下功能:在字符串中的所有数字字符前加一个$字符。例如,输入 A1B23CD45,输出 A$1B$2$3CD$4$5。一个哥们的解法是:用串S拷贝出另一个串T,对串T从头至尾扫描,对非数字字符原样写入串S,对于数字字符先写一个$符号再写该数字字符,最后,在S串尾加结束标志。使用此方法是牺牲空间,赢得时间。代码如下:#include &lt;stdio.h&g...
Hana 或者其他数据库原生的数据库连接池实现。
.husky:husky是一个为git客户端增加hook的工具.vscodebiuld:vite的配置,项目打包时候的配置mock:mock数据node_modules:node的一些基础依赖包,可能还有拓展的安装的别的插件publicsrc:项目的主文件夹 assets:资源文件 components:vue组件 componens 下的**.vue文件就可以具体编写每一个vue, 最后通过router-link 连接给定的path路径,可以调用vue对象 ...
&lt;iframe name="google_ads_frame" marginwidth="0" marginheight="0" src="http://pagead2.googlesyndication.com/pagead/ads?client=ca-pub-5572165936844014&amp;amp;dt=1204028028375&amp;amp;lmt=1203788092&...
近期项目涉及到IM功能,使用到一个好用的支持WebSocket的IM开源框架:Socket.IO;它是一个完全由JavaScript实现、基于Node.js、支持WebSocket的协议用于实时通信、跨平台的开源框架,它包括了客户端的JavaScript和服务器端的Node.js。Socket.IO除了支持WebSocket通讯协议外,还支持许多种轮询(Polling)机制以及其它实时通信方...
package org.pcl;import java.util.Scanner;/** * 用户输入一个整数,程序输出该数的二进制 * * @version 1.0 2014-05-05 * @author yifan */public class OutBinary { public static void main(String[] args) { Scann
原文地址:一位用贞操换取欲望的仙女作者:游文意 为了唐僧这块肉,白骨精攻了三次。第一次,好妖精,停下阴风,在那山凹里,摇身一变,变做个月貌花容的女儿,说不尽那眉清目秀,齿白唇红,左手提着一个青砂罐儿,右手提着一个绿磁瓶儿,从西向东,径奔唐僧。 只见那行者自南山顶上,摘了几个桃子,托着钵盂,一筋斗,点将回来。睁火眼金睛观看,认得那女子是个妖精,放下钵盂,掣铁棒,望妖精劈脸一下。那
在网上照着大神的博客用CityScapes的数据集训练deeplab V3+的时候,一步一步照着别人的方法弄,弄到生成tfrecord的时候突然报错:Failed to find all Cityscapes modules。这个错误是从csHelpers.py里面报出来的就是因为from annotation import Annotation这个语句出错,才报的Failed to fi...
想把hadoop102机器上的环境变量分发给hadoop103和hadoop104,xsync /etc/profile.d/my_env.sh,这里的xsync是自己的分发脚本#!/bin/bash#1. 判断参数个数if [ $# -lt 1 ]then echo Not Enough Arguement! exit;fi#2. 遍历集群所有机器for host in hadoop102 hadoop103 hadoop104do echo =========== $host