油猴脚本记(含检测)

写脚本

模拟爬取市面上网站(淘宝、京东、美团等)的页面内容

油猴脚本是通过JS来编写,我也才接触只是对dom进行操作来完成

  1. 首先是@match需要设置,就是用来说明脚本在哪个页面执行
  2. 接下来就是写脚本,主要思路是
    • 页面分为列表页,从列表页可以进入详情页。那么脚本就设置在列表页进行
    • 为了直观显示,将在列表页创建一个iframe用来显示爬取的详情页
    • 模拟用户去点击每一个商品操作,这样子做轮询
  3. 实现
    • 列表页:获取当前的页面,获取商品数,获取每个商品的链接
    • 创建iframe,加载商品的链接
    • 两个函数做递归,在加载第二个商品时候需要将第一个iframe删除
// ==UserScript==
// @name         (自定义随意)
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        (模板https://xxx.com/xxx/*)来匹配需要之行脚本的页面
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    var content = document.getElementsByClassName("info--wrap"); //获取当前页面的所有商品
    var nowIndex=0;//起始页数
    var page=document.getElementsByTagName("strong")[1].innerText;//当前页
    
    var ScrapyFunc=function(o){
        var iframeDocument=o.contentDocument; //对iframe进行dom操作
        console.log(nowIndex);
        //var title = iframeDocument.getElementsByClassName("info-basic__right");
        //console.log(title[0].innerText);
        setTimeout(function(){LoopFunc()},3000);

    };
    var LoopFunc=function(){
        if(nowIndex>=content.length){
            page++;
            window.location.replace('https://bj.58.com/ershouche/pn'+page+'/');//加载到下一页
        }
        var url = content[nowIndex++].innerHTML.split('"')[3];
        console.log(url);
        var now_car_info_i = document.getElementsByClassName("cariframe");
        if(now_car_info_i.length != 0)now_car_info_i[0].parentNode.removeChild(now_car_info_i[0]); //调用父删除iframe

        var iframe = document.createElement("iframe"); //创建iframe
        iframe.src = url;
        iframe.className = 'cariframe';
        iframe.height="300";
        iframe.width="1280";

        if (iframe.attachEvent){  //判断iframe是否加载完成
            iframe.attachEvent("onload",function(){ScrapyFunc(iframe)});
        } else {
            iframe.onload =function(){ScrapyFunc(iframe)};
        }
        
        document.body.insertBefore(iframe, document.body.children[0]); //将iframe放在页面顶端
    };
    LoopFunc();

})();

踩坑

  1. 如果页面是https,那么iframe也必须是https,如果iframe是http那么需要从浏览器中去单独的设置,否则浏览器是会报错无法显示frame内容

  2. 使用setTimeout()函数达到延迟效果,有时由于网络问题页面还没有加载完成,这是如果进行了dom操作会报错,所以可以进行短暂的延时让页面加载一会。setTimeout()直接使用可能不生效需要下成如下样式:

    setTimeout(function(){xxxxxxxxxxx},3000);

检测脚本

脚本的运行原理

油猴脚本是在沙盒里执行用户脚本,不会对网页注入script元素,它通过沙盒向网页中传递信息以达到控制dom的操作。所以如果要对脚本进行检测,没有像上面代码这样子向页面中植入iframe的话,通过去检测dom和window是无法检测出使用油猴脚本的。

检测方法一

通过鼠标点击事件检测,正常的用户使用鼠标点击按钮会有一个坐标,但是动过click()函数进行的点击操作是没有坐标的。所以可以通过这个方式做简单的验证,测试一下

//点击事件的坐标
document.addEventListener('click',(e)=>{console.log(e.clientX,e.clientY)})
  • 正常鼠标点击

    油猴脚本

  • 使用click()进行点击

    油猴脚本

检测方法二

使用isTrusted事件进行识别,这个事件可以判断是否是人进行点击或者是js模拟点击,当是手动点击会返回true,否则会返回false

Js代码如下:

document.querySelector("#bt").addEventListener("click",
	function(event) {
   		console.log('被点击,isTrusted值为:');
    	console.log(event.isTrusted);
	});

测试

油猴脚本

对于油猴脚本的检测难度是比较大的,但应该还是有其他的办法,后续也会对其进行研究。同时也可以通过用户的行为等方式来辅助的进行判断,因为人工去点击和脚本去执行操作还是有很大的不同。

Q.E.D.