目录
1、目标内容
目标网站为某彩票网站;获取每一期的 开奖日期 和 开奖号码,整理数据为 表格 格式,再导出为 Excel 表格。
一页的内容有55 - 26 + 1 = 30项数据,计划获取五页的数据。
2、观察网页结构
开奖日期的文档结构可以使用 tbody > tr > 第二个 childNode 来获取到;
中奖号码(每个中奖数字)可以使用 .qiu > .qiu-item-small 依次得到;
观察页面底部下一页的事件处理。
发现点击某页或者点击下一页时,不改变地址路径,而是执行一段js代码重新渲染表格的内容。则此时为了获取各个页面的数据,可以获取到指定页的元素或下一页的原,然后构造触发点击事件,就能达到效果。
这里使用获取下一页的元素,然后依次构造并触发点击事件以获取到连续几页的数据内容。
3、在浏览器控制台实现数据的爬取和下载
// 引入alasql,可以用于数据处理,数据导出为Excel
let alasqlScript = document.createElement('script');
alasqlScript.src = "https://cdn.jsdelivr.net/npm/alasql@4.0.0/dist/alasql.min.js";
document.body.appendChild(alasqlScript);
// 存放最终的数据
let resultArr = [];
// 主要执行函数,当前页,总共需要多少页,回调函数(导出数据)
function action(currentPage, needPage, callback){
boxArr = document.querySelectorAll('tbody .qiu');
line = document.querySelectorAll("tbody tr");
for(let i = 0 ; i < boxArr.length ; i ++){
let item = boxArr[i];
// 构造单行数据对象
let obj = {
time:line[i].childNodes[1].innerText,
ball_1:boxArr[i].childNodes[0].innerText,
ball_2:boxArr[i].childNodes[1].innerText,
ball_3:boxArr[i].childNodes[2].innerText,
ball_4:boxArr[i].childNodes[3].innerText,
ball_5:boxArr[i].childNodes[4].innerText,
ball_6:boxArr[i].childNodes[5].innerText,
ball_7:boxArr[i].childNodes[6].innerText,
}
resultArr.push(obj);
};
// 没有达到所需的数据数量要求,继续获取数据
if(needPage > currentPage){
// 自动触发点击事件,返回下一页的数据
document.querySelector('.layui-laypage-next').click();
// 等页面加载完后,在收集数据,放置页面加载过慢,数据没有回来或回来的是旧的数据
setTimeout(()=>{
action(currentPage + 1, needPage, callback);
},100);
}else{
// 执行回调函数导出数据
callback();
}
}
// 获取 5 页的数据
action(0, 4, ()=>{
// 将resultArr中的数据输出成表格xls,表格名称为ballData.xls
alasql('select * into XLS("ballData.xls",{headers:true}) from ?',[resultArr]);
})
点击执行代码,将弹窗表格下载的目标地址,选择位置进行存放。
打开表格文件并信任该表格的内容。
4、禁止加载外部脚本文件(CSP)
回顾上面在浏览器控制台抓取网页数据并保存到本地的方式,一个关键的部分是加载了外部的JS文件,即导入了 alasql 这个库来帮助我们把数据整理并保存到本地。
当然,也可以不引入其他的库,拿到最终的 resultData 后,直接在控制台输出,然后手动地复制黏贴到本地的文件中。不过这样也可能会比较繁琐。
如何禁止用户在控制台引入外部的脚步文件来限制用户的自由?可以在网站中配置CSP(内容安全策略)来实现。
CSP
的实质就是白名单制度,开发者明确告诉客户端,哪些外部资源可以加载和执行。它的实现和执行全部由浏览器完成,开发者只需提供配置。
配置CSP有两种方式,一种是通过通过响应头设置 Content-Security-Policy
的方式,另一种是在网页的 meta 标签中进行配置,两种方法是等效的。
对于第一种,设置响应头的方式(如 Nginx 配置,后端返回的响应头配置等):
// 只能加载当前域名的js文件,不信任任何的插件资源
Content-Security-Policy: script-src 'self'; object-src 'none';
对于第二种,是前端在开发网页时进行的配置。
// 只允许加载当前域名下的脚步文件,运行加载任何图片资源
// default-src 设置各个配置选项的默认值, * 为允许任何资源,该配置的优先级最低
<meta http-equiv="Content-Security-Policy" content="default-src *; script-src 'self'; img-src *;">
手动为该网站设置<meta>标签,并配置 CSP 策略,然后再与控制台中进行简单尝试:
let meta = document.createElement('meta');
meta.httpEquiv = "Content-Security-Policy";
meta.content = `default-src 'self';script-src 'self';object-src 'none';`;
document.head.appendChild(meta);
let alasqlScript = document.createElement('script');
alasqlScript.src = "https://cdn.jsdelivr.net/npm/alasql@4.0.0/dist/alasql.min.js";
document.body.appendChild(alasqlScript);
alasql;
5、关于CSP更多的内容 参考:
[1] HTTP中的CSP ( Content Security Policy )内容安全策略 - 掘金
[2] Web内容安全策略浅析 - 知乎