和硒似乎互相干扰

时间:2019-01-12 21:02:59

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

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

我的代码的简要背景:我试图使用scrapy从多个网站上获取产品信息,并且我还使用了硒,因为我需要单击网页上的“查看更多”按钮和“不,谢谢”按钮。由于网站上有不同类别的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)

1 个答案:

答案 0 :(得分:0)

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

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

说实话,就我所知,您并不需要Scrapy中的Selenium。在Scrapy中,诸如Splash或Selenium之类的东西仅在非常特定的情况下使用,诸如避免机器人检测之类的东西。

通过使用Web浏览器(检查,网络)中的开发人员工具,然后在Scrapy中再现它们,通常是找出页面HTML的结构和请求中使用的参数的更好的方法。