如何从操纵延迟加载方法的网页中获取所有数据?

SIM*_*SIM 4 python selenium web-scraping python-3.x selenium-webdriver

我已经使用 selenium 在 python 中编写了一些脚本来从 redmart 网站上抓取不同产品的名称和价格。我的爬虫点击一个链接,转到它的目标页面,从那里解析数据。但是,我在使用此爬网程序时面临的问题是,由于网页的加载速度较慢,它从页面中抓取的项目很少。如何从控制延迟加载过程的每个页面获取所有数据?我尝试使用“执行脚本”方法,但我做错了。这是我正在尝试的脚本:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()
driver.get("https://redmart.com/bakery")
wait = WebDriverWait(driver, 10)

counter = 0    
while True:

    try:
        wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "li.image-facets-pill")))
        driver.find_elements_by_css_selector('img.image-facets-pill-image')[counter].click()      
        counter += 1    
    except IndexError:
        break 

    # driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

    for elems in wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, "li.productPreview"))):
        name = elems.find_element_by_css_selector('h4[title] a').text
        price = elems.find_element_by_css_selector('span[class^="ProductPrice__"]').text
        print(name, price)

    driver.back()
driver.quit() 
Run Code Online (Sandbox Code Playgroud)

小智 5

我想您可以为此使用 Selenium,但是如果 @Andersson 在 Stackoverflow上的另一个问题中为您制作了代码后您担心速度,那么您应该复制 API 调用,该站点使用该调用并从 JSON 中提取数据 -就像网站一样。

如果您使用 Chrome Inspector,您将看到外部 while 循环(原始代码中的 try 块)中的每个类别的站点都调用 API,该 API 返回站点的整体类别。所有这些数据都可以像这样检索:

categories_api = 'https://api.redmart.com/v1.5.8/catalog/search?extent=0&depth=1'
r = requests.get(categories_api).json()
Run Code Online (Sandbox Code Playgroud)

对于下一个 API 调用,您需要获取有关面包店内容的 uri。这可以像这样完成:

bakery_item = [e for e in r['categories'] if e['title'] == 'Bakery]
children = bakery_item[0]['children']
uris = [c['uri'] for c in children]
Run Code Online (Sandbox Code Playgroud)

Uris 现在将是一个字符串列表(['bakery-bread', 'breakfast-treats-212', 'sliced-bread-212', 'wraps-pita-indian-breads', 'rolls-buns-212', “烘焙食品,甜点”,“面包,手工-面包-212”,“冻结部分烘烤”,“长寿命,面包吐司”,“专业-212”]) ,你会传递给Chrome Inspector 发现的另一个 API,该网站用于加载内容。

此 API 具有以下形式(默认返回较小的 pageSize,但我将其提高到 500,以确保您在一个请求中获得所有数据):

items_API = 'https://api.redmart.com/v1.5.8/catalog/search?pageSize=500&sort=1024&category={}'

for uri in uris:
    r = requests.get(items_API.format(uri)).json()
    products = r['products']
    for product in products:
        name = product['title']
        # testing for promo_price - if its 0.0 go with the normal price
        price = product['pricing']['promo_price']
        if price == 0.0:
            price = product['pricing']['price']
        print("Name: {}. Price: {}".format(name, price))
Run Code Online (Sandbox Code Playgroud)

编辑:如果你仍然想坚持使用硒,你可以插入这样的东西来处理延迟加载。关于滚动的问题之前已经回答过多次,所以你的实际上是重复的。将来,您应该展示您尝试过的内容(您自己在执行部分的努力)并显示回溯。

check_height = driver.execute_script("return document.body.scrollHeight;") 
while True:
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    time.sleep(5)
    height = driver.execute_script("return document.body.scrollHeight;") 
    if height == check_height: 
        break 
     check_height = height
Run Code Online (Sandbox Code Playgroud)