首页 > 解决方案 > Selenium Firefox Scraping:占用大量内存并崩溃

问题描述

转发原因:没有足够的期望行为

几天来,我一直在寻找解决问题的方法。我有一个 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 - 无头抓取

标签: pythonseleniumgeckodriver

解决方案


我可以看到您正在使用 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() 绰绰有余


推荐阅读