如何在 Selenium 中使用滚动进行分页?

How to do pagination with scroll in Selenium?

我需要为this page做分页:

我阅读了 this question 并尝试了这个:

scrolls = 10
while True:
    scrolls -= 1
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
    time.sleep(3)
    if scrolls < 0:
        break

我需要向下滚动才能获得所有产品,但我不知道我需要滚动多少次才能获得所有产品。

我也试过大屏

'SELENIUM_DRIVER_ARGUMENTS': ['--no-sandbox', '--window-size=1920,30000'],

并向下滚动

time.sleep(10) 
self.driver.execute_script("window.scrollBy(0, 30000);")

有人知道如何获得所有产品吗? 如果 Selenium 不是这种情况下的最佳选择,我愿意接受另一种解决方案。 谢谢。

更新 1: 我需要所有产品 ID。为了获得产品 ID,我使用了这个:

products = response.css('div.jfJiHa > .iepIep')
        for product in products:
            detail_link = product.css('a.jXwbaQ::attr("href")').get()
            product_id = re.findall(r'products/(\d+)', detail_link)[0]

每次阅读展示的产品时尝试向下滚动可见屏幕高度数量页面,直到 //button[@data-test='footer-feedback-button'] 或位于底部的任何其他元素可见

此代码可能有帮助 -

from selenium import webdriver
from selenium.common.exceptions import StaleElementReferenceException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

driver = webdriver.Chrome()
wait = WebDriverWait(driver, 30)

driver.get('https://www.compraonline.bonpreuesclat.cat/products/search?q=pasta')

BaseDivs = driver.find_elements_by_xpath("//div[contains(@class,\"base__Wrapper\")]")

for div in BaseDivs:
    try:
        wait.until(EC.visibility_of_element_located((By.XPATH, "./descendant::img")))
        driver.execute_script("return arguments[0].scrollIntoView(true);", div)
    except StaleElementReferenceException:
        continue

此代码将等待图像加载,然后将焦点放在元素上。这样它会自动向下滚动到页面末尾。

如果这是您要查找的内容,请将其标记为答案。

正如所评论的,如果没有看到你的整个蜘蛛,很难看出你哪里出了问题,但如果我们假设你的解析使用的是 scrapy 响应,那么这就是为什么你总是得到30 个产品。

您需要在每次滚动并查询后从 driver 创建一个新的选择器。从页面获取 300 项的代码的完整示例是

import re
import time
from pprint import pprint

import parsel
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver import Firefox

with Firefox() as driver:
    driver.get("https://www.compraonline.bonpreuesclat.cat/products/search?q=pasta")

    all_items = {}

    while True:
        sel = parsel.Selector(driver.page_source)
        for product in sel.css("div[data-test] h3 > a"):
            name = product.css("::text").get()
            product_id = re.search("(\d+)", product.attrib["href"]).group()
            all_items[product_id] = name
        try:
            element = driver.find_element_by_css_selector(
                "div[data-test] + div.iepIep:not([data-test])"
            )
        except NoSuchElementException:
            break
        driver.execute_script("arguments[0].scrollIntoView(true);", element)
        time.sleep(1)

    pprint(all_items)
    print("Number of items =", len(all_items))

这里的关键位

  • 使用driver.get获取页面后我们开始循环
  • 我们新建一个Selector(这里我直接用parsel.Selectorscrapy内部用的是parsel.Selector
  • 我们提取了我们需要的信息。显示的产品都具有 data-test 属性。如果这是 scrapy.Spider 我会 yield 信息,但在这里我只是将它添加到所有项目的字典中。
  • 获得所有可见项后,我们尝试找到 div 的第一个具有 data-test 属性的兄弟项,data-test 属性 (using the css + symbol)
  • 如果不存在这样的元素(因为我们已经看到所有项目)则跳出循环,否则将该元素滚动到视图中并暂停一秒钟
  • 重复直到所有项目都被解析

我解决了我的问题,但没有使用 Selenium,我们可以通过另一个请求搜索所有产品: https://www.compraonline.bonpreuesclat.cat/api/v4/products/search?limit=1000&offset=0&sort=favorite&term=pasta