懒加载元素的通用解决方案----By广州组
回答
收藏

懒加载元素的通用解决方案----By广州组

驿站
2023-05-29 19:46·浏览量:3035
驿站
发布于 2023-05-29 19:463035浏览

〇、实现效果

一、问题背景

    懒加载。。。。此方案能解决大多数懒加载情况,如果遇到解决不了的,可以找我给你其他解决方案。


二、实现原理

2.1 过滤

    懒加载最重要的是过滤掉已经获取的元素,可以直接在js中定义一个变量用来存储和过滤每次获取的元素。

因为每个元素在页面中是唯一的,所以可以直接通过两个元素的地址判断是否为同一个元素.


2.2 滚动页面

    每次迭代元素都执行这段代码 element.scrollIntoView({ behavior: 'auto', block: 'center' });  可以让元素 element 滚动到可视页面的中心点,

这样代替鼠标滚动的方式有两个好处:

    1.可以提前加载新的元素 

    2.滚动的比较稳定


2.3 使用体验优化

    为了让使用体验和正常的相似元素列表一致,构造一个类,重写 __iter__、__next__、 __getitem__。让得到的对象可以像正常的列表一样可以循环和下标取值


三、代码实现


import xbot
from xbot import print, sleep, win32
from . import package
from .package import variables as glv

import uuid
import time

class LazyLoadIter():
    def __init__(self, web_page: xbot.web.WebBrowser, selector, timeout):
        self.web_page = web_page
        self.selector = selector
        self.var_name = "yd" + str(uuid.uuid4()).replace("-", "_")
        self.timeout = int(timeout)

        eles = self.web_page.find_all(selector, timeout=self.timeout)
        if len(eles) == 0:
            raise Exception("未找到懒加载元素")

        # 将变量初始化到相似元素所在域
        init_code = '''
            function (element, input) {
                %s = []
            }
        ''' % self.var_name
        eles[0].execute_javascript(init_code)
        self._data = []
        self.iterable = iter(self._data)

    def __getitem__(self, index):
        if len(self._data) <= index:
            self.load_ele()
        return self._data[index]

    def __len__(self):
        return len(self._data)

    def __iter__(self):
        return self

    def __next__(self):
        try:
            ele = next(self.iterable)
            scroll_into_view_code = """
                function (element, input) {
                    element.scrollIntoView({ behavior: 'auto', block: 'center' });
                }               
            """
            ele.execute_javascript(scroll_into_view_code)
            return ele
        except StopIteration:
            if self.load_ele():
                return self.__next__()
            raise
        except Exception as e:
            # TODO 待处理的异常,可能也不需要处理
            if "未找到指定元素ID" == e:
                pass
            raise


    def load_ele(self):
        """
        加载元素,并过滤元素
        """
        start_time = time.time()
        while True:
            new_eles = []
            for ele in self.web_page.find_all(self.selector, timeout=self.timeout):
                filter_code = '''
                    function (element, input) {
                        res = %s.includes(element)
                        if (!res) {
                            %s.push(element)
                        }
                        return res;
                    }
                ''' % tuple([self.var_name] * 2)
                res = ele.execute_javascript(filter_code)
                if res:
                    continue
                new_eles.append(ele)

            if len(new_eles) == 0:
                end_time = time.time() 
                if end_time - start_time > self.timeout:
                    return False
                continue

            self.iterable = iter(new_eles)
            self._data += new_eles
            return True


def main(args):
	# 使用示例
	lazy_element_list = LazyLoadIter(web_page, selector, timeout)
	for lazy_element in lazy_element_list:
		# 元素的相关操作...
		pass


四、指令实现



五、桌面端

    敬请期待...

收藏5
全部回答1
最新
发布回答
回答