另类爬虫工具-犀利的devtools

471 阅读3分钟

一、封不了的爬虫

做过爬虫的童鞋可能大多数是用python去模拟请求爬数据的,有些封IP的网站数据,可能是去页面上爬的demo,这种效率太低,今天让我们借用devtools,去高效的爬数据,本篇技术需要你熟悉谷歌插件的开发,这里我就不赘述了,不了解的可以参考这个:www.cnblogs.com/liuxianan/p…

二、起步配置谷歌插件

我的目录结构如下:

WX20220217-160657.png

分别介绍下功能吧!

manifest.js 插件核心配置

background.html 背景页面,运行在浏览器上

popup.html 点击浏览器上的插件图标弹出的页面

devtools.html devtools页面,我们使用的vue-devtools也是这个

他们分别对应自己的js,这里同样可以引入jquery.js,下面我贴上manifest.js的配置,可参考修改

{
	"manifest_version": 2,
	"name": "lykj",
	"version": "1.0.0",
	"description": "补充浏览器功能",
	"icons":
	{
		"16": "img/w6.png",
		"48": "img/w6.png",
		"128": "img/w6.png"
	},
	"background":
	{
		"page": "background.html"
	},
	"browser_action": 
	{
		"default_icon": "img/w6.png",
		"default_title": "谷歌插件",
		"default_popup": "popup.html"
	},
	"content_scripts": 
	[
		{
			"matches": ["<all_urls>"],
			"js": ["js/jquery.js","js/content_script.js"],
			"run_at": "document_start"
		}
		
	],
	"permissions":
	[
		"cookies",
		"contextMenus", 
		"tabs", 
		"<all_urls>",
		"notifications",
		"webRequest", 
		"webRequestBlocking", 
		"storage", 
		"http://*/*", 
		"https://*/*" 
	],
	"omnibox": { "keyword" : "go" },
	"default_locale": "zh_CN",
	"devtools_page": "devtools.html"
}

三、开始搞数据

配置好我们的插件后,首先我们需要明确下功能怎么开发,我这里画了个简单的图

WX20220217-164516.png 大体流程是我们需要在content_script.js里面先与服务器交互获取我们想要打开的页面并且植入cookie信息,模拟登录,然后通信给background.js中,去操作打开页面,关闭页面,同时我们需要在content_script.js中配置一些信息,因为可以我们需要模拟点击实现接口调用,再有devtools拦截,上报数据。

核心代码: content_script.js


// 请求接口的url
const url = 'xxxxx'
let number = 0
let timer = null
let getClose = false;
window.onload=function(){
    // 获取url上的信息
    let history=window.location.href.split('?')[1];
    let nowRouter =window.location.href.split('?')[0];
    let query={
        awemeId: '', 
        roomId: ''
    }; 
    if(history&&history.length>0){
        history.split('&').forEach(function(item){
            let obj=item.split('=')
            query[obj[0]]=obj[1]
        })
    }
    // 获取#号后面挂载的参数
    let therePage = history.split('#')[1];
    // 在登录页面统一操作打开逻辑
    if(nowRouter==='xxx'){
        // 发起ajax请求获取cookie信息并且将cookie信息注入到当前域名实现登录
        $.ajax ({
            url:url+'xxxxxxx',
            type: 'get',
            data: {},
            dataType:'json',
            success: function(result){
                // 向background通信
                chrome.runtime.sendMessage({
                    action:"cookie",
                    content:result.data,
                    awemeId:query.awemeId,
                    roomId:query.roomId,
                })
            },
            error:function(error){
                console.log(error)
            }
        })
    }
    // 挂载页面Js
    if(nowRouter==='https://baidu.com'){
        if(therePage){
            switch (therePage) {
                case 'data1':
                    setTimeout(()=>{
                        handleDemo.f()
                    },2000)
                    break;
                case 'data2':
                    setTimeout(()=>{
                        handleDemo.g()
                    },2000)
                    break;
                default:
                    break;
            }
        }
    }
    
}

bakground.js

const url = 'xxxxx'
let createTabOpthon={};
let httplist=[];
let awemeId='';
let roomId='';
$("#open").click(function(){
    chrome.tabs.create({url : 'https://www.baidu.com'})
})
// 提交数据到服务器
function pushData(api,data,id){
    $.ajax ({
        url:url+'xxxx',
        type: 'post',
        dataType:'json',
        data:JSON.stringify({
            
        }),
        contentType: "application/json; charset=utf-8",
        success: function(result){
            if(result.code === 'Success'){
                console.log('发送成功',api,id)
            }else{
                console.log('发送失败',api,id)
            }
        },
        error:function(error){
            console.log('发送失败',api,id)
        },
        
    });
}
// 监听标签创建成功
chrome.tabs.onCreated.addListener(function(tab) {
    if(!createTabOpthon[tab.id]){
        createTabOpthon[tab.id]=tab.pendingUrl
    }
});
// 消息监听
chrome.extension.onMessage.addListener((message, sender, sendResponse) =>{
    // 来自content_script.js的消息,携带的有cookie以及需要跳转的页面
    if(message.action==='cookie'){
        const list = message.content;
        localStorage.clear();
        list.split(';').forEach(function(item){
            // 谷歌插件设置cookie
            chrome.cookies.set({
                "url": 'www.baidu.com',
                "name": item.split('=')[0],
                "value": item.split('=')[1],
            });
        })
               // 谷歌插件打开标签,挂载js脚本
           chrome.tabs.create({url:'www.baidu.com?xx=xx#data1'},function(tab){
                    chrome.tabs.executeScript(tab.id, {file: 'js/handle.js'});
                })
            }
        
    }
 
    // 上报数据
    if(message.action==='http'){

        if(httplist.includes(message.url)==true){
            localStorage.setItem(message.url,message.tabId)
            pushData(message.url,message.content,message.tabId)
        }
    }
    // 关闭标签
    if(message.action === 'closeTab'){
        let data = message.content;
        if(data.length>0){
            for (let index = 0; index < data.length; index++) {
                const ele = data[index];
                let tabId = localStorage.getItem(ele);
                if(tabId){
                    chrome.tabs.remove(Number(tabId), function (){
                        chrome.tabs.create({url:createTabOpthon[tabId]},function(tab){
                            chrome.tabs.executeScript(tab.id, {file: 'js/handle.js'});
                            delete createTabOpthon[tabId]
                        })
                    })
                }
            }
        }
    }
});

devtools.js


// 向background.js发送劫持到的接口信息消息
chrome.devtools.network.onRequestFinished.addListener(values=>{	
	values.getContent((content,encoding)=>{	
	   // 批处理url
		let newUrl = values.request.url;
		newUrl=newUrl.split('?')[0];
                newUrl=newUrl.replace(/^(https|http):\/\/[^/]+/, "");
		chrome.runtime.sendMessage({
			action:"http",
			tabId:chrome.devtools.inspectedWindow.tabId,
			url:newUrl,
			content:content
		})
	})
});
//

handle.js

// 通过xpath路劲获取到demo
function x(xpath) {
    var result = document.evaluate(xpath, document, null, XPathResult.ANY_TYPE, null);
    return result.iterateNext()
}
const handleDemo = {
    // 设置商品
    a:function(){
        let demo = x('/html/body/div[1]/div/div/div/div/div/div/div/div[2]/a[2]/div')
        demo.click()
    },
}

这里说明下因为我们要模拟demo的点击情况,一般打包后demo上都有hash值,所以无法通过class获取,我们采用xpath路径获取demo节点

四、一些注意

主要分享下开发过程中踩过的一些坑,开发需要后端配合帮我们采集cookie信息,最终才能工程化,这只是插件部分的数据采集,上报。后端还需要一套报警机制,来判断页面是否死掉, 如果页面死掉了,只能关闭标签重新打开挂载脚本Js,如果刷新脚本js就丢失了,并且content_script.js被被注入到每一个打开的标签页中,所以一定要有域名判断执行逻辑。

为什么要在content_script.js中请求接口获取cookie?

因为只有这里才能获取到我们url上面的参数,启动脚本一定要用shell命令启动并且打开控制台,只有打开了控制台devtools才能工作。

特别提醒:爬虫有法律风险,慎商用,欢迎一起讨论探索,喜欢别忘点赞额!