Я пытаюсь использовать Scrapy Drumwright, чтобы пролистать интернет-магазин и собрать все товары, но это не работает

Я пытаюсь нажимать кнопку «Загрузить еще», пока она не исчезнет и все продукты не загрузятся. Затем я хочу щелкнуть по всем отдельным продуктам, чтобы получить необходимые мне данные с сайта отдельных продуктов.

Я пробовал несколько способов прокрутки вниз и несколько раз менял код и синтаксис, используя чат gpt и Gemini. Тем не менее, мне все равно возвращают пустой файл JSON.


import scrapy
import datetime
import re

from scrapy.crawler import CrawlerProcess
from scrapy_playwright.page import PageMethod
from scrapy.selector import Selector



class LidlSpider(scrapy.Spider):
    name = 'lidl_snacks'
    allowed_domains = ['sortiment.lidl.ch']
    custom_settings = {
        'ROBOTSTXT_OBEY': False
    }
    start_urls = [
        'https://sortiment.lidl.ch/de/sussigkeiten-snacks#/', #246 Produkte
    ] 
    
    def start_requests(self):
        for url in self.start_urls:
            yield scrapy.Request(
                url,
                dont_filter=True,
                callback=self.parse,
                meta = {
                    'url': url,
                    'playwright': True,
                    'playwright_include_page': True,
                    'playwright_page_methods':[
                        PageMethod('wait_for_selector', 'div.product-item-info'),
                        PageMethod("wait_for_selector", "button.primary.amscroll-load-button-new"),
                        
                    ]
                }
            )
    async def scroll_to_bottom(self,page):
        await page.evaluate("window.scrollTo(0, document.body.scrollHeight);")

    async def parse(self, response):
        page = response.meta["playwright_page"]
        pagination_buttons = page.locator("button.primary.amscroll-load-button-new")  # Adjust the selector as needed

        
        if pagination_buttons:
            buttons = await pagination_buttons.all()
            for button in buttons:
                await button.click()  # Trigger pagination action
                await page.wait_for_navigation()
                await self.scroll_to_bottom(page)  # Optional scroll down on the new page
                
        # Extract product information after pagination click
        content = await page.content()
        sel = Selector(text=content)
        produkte = sel.css('div.product-item-info')
        for produkt in produkte:
            produkt_url = produkt.css('a.product-item-link::attr(href)').get()
            yield response.follow(produkt_url, callback=self.parse_produkt, meta = {'url': response.meta['url']})

      

    def parse_produkt(self, response):
        
        mini_dict = {
                'retailer':       self.name,
                'datetime':       datetime.date.today(),
                'categorie':      None,
                'id':             None, #response.css('div.col-left>p::text').get().split()[1],
                'brand':          str(response.css('p.brand-name::text').get()),
                'detail':         str(response.css('span.base::text').get()),
                'actual_price':   response.css('strong.pricefield__price::attr(content)').get(),
                'quantity':       None,
                'regular_price':  None,
                'price_per_unit': None,

            }
           

        yield mini_dict

       
    

        
if __name__ == "__main__":  # __main__ was only created for debug purposes
    process = CrawlerProcess()
    process.crawl(LidlSpider)
    process.start()

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
104
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я вижу пару проблем,

  • На странице есть всплывающее окно , где вам сначала нужно нажать кнопку Zustimmen (Согласен), прежде чем вы сможете нажать что-нибудь еще. Поэтому добавьте в свой код следующее:
popup = 'div#onetrust-banner-sdk'
if await page.is_visible(popup, timeout = 5000):
    await page.locator('button#onetrust-accept-btn-handler').click()
    await page.wait_for_selector(popup, state='hidden')
  • page.wait_for_navigation() выдает ошибку, так как на playwright.page нет такого метода, поэтому вы можете заменить его на page.wait_for_load_state("domcontentloaded")

  • Существует одна кнопка Weitere Produkte laden (Загрузить больше продуктов), которую нужно нажимать несколько раз, пока она не исчезнет, ​​поэтому pagination_buttons в вашем коде возвращает одну кнопку, на которую нажимают один раз.

pagination_buttons = page.locator("button.primary.amscroll-load-button-new")
buttons = await pagination_buttons.all()
for button in buttons:
    await button.click()  # Trigger pagination action
    await page.wait_for_load_state("domcontentloaded")  # Wait for new page to load
    await self.scroll_to_bottom(page)  # Optional scroll down on the new page

вы можете исправить это, заменив приведенное выше:

while True: 
    try:
        show_more_button = page.locator("button.primary.amscroll-load-button-new")
        if show_more_button:
            await show_more_button.click()
            await page.wait_for_load_state("domcontentloaded", timeout=5000)
            await self.scroll_to_bottom(page)  
        else:
            break
    except Exception:
        break

Вот полный код:

import datetime
import scrapy

from scrapy.crawler import CrawlerProcess
from scrapy_playwright.page import PageMethod
from scrapy.selector import Selector

class LidlSpider(scrapy.Spider):
    name = 'lidl_snacks'
    allowed_domains = ['sortiment.lidl.ch']
    custom_settings = {
        'ROBOTSTXT_OBEY': False
    }
    start_urls = [
        'https://sortiment.lidl.ch/de/kaffee-tee', #72 products
    ] 
    
    def start_requests(self):
        for url in self.start_urls:
            yield scrapy.Request(
                url,
                dont_filter=True,
                callback=self.parse,
                meta = {
                    'url': url,
                    'playwright': True,
                    'playwright_include_page': True,
                    'playwright_page_methods':[
                        PageMethod('wait_for_load_state',"domcontentloaded"),   
                    ]
                }
            )
    async def scroll_to_bottom(self,page):
        await page.evaluate("window.scrollTo(0, document.body.scrollHeight);")

    async def parse(self, response):
        page = response.meta["playwright_page"]
        
        #await page.screenshot(path = "popup.png")

        popup = 'div#onetrust-banner-sdk'
        if await page.is_visible(popup, timeout = 5000):
            await page.locator('button#onetrust-accept-btn-handler').click()
            await page.wait_for_selector(popup, state='hidden')

        #await page.screenshot(path = "popup_clicked_check.png", full_page=True)
        
        #count = 0
        while True: 
            try:
                show_more_button = page.locator("button.primary.amscroll-load-button-new")
                if show_more_button:
                    await show_more_button.click()
                    await page.wait_for_load_state("domcontentloaded", timeout=5000)  # Wait for new page to load
                    await self.scroll_to_bottom(page)  # Optional scroll down on the new page
                    # await page.screenshot(path=f"page_scrolled_{count}.png", full_page=True)
                    # count+=1
                else:
                    break
            except Exception:
                break
   
        #Extract product information after pagination click
        content = await page.content()
        sel = Selector(text=content)
        produkte = sel.css('div.product-item-info')
        for produkt in produkte:
            produkt_url = produkt.css('a.product-item-link::attr(href)').get()
            yield response.follow(produkt_url, callback=self.parse_produkt, meta = {'url': response.meta['url']})

      

    def parse_produkt(self, response):
        
        mini_dict = {
                'retailer':       self.name,
                'datetime':       datetime.date.today(),
                'categorie':      None,
                'id':             None, #response.css('div.col-left>p::text').get().split()[1],
                'brand':          str(response.css('p.brand-name::text').get()),
                'detail':         str(response.css('span.base::text').get()),
                'actual_price':   response.css('strong.pricefield__price::attr(content)').get(),
                'quantity':       None,
                'regular_price':  None,
                'price_per_unit': None,

            }
           

        yield mini_dict

if __name__ == "__main__":  # __main__ was only created for debug purposes
    process = CrawlerProcess()
    process.crawl(LidlSpider)
    process.start()

Примечания) :

  • Заменил /sussigkeiten-snacks#/ на /kaffee-tee, так как на странице меньше товаров, которые нужно очистить.
  • возвращает правильное количество элементов при запуске как есть, или вы можете использовать
scrapy crawl lidl_snacks -O snacks.json

чтобы увидеть, что он возвращает.

Другие вопросы по теме