【问题标题】:Selenium Firefox Scraping : Takes so much RAM and crashSelenium Firefox Scraping:占用大量内存并崩溃
【发布时间】:2021-03-21 02:22:44
【问题描述】:

转帖原因:没有足够的行为

几天来,我一直在寻找解决问题的方法。 我有一个 python 脚本,它使用 geckodriver 迭代地用 selenium 抓取一个动态网站。 在 2 小时内,它设法获取了我告诉要恢复的所有数据,在这 2 小时结束时,它开始减速并最终崩溃。 崩溃是由于firefox在RAM中的占用引起的。具体来说,脚本抓取的时间越长,Firefox 占用的内存就越多。 我在网上搜索并找到了各种不起作用的解决方案。 如果你能帮我找到能够刮至少 24 小时的解决方案,那你会很酷。

一点代码

binary = FirefoxBinary('/opt/firefox/firefox')

start_time = time.time()
options = Options()
options.add_argument("--headless")
        
firefox_profile = webdriver.FirefoxProfile()
firefox_profile.set_preference("browser.privatebrowsing.autostart", True)


driver=webdriver.Firefox(executable_path="/usr/bin/geckodriver",options=options, firefox_binary=binary, firefox_profile=firefox_profile)
        
driver.get("https:********************************")
        
time.sleep(5)
print("WebSite OPENED ready to connect")
        
def auth(t_end) :
print("entering in auth function")
login_button = driver.find_element_by_xpath("******************").click()
time.sleep(5)
username = driver.find_element_by_xpath("******************")
username.clear()
username.send_keys("*****")
password = driver.find_element_by_xpath("*****************")
password.clear()
password.send_keys("*****")  
driver.find_element_by_xpath("**************").click()
        
time.sleep(5)
print("Connected ready for Scraping")
    
    def scraping(i, t_end) :

print("entering in scraping function")
os.system("free -h && sysctl vm.drop_caches=3 && free -h")
maps = driver.find_elements_by_class_name("************")

t_end = t_end * 3600
t_end = time.time() + t_end
l_a = []
dit_l_a ={}
time.sleep(5)
while time.time() < t_end :
    dict_tempo = {}
    total_a = driver.find_element_by_xpath("***************").text
    if total_a == '0.00' :
        time.sleep(10.5)
        final_a = driver.find_element_by_xpath("**********").text
        l_a.append(final_a)

        history_a1 = driver.find_element_by_xpath('******').text
        scrape = driver.find_element_by_xpath('*******').text
        while scrape == history_a1 : 
            scrape = driver.find_element_by_xpath('****').text
        scrape = scrape.split('\n')
        
        dict_tempo["Final a"] = final_a
        dict_tempo["List Of All a"] = scrape
        now = datetime.datetime.now()
        now = now.strftime("%d/%m/%Y %H:%M:%S")
        dict_tempo["Date"] = now

        dit_l_a[scrape[0]] = dict_tempo

return dit_l_a
for i in range(168):
    print("Interation : ", i)
    try :
      returned_dict = scraping(i, t_end)
      joblib.dump(returned_dict, './returned_dict_' + str(i))
    except Exception as e :
      print(e)
      pass
return returned_dict

if __name__ == '__main__':

    returned_dict = auth(2)

环境:VPS 4GB RAM - CentOS 8 - Python 3.8 - Firefox84Beta - GeckDriver 0.28.0 - 无头抓取

【问题讨论】:

  • 你确定它的 firefox.exe 占用内存吗?你会不断地出现在 l_a 上,这会占用内存#
  • 偶尔关闭并重新打开浏览器可能是个好主意。 driver.close() 关闭选项卡,driver.quit() 退出窗口。
  • @PDHide - 我 100% 认为这是 Firefox 占用内存:/
  • @WBM - 如果我 driver.close() 我将不得不重新加载页面并再次进行身份验证。问题是我正在抓取一个动态网站,我必须能够在至少 24 小时内执行该操作...
  • 实际的错误情况是什么?火狐崩溃?脚本失败了?

标签: python selenium geckodriver


【解决方案1】:

我可以看到您正在使用 Firefox 配置文件,因此您可以按照 Firefox 中的推荐设置配置您的配置文件以使用更少的内存,然后使用它

https://support.mozilla.org/en-US/kb/firefox-uses-too-much-memory-or-cpu-resources

另外

在脚本中尝试添加 3 或 4 秒的隐式等待,这会导致所有命令等待 4 秒,如果未找到或完成元素,则抓取过程会变慢。

还在while和for循环之后添加睡眠:

while time.time() < t_end :
          time.sleep(5)

还有

for i in range(168):
          time.sleep(5)

这导致 firefox 将文件存储在硬盘而不是 RAM 中,如果您不使用 sleep ,浏览器上的 selenium 操作将非常快,而不是 firefox 可以处理的。这导致 firefox 使用更多 RAM 来满足快速需求,因为从 RAM 中的读写操作比硬盘更快

另外添加 driver.close() 这不会主要删除浏览器会话,如果它确实尝试在不同的选项卡中打开 url 并在每 100 次迭代中关闭前一个选项卡或其他东西。这也会释放内存

您可以使用侦听器在每个操作之前添加睡眠

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
import time;

from selenium.webdriver.support.events import EventFiringWebDriver, AbstractEventListener


class MyListener(AbstractEventListener):
    def before_navigate_to(self, url, driver):
        time.sleep(5)
        print("Before navigate to %s" % url)

    def find_element_by_id(self, id_, driver):
        for i in range(10):
            time.sleep(5)
            print("helloooo")
        print("After navigate to %s" % url)

    def after_navigate_to(self, url, driver):
        for i in range(10):
            time.sleep(5)
            print("hi")
        print("After navigate to %s" % url)


tempdriver = webdriver.Chrome()
driver = EventFiringWebDriver(tempdriver, MyListener())
driver.get("http://www.google.co.in/")

driver.find_element_by_id("hi")

阅读:7.37。事件触发 WebDriver 支持

在:https://selenium-python.readthedocs.io/api.html

以上示例仅适用于驱动程序,如果需要,请为 webelement 添加相同的示例。但是在您的情况下,带有 in 循环的 time.sleep() 就绰绰有余了

【讨论】:

  • "...添加 3 或 4 秒的隐式等待,这会导致所有命令等待 4 秒,从而使报废过程变慢" 只有在未找到元素时才会这样。
  • 非常感谢您的回答,明天让我测试一下,我会回来告诉您是否有变化
  • 您好,今天没时间测试,明天试试,给您反馈,谢谢您的回复
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-11
  • 2011-02-27
  • 2013-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多