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