爬虫遇到 js 动态数据时,主要解决方法有两种:
- 使用一些库,例如 Selenium,来模拟浏览器环境抓取数据。但这样做对内存和 CPU 的消耗都比较大,爬虫效率低,应尽量避免。
- 手动分析 js 请求
下面我选了一个漫画网站作为小例子,讲一下第二个方法。
https://manhua.sfacg.com/mh/YSJ/4519/
我们的目的是获取漫画图片 url,然后下载下来。
判断待爬数据是否 js 动态加载的
用 chrome 打开该网页,右键漫画图片 -> 检查
我们可以看到图片的 url 就在里面。可以右键此处(蓝色部分)-> copy -> copy xpath 获得图片对应的 xpath,然后可以使用 requests 和 xpath 获取图片 url。当然最后还是失败了。因为这里的图片是 js 动态加载出来的。
获取跟待爬数据有关的 js 代码信息
我们可以查看网页源代码,Ctrl+F 定位图片 id “curPic”:
可以看到,里面根本没有图片的 url,图片是 js 加载的。阅读里面的 js 代码,我们可以知道图片 url 是由下面这行代码决定的:
1 | pic2.src = hosts[getHost()] + picAy[curIndex] |
在源码中寻找 hosts
和 picAy
,发现它们只在这里出现过。这说明这两个数组可能是由 js 代码加载的。
寻找跟待爬数据有关的 js 请求
回到漫画那个页面,我们打开 Chrome 的 F12,点击 network,勾选 js,刷新网页,查看相关 js 请求对应的 preview,看看哪些包含 hosts
和 picAy
:
额,这进展还是出乎意料的顺利,第一个 js 就有我们想要寻找的内容了。我们可以看到,这一话漫画的所有图片都在这个 js 请求的响应内容里了。由此图可知,我们进入某一话漫画的第一页时,就有一份 js 代码请求了这一话漫画所有页的图片 url。那么,我们在写程序的时候,该如何得到这份 js 的文件名?
观察其他漫画的情况,我们可以发现,虽然这份 js 代码的命名没啥规律,不过在网页源代码中,它一般是处于第一个 js 的位置。
总结
至此,总结一下如何下载该网站漫画:
- 获取一话漫画的第一页 url
- 获取该 url 响应的 html
- 在 html 中寻找第一个 js 代码文件名
- 获取该 js 的响应内容,从中提取所有图片 url
总结一下该例子中获取 js 动态数据的思路:
- 判断是不是 js 加载的数据
- 如果是 js 加载的,查看网页源代码中待下载数据附近的 js 代码,获取关键信息(比如一些变量名)
- 回到待爬网页那里,按 F12(我用的 Chrome),点击 network,勾选 js,刷新网页,获取 js 请求
- 逐个查看每个请求的 preview,看有没有跟待爬取内容相关的信息。