首页 > 解决方案 > 使用 Selenium 改进容器中元素的 Web 抓取

问题描述

我正在使用 FireFox,我的代码运行良好,只是速度很慢。我阻止加载图像,只是为了加快一点速度:

firefox_profile = webdriver.FirefoxProfile()
firefox_profile.set_preference('permissions.default.image', 2)
firefox_profile.set_preference('dom.ipc.plugins.enabled.libflashplayer.so', 'false')
firefox_profile.set_preference("browser.privatebrowsing.autostart", True)
driver = webdriver.Firefox(firefox_profile=firefox_profile)

但性能仍然很慢。我试过无头,但不幸的是,它没有用,因为我收到 NoSuchElement 错误。那么有没有办法加速 Selenium 网络抓取?我不能使用scrapy,因为这是一个动态的网络抓取,我需要多次点击next按钮,直到不存在可点击的按钮,并且还需要点击弹出按钮。

这是代码片段:

a = []
b = []
c = []
d = []
e = []
f = []
while True:
    container = driver.find_elements_by_xpath('.//*[contains(@class,"review-container")]')
    for item in container:
        time.sleep(2)
        A = item.find_elements_by_xpath('.//*[contains(@class,"ui_bubble_rating bubble_")]')
        for i in A:
            a.append(i,text)
        time.sleep(2)
        B = item.find_elements_by_xpath('.//*[contains(@class,"recommend-titleInline noRatings")]')
        for j in B:
            b.append(j.text)
        time.sleep(3)
        C = item.find_elements_by_xpath('.//*[contains(@class,"noQuotes")]')
        for k in C:
            c.append(k.text)
        time.sleep(3)
        D = item.find_elements_by_xpath('.//*[contains(@class,"ratingDate")]')
        for l in D:
            d.append(l.text)
        time.sleep(3)
        E = item.find_elements_by_xpath('.//*[contains(@class,"partial_entry")]')
        for m in E:
            e.append(m.text)

    try:
        time.sleep(2)
        next = driver.find_element_by_xpath('.//*[contains(@class,"nav next taLnk ui_button primary")]')
        next.click()
        time.sleep(2)
        driver.find_element_by_xpath('.//*[contains(@class,"taLnk ulBlueLinks")]').click()
    except (ElementClickInterceptedException,NoSuchElementException) as e:
        break

这是一个经过编辑的版本,但速度没有提高。

========================================================================
while True:
    container = driver.find_elements_by_xpath('.//*[contains(@class,"review-container")]')
    for item in container:
        WebDriverWait(driver, 50).until(EC.element_to_be_clickable((By.XPATH,'.//*[contains(@class,"ui_bubble_rating bubble_")]')))
        A = item.find_elements_by_xpath('.//*[contains(@class,"ui_bubble_rating bubble_")]')
        for i in A:
            a.append(i.text)
        WebDriverWait(driver, 50).until(EC.element_to_be_clickable((By.XPATH,'.//*[contains(@class,"recommend-titleInline noRatings")]')))
        B = item.find_elements_by_xpath('.//*[contains(@class,"recommend-titleInline noRatings")]')
        for i in B:
            b.append(i.text)
        WebDriverWait(driver, 50).until(EC.element_to_be_clickable((By.XPATH,'.//*[contains(@class,"noQuotes")]')))
        C = item.find_elements_by_xpath('.//*[contains(@class,"noQuotes")]')
        for i in C:
            c.append(i.text)
        WebDriverWait(driver, 50).until(EC.element_to_be_clickable((By.XPATH,'.//*[contains(@class,"ratingDate")]')))
        D = item.find_elements_by_xpath('.//*[contains(@class,"ratingDate")]')
        for i in D:
            d.append(i.text)
        WebDriverWait(driver, 50).until(EC.element_to_be_clickable((By.XPATH,'.//*[contains(@class,"partial_entry")]')))
        E = item.find_elements_by_xpath('.//*[contains(@class,"partial_entry")]')
        for i in E:
            e.append(i.text)

    try:
        #time.sleep(2)
        WebDriverWait(driver, 50).until(EC.element_to_be_clickable((By.XPATH,'.//*[contains(@class,"nav next taLnk ui_button primary")]')))
        next = driver.find_element_by_xpath('.//*[contains(@class,"nav next taLnk ui_button primary")]')
        next.click()
        WebDriverWait(driver, 50).until(EC.element_to_be_clickable((By.XPATH,'.//*[contains(@class,"taLnk ulBlueLinks")]')))
        driver.find_element_by_xpath('.//*[contains(@class,"taLnk ulBlueLinks")]').click()
    except (ElementClickInterceptedException,NoSuchElementException) as e:
        break

标签: pythonseleniumfirefoxweb-scrapingscrapy

解决方案


对于动态网页(使用 javascript 渲染或增强的页面),我建议您使用scrapy-splash

并不是说您不能使用硒,而是出于报废目的,scrapy-splash 更适合。

此外,如果您必须使用 selenium 进行抓取,一个好主意是使用无头选项。你也可以使用铬。我有一些 chrome headless 的基准,有时比 firefox headless 更快。

此外,最好使用具有预期条件的 webdriverwait,而不是更好地睡眠,因为它会等待必要的时间,而不是线程睡眠,这会让您等待提到的时间。

编辑:在尝试回答@QHarr 时添加为编辑,因为答案很长。

这是评估scrapy-splash的建议。

我倾向于使用scrapy,因为整个生态系统都围绕着报废的目的。像中间件、代理、部署、调度、扩展。所以基本上如果你正在寻找一些严重的报废scrapy可能是更好的起始位置。因此,该建议带有警告。

谈到速度,我无法给出任何客观的答案,因为我从来没有从时间角度对任何规模的项目与 selenium 进行对比和基准测试。

但我会或多或少地假设,如果你做同样的事情,你将能够在串行运行中获得可比较的时间。在大多数情况下,您花费的时间是等待响应。

如果您废弃任何相当多的项目,那么您获得的加速通常是通过并行化请求。同样在某些情况下,在没有必要的情况下回退到基本的 http 请求和响应,而不是在任何用户代理中呈现页面。

此外,有趣的是,可以使用底层的 http 请求/响应来执行一些网页内操作。所以时间是一个优先事项,那么您应该寻求通过 http 请求/响应完成尽可能多的事情。


推荐阅读