


懒加载。。。。此方案能解决大多数懒加载情况,如果遇到解决不了的,可以找我给你其他解决方案。
懒加载最重要的是过滤掉已经获取的元素,可以直接在js中定义一个变量用来存储和过滤每次获取的元素。
因为每个元素在页面中是唯一的,所以可以直接通过两个元素的地址判断是否为同一个元素.
每次迭代元素都执行这段代码 element.scrollIntoView({ behavior: 'auto', block: 'center' }); 可以让元素 element 滚动到可视页面的中心点,
这样代替鼠标滚动的方式有两个好处:
1.可以提前加载新的元素
2.滚动的比较稳定
为了让使用体验和正常的相似元素列表一致,构造一个类,重写 __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

敬请期待...