【问题标题】:scrapy and selenium seem to intervene each otherscrapy 和 selenium 似乎相互干预
【发布时间】:2019-01-12 21:02:59
【问题描述】:

您好,我在网页抓取或使用 scrapy 和 selenium 方面没有太多经验。如果我的代码中有太多不好的做法,请先道歉。

我的代码的简要背景:我尝试使用scrapy从多个网站抓取产品信息,我也使用selenium,因为我需要点击网页上的“查看更多”按钮和“不,谢谢”按钮。由于网站上有不同类别的href,我还需要请求那些“子链接”以确保我不会错过任何未显示在根页面上的项目。

问题是,我注意到在这个 for 循环 for l in product_links: 中,scrapy 和 selenium 似乎表现得很奇怪。例如,我希望response.url == self.driver.current_url 总是正确的。但是,它们在这个 for 循环的中间变得不同。此外,self.driver 似乎在products = self.driver.find_elements_by_xpath('//div[@data-url]') 中捕获了当前url 中不存在的一些元素,然后在sub = self.driver.find_elements_by_xpath('//div[(@class="shelf-container") and (.//div/@data-url="' + l + '")]//h2') 中再次检索它们失败

非常感谢。我真的很困惑。

from webScrape.items import ProductItem
from scrapy import Spider, Request
from selenium import webdriver

class MySpider(Spider):
    name = 'name'
    domain = 'https://uk.burberry.com'

    def __init__(self):
        super().__init__()
        self.driver = webdriver.Chrome('path to driver')
        self.start_urls = [self.domain + '/' + k for k in ('womens-clothing', 'womens-bags', 'womens-scarves',
                                        'womens-accessories', 'womens-shoes', 'make-up', 'womens-fragrances')]
        self.pool = set()

    def parse(self, response):
        sub_links = response.xpath('//h2[starts-with(@class, "shelf1-section-title")]/a/@href').extract()
        if len(sub_links) > 0:
            for l in sub_links:
                yield Request(self.domain + l, callback = self.parse)
        self.driver.get(response.url)
        email_reg = self.driver.find_element_by_xpath('//button[@class="dc-reset dc-actions-btn js-data-capture-newsletter-block-cancel"]')
        if email_reg.is_displayed():
            email_reg.click()
        # Make sure to click all the "load more" buttons
        load_more_buttons = self.driver.find_elements_by_xpath('//div[@class="load-assets-button js-load-assets-button ga-shelf-load-assets-button"]')
        for button in load_more_buttons:
            if button.is_displayed():
                button.click()
        products = self.driver.find_elements_by_xpath('//div[@data-url]')
        product_links = [item.get_attribute('data-url') for item in products if item.get_attribute('data-url').split('-')[-1][1:] not in self.pool]
        for l in product_links:
            sub = self.driver.find_elements_by_xpath('//div[(@class="shelf-container") and (.//div/@data-url="' + l + '")]//h2')
            if len(sub) > 0:
                sub_category = ', '.join(set([s.get_attribute('data-ga-shelf-title') for s in sub]))
            else:
                sub_category = ''
            yield Request(self.domain + l, callback = self.parse_product, meta = {'sub_category': sub_category})

    def parse_product(self, response):
        item = ProductItem()
        item['id'] = response.url.split('-')[-1][1:]
        item['sub_category'] = response.meta['sub_category']
        item['name'] = response.xpath('//h1[@class="product-title transaction-title ta-transaction-title"]/text()').extract()[0].strip()
        self.pool.add(item['id'])
        yield item
        others = response.xpath('//input[@data-url]/@data-url').extract()
        for l in others:
            if l.split('-')[-1][1:] not in self.pool:
                yield Request(self.domain + l, callback = self.parse_product, meta = response.meta)

【问题讨论】:

    标签: python selenium selenium-webdriver web-scraping scrapy


    【解决方案1】:

    Scrapy 是一个异步框架。 parse*() 方法中的代码并不总是线性运行。无论哪里有yield,该方法的执行可能会在那里停止一段时间,同时代码的其他部分运行。

    因为循环中有一个yield,这就解释了为什么您会遇到这种意外行为。在yield,您的程序的一些其他代码恢复执行并可能将 Selenium 驱动程序切换到不同的 URL,当代码恢复循环时,来自 Selenium 驱动程序的 URL 已更改。

    老实说,据我所知,您的用例并不需要 Scrapy 中的 Selenium。在 Scrapy 中,Splash 或 Selenium 之类的东西仅用于非常特定的场景,例如避免机器人检测。

    通过使用 Web 浏览器中的开发人员工具(Inspect、Network)然后在 Scrapy 中重现它们来确定页面 HTML 的结构和请求中使用的参数通常是一种更好的方法。

    【讨论】:

    • 非常感谢您的解释!我使用 selenium 的主要原因是因为我需要单击“查看更多”按钮。如果我不单击这些按钮,我将无法获得所有产品(我在单击按钮之前和之后尝试了两次相同的 xpath,但结果不同)。您对此有什么建议吗?
    • 是的。常见的 Scrapy 方法是打开浏览器 devtools 的 Network 选项卡,查看 View More 按钮的实际作用(它很可能发送 AJAX 请求),然后在您的蜘蛛中重现。
    • 在这种情况下,点击会触发对uk.burberry.com/womens-new-arrivals-new-in/…的请求,您可以直接对这样的URL执行请求,根据需要更改参数。如果您收到意外响应,您可能需要确保您还发送了所需的标头和 cookie,同样,浏览器开发人员工具也是您的朋友。
    • 非常感谢加莱西奥。我设法在没有硒的情况下做到这一点,它非常有效且无痛。感激不尽!
    • 嗨,Gallaecio,希望你不会介意我回过头来看这篇文章。我最近发现我的代码仍然无法完全捕获所有内容,这可能是由于异步框架。例如,当我执行self.domain + l 时,我看到 str 和 Nontype 之间发生了像“+”这样的异常。我相信正如您所描述的,代码可能会恢复并且变量l 已经更改(奇怪的是,不知何故为 NoneType Object)。有什么办法可以避免这种问题吗?我想我的程序设计很差,很想听听你的想法。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2023-01-31
    • 2012-03-21
    • 1970-01-01
    • 1970-01-01
    • 2011-07-14
    • 2023-04-03
    • 1970-01-01
    • 2013-05-10
    相关资源
    最近更新 更多