python - 使用 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
解决方案
对于动态网页(使用 javascript 渲染或增强的页面),我建议您使用scrapy-splash
并不是说您不能使用硒,而是出于报废目的,scrapy-splash 更适合。
此外,如果您必须使用 selenium 进行抓取,一个好主意是使用无头选项。你也可以使用铬。我有一些 chrome headless 的基准,有时比 firefox headless 更快。
此外,最好使用具有预期条件的 webdriverwait,而不是更好地睡眠,因为它会等待必要的时间,而不是线程睡眠,这会让您等待提到的时间。
编辑:在尝试回答@QHarr 时添加为编辑,因为答案很长。
这是评估scrapy-splash的建议。
我倾向于使用scrapy,因为整个生态系统都围绕着报废的目的。像中间件、代理、部署、调度、扩展。所以基本上如果你正在寻找一些严重的报废scrapy可能是更好的起始位置。因此,该建议带有警告。
谈到速度,我无法给出任何客观的答案,因为我从来没有从时间角度对任何规模的项目与 selenium 进行对比和基准测试。
但我会或多或少地假设,如果你做同样的事情,你将能够在串行运行中获得可比较的时间。在大多数情况下,您花费的时间是等待响应。
如果您废弃任何相当多的项目,那么您获得的加速通常是通过并行化请求。同样在某些情况下,在没有必要的情况下回退到基本的 http 请求和响应,而不是在任何用户代理中呈现页面。
此外,有趣的是,可以使用底层的 http 请求/响应来执行一些网页内操作。所以时间是一个优先事项,那么您应该寻求通过 http 请求/响应完成尽可能多的事情。
推荐阅读
- swift - 为什么 swift 中的中缀运算符不起作用?
- python - 需要帮助理解这个 python 深度优先搜索代码
- json - 尝试删除创建的 API 时页面过期
- c - 无法生成“gcc”。它是否已安装并在您的路径上?
- html - 此路由不支持 post 方法
- sql - 如何解决嵌套在postgres sql中的聚合函数问题
- javascript - 在更改事件中获取单击的单选按钮 Id
- javafx - 通过另一个控制器更改组合框的值不会触发 JavaFX 中的 onAction 回调
- python - VGGnet 在训练时不学习
- xml - 从一个 XML 标记中获取值并使用 XSLT 放入另一个标记?