webscraper改写案例分析

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

对webscraper中SelectorElementScroll部分改进,使其先滚动到底部加载全部网页,再读出所有数据。
因Firefox浏览器加载自己写的扩展程序需要审批,因此使用360浏览器加载改写的扩展,QQ浏览器中部分功能不能正常运行,其他浏览器未尝试。


提示:本代码在360浏览器中执行通过

一、对webscraper0.2.0.18的修改

该版本中SelectorElementScroll正好处于script/Selector文件夹下,文件结构较简单,但官方初始版本在执行上就发现有些浏览器不兼容,因此后面对更高版本也做了修改。

var SelectorElementScroll = {

	canReturnMultipleRecords: function () {
		return true;
	},

	canHaveChildSelectors: function () {
		return true;
	},

	canHaveLocalChildSelectors: function () {
		return true;
	},

	canCreateNewJobs: function () {
		return false;
	},
	willReturnElements: function () {
		return true;
	},
	scrollToBottom: function() {
		window.scrollTo(0,document.documentElement.scrollHeight);
		//console.log(document.documentElement.scrollTop+";"+document.documentElement.clientHeight+","+document.documentElement.scrollHeight);
		
	},
	scrollToTop: function() {
		var step=50;
		if(document.documentElement.scrollTop>step){
			window.scrollTo(document.documentElement.scrollTop,document.documentElement.scrollTop-step);
		}else{
			window.scrollTo(document.documentElement.scrollTop,0);
		}
	},

	_getData: function (parentElement) {

		var delay = parseInt(this.delay) || 0;
		var deferredResponse = $.Deferred();
		var foundElements = [];
		var lastHeight=0;
		var isTouchBottom=false;
		
		// initially scroll down and wait
		this.scrollToBottom();

		var nextElementSelection = (new Date()).getTime()+delay;
		var begin = nextElementSelection;

		// infinitely scroll down and find all items
		var interval = setInterval(function() {

			var now = (new Date()).getTime();
			// sleep. wait when to extract next elements
			if(now < nextElementSelection) {
				clearInterval(interval);
				return;
			}
			/*if(now - begin > 10000){
				clearInterval(interval);

				alert("now-begin");
				return;
			}*/

			var elements = this.getDataElements(parentElement);
			// quick find max bottom
			if(!isTouchBottom && lastHeight!=document.documentElement.scrollHeight) {
				// continue scrolling and add delay
				lastHeight=document.documentElement.scrollHeight;
				foundElements = elements;
				this.scrollToBottom();
				nextElementSelection = now+delay;		
			
				//alert('step1;now:='+now+'nextElementSelection ='+nextElementSelection);
			
			// check max bottom
			//}else if(!isTouchBottom && lastHeight==document.documentElement.scrollHeight) {
			}else if(!isTouchBottom &&now - begin > 10000){
				isTouchBottom=true;
				foundElements = elements;
				this.scrollToTop();
				nextElementSelection = now+delay;
				//alert('step2;scrollTop='+document.documentElement.scrollTop);
				

			// smooth up to load pic
			}else if(isTouchBottom && document.documentElement.scrollTop!=0){
				foundElements = elements;
				this.scrollToTop();
				nextElementSelection = now+delay;
				//alert('step3;scrollTop='+document.documentElement.scrollTop);
				
			// check top
			}else if(isTouchBottom && document.documentElement.scrollTop==0){
				clearInterval(interval);
				deferredResponse.resolve(jQuery.makeArray(elements));
				//alert('step4;scrollTop='+document.documentElement.scrollTop);
			
			
			}

		}.bind(this), 50);

		return deferredResponse.promise();
	},

	getDataColumns: function () {
		return [];
	},

	getFeatures: function () {
		return ['multiple', 'delay']
	}
};

二、对0.3.6版本的修改

1.导入

导入src目录,先修改其中的manifest.json文件,完善插件名称、版本号等。
代码如下(示例):

2.修正报错

要点2:
引用模块必须在json中声明类型"type"="module"或在html中添加type=“module”,否则无法识别

Uncaught SyntaxError: Cannot use import statement outside a module

如:

<script type="module" src="/public/portis.js"></script>

	"background": {
		"page": "./background/background.html",
		"type": "module"
	},

要点3:
导入的模块文件地址前不能省略/(根文件夹)或./(本文件夹)或…/(上层文件夹),须按照规范

Uncaught TypeError: Failed to resolve module specifier "mymodule.js". Relative references must start with either "/", 

如:

import * as browser from "../webextension-polyfill/browser-polyfill.min.js";
import Config from '../scripts/Config';
import StorePouchDB from '../scripts/StorePouchDB';
import StoreRestApi from '../scripts/StoreRestApi';
import Sitemap from '../scripts/Sitemap';
import Queue from '../scripts/Queue';
import ChromePopupBrowser from '../scripts/ChromePopupBrowser';
import Scraper from '../scripts/Scraper';
import getBackgroundScript from '../scripts/BackgroundScript';

3.特殊版本

发现GitHub上下载的版本是第三方修改版本,与官网下载版本不符,格式也不对应,修改此版本任务终止。


三、对0.6.4版本的修改

从0.2.1版本后采用ES6语法重写,之后所有版本都在此基础上迭代,因此我修改了最新版本。ES6语法一开始有些难以理解,因此是模仿着改写。

主要修改部分为background_script.js和content_script.js两个文件,注意devtools_panel.js也包含与background.js相同的代码,但修改devtools_panel.js是无效的。

background_script.js的#16095行是SelectorElementScroll部分

function(e, t, i) {
    "use strict";
    var n = this && this.__awaiter || function(e, t, i, n) {
        return new (i || (i = Promise))((function(r, a) {
            function o(e) {
                try {
                    c(n.next(e));
                } catch (e) {
                    a(e);
                }
            }
            function s(e) {
                try {
                    c(n.throw(e));
                } catch (e) {
                    a(e);
                }
            }
            function c(e) {
                var t;
                e.done ? r(e.value) : (t = e.value, t instanceof i ? t : new i((function(e) {
                    e(t);
                }))).then(o, s);
            }
            c((n = n.apply(e, t || [])).next());
        }));
    }, r = this && this.__await || function(e) {
        return this instanceof r ? (this.v = e, this) : new r(e);
    }, a = this && this.__asyncGenerator || function(e, t, i) {
        if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
        var n, a = i.apply(e, t || []), o = [];
        return n = {}, s("next"), s("throw"), s("return"), n[Symbol.asyncIterator] = function() {
            return this;
        }, n;
        function s(e) {
            a[e] && (n[e] = function(t) {
                return new Promise((function(i, n) {
                    o.push([ e, t, i, n ]) > 1 || c(e, t);
                }));
            });
        }
        function c(e, t) {
            try {
                (i = a[e](t)).value instanceof r ? Promise.resolve(i.value.v).then(l, u) : d(o[0][2], i);
            } catch (e) {
                d(o[0][3], e);
            }
            var i;
        }
        function l(e) {
            c("next", e);
        }
        function u(e) {
            c("throw", e);
        }
        function d(e, t) {
            e(t), o.shift(), o.length && c(o[0][0], o[0][1]);
        }
    };
    Object.defineProperty(t, "__esModule", {
        value: !0
    }), t.SelectorElementScroll = void 0;
    const o = i(10);
    class s extends o.Selector {
        constructor(e) {
            super(), this.type = "SelectorElementScroll", this.selector = "", this.multiple = !0, 
            this.delay = 2e3, this.scrollElementSelector = "", this.updateData(e);
        }
        canReturnMultipleRecords() {
            return !0;
        }
        canHaveChildSelectors() {
            return !0;
        }
        canCreateNewJobs() {
            return !1;
        }
        willReturnElements() {
            return !0;
        }
        scrollToBottomIm(e) {
            return n(this, void 0, void 0, (function*() {
                e.element;
                this.scrollElementSelector, yield e.scrollDownBodyIm();
            }));
        }
        scrollToBottom(e, t = !1) {
            return n(this, void 0, void 0, (function*() {
                const i = e.element;
                if (this.scrollElementSelector) {
                    const n = yield e.getElement(this.scrollElementSelector);
                    if (!n) return;
                    yield e.scrollDownElement(i, this.selector, t, n.element);
                } else yield e.scrollDownBody(i, this.selector, t);
            }));
        }
        scrollToTop(e) {
            return n(this, void 0, void 0, (function*() {
                e.element;
                this.scrollElementSelector, yield e.srcollBodyToTop();
            }));
        }
        _getData(e) {
            return a(this, arguments, (function*() {
                yield r(this.waitDelay()), yield r(this.scrollToTop(e));
                const t = parseInt("" + this.delay, 10) || 0;
                let i = yield r(this.getDataElements(e)), n = i.length;
                for (;;) {
                    if (yield r(this.scrollToBottomIm(e)), yield r(e.webPage.waitForPageLoadComplete(!1, t)), 
                    i = yield r(this.getDataElements(e)), i.length === n && (yield r(this.scrollToTop(e)), 
                    yield r(this.scrollToBottom(e, !0)), yield r(e.webPage.waitForPageLoadComplete(!1, t)), 
                    i = yield r(this.getDataElements(e)), i.length === n) && (yield r(this.scrollToTop(e)), 
                    yield r(this.scrollToBottom(e, !0)), yield r(e.webPage.waitForPageLoadComplete(!1, t)), 
                    i = yield r(this.getDataElements(e)), i.length === n)) {
                        for (const e of i) yield yield r(e);
                        return yield r(void 0);
                    }
                    n = i.length;
                }
            }));
        }
        getDataColumns() {
            return [];
        }
        getFeatures() {
            return [ "selector", "multiple", "delay", "scrollElementSelector" ];
        }
        getExperimentalFeatures() {
            return [ "scrollElementSelector" ];
        }
    }
    t.SelectorElementScroll = s;
}

注意#50477和#50918行做了函数传递
#50477

		scrollDownBody(e, t, i = !1) {
            return n(this, void 0, void 0, (function*() {
                return this.sendMessage("scrollDownBody", [ e, t, i ]);
            }));
        }
        srcollBodyToTop() {
            return n(this, void 0, void 0, (function*() {
                return this.sendMessage("srcollBodyToTop");
            }));
        }

#50918

        srcollBodyToTop() {
            return n(this, void 0, void 0, (function*() {
                yield this.contentScriptClient.srcollBodyToTop();
            }));
        }
        scrollDownBodyIm() {
            return n(this, void 0, void 0, (function*() {
                yield this.contentScriptClient.scrollDownBodyIm();
            }));
        }

content-script.js中

#2135

            scrollElementToTop(e) {
                return r(this, void 0, void 0, (function*() {
                    const t = this.elementReferences.getElementByReference(e);
                    yield s.ScrollDown.scrollElementToTop(t);
                }));
            }
            srcollBodyToTop() {
                return r(this, void 0, void 0, (function*() {
                    yield s.ScrollDown.scrollElementToTop(window);
                }));
            }
			scrollElementToBottomIm(e) {
                return r(this, void 0, void 0, (function*() {
                    const t = this.elementReferences.getElementByReference(e);
                    yield s.ScrollDown.scrollElementToBottomIm(t);
                }));
            }
            scrollDownBodyIm() {
                return r(this, void 0, void 0, (function*() {
                    yield s.ScrollDown.scrollElementToBottomIm(window);
                }));
            }

#2856

            static scrollElementToTop(e) {
                return r(this, void 0, void 0, (function*() {
                    0 !== o.getElementScrollYPosition(e) && (yield o.scrollToY(0, e));
                }));
            }
            static scrollElementToBottomIm(e) {
                return r(this, void 0, void 0, (function*() {
                    document.documentElement.scrollTop !== o.getElementScrollYPosition(e) && (yield o.scrollToY(0, e));
                }));
            }			

总结

通过自己改写浏览器插件大幅提高工作效率,修改该浏览器插件需要补充JS(ES6)方面知识,ES6的难度较高,不太容易上手。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
查询优化是数据库性能优化的重要环节之一,而优化改写技巧是提高查询性能的关键手段之一。在Oracle数据库中,有许多查询优化改写技巧和案例可以借鉴。 首先,可以利用索引来提高查询性能。索引是数据库中的一种数据结构,它可以加速查询操作。可以通过创建适当的索引来改进查询的执行计划,从而提高查询性能。例如,对于常见的查询字段,可以创建相应的索引,以减少全表扫描的开销。 其次,可以通过优化查询语句来改善查询性能。优化查询语句包括使用合适的JOIN操作、使用子查询和内联视图等。例如,可以使用内联视图来减少查询中的步骤,从而提高查询性能。 此外,可以通过调整数据库参数来改善查询性能。在Oracle数据库中,有许多参数可以配置,以适应不同的查询工作负载。通过合理地配置这些参数,可以提高查询的响应速度。例如,可以调整SGA(System Global Area)和PGA(Program Global Area)的大小,以适应不同的查询需求。 最后,可以通过使用数据库查询优化工具来改善查询性能。Oracle提供了一些查询优化工具,如Explain Plan、SQL Tuning Advisor和Automatic SQL Tuning等。这些工具可以帮助诊断查询性能问题,并提供相应的优化建议。通过使用这些工具,可以快速定位问题并进行优化改写。 总的来说,Oracle查询优化改写技巧和案例2.0 PDF提供了一些实用的优化方法和案例,可以帮助开发人员和数据库管理员提高查询性能。通过对这些技巧和案例的学习和实践,我们可以更好地优化查询性能,提高数据库的整体性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值