Всех нас на работе то и дело пытаются заставить писать юнит-тесты. Многие уже поняли, что от них один вред. Написание тестов отнимает много времени, за которое вы могли бы сделать что-то более полезное. Если тест неожиданно начинает падать, ломается сборка на сервере непрерывной интеграции, не выкатывается вовремя релиз, бизнес теряет деньги и крайним оказываетесь вы, автор упавшего юнит-теста. При рефакторинге тесты причиняют головную боль, потому что начинают падать и приходится с этим разбираться.
Тем не менее злые начальники требуют больше тестов, говоря о так называемом «контроле качества». Особо хитрые менеджеры даже считают покрытие и не отпускают вас с работы, пока оно не будет достигнуто. Ваш код заворачивают на ревью, если в нём нет тестов или они чем-то не понравились. Сплошное расстройство!
Пытаюсь написать парсер на питоне, используя селениум. Суть парсера в том, что нужно сначал повытаскивать url-адреса (их около 50 000). А потом уже парсить данные из каждой страницы.
Столкнулся с проблемой. Пытался выставлять тайминги до 10 секунд - не помогло. Самое интересное, что эта ошибка появляется постоянно в разных местах. По-моему, во всех случаях она была связана с выпадающим списком. Тут список довольно непростой. Вот его особенности.
1. Список открывается при наведении на него мышью.
2. Для того, чтобы получить url каждого пункта я навожу на него, кликаю на пункт меню, вытаскиваю url.
2.1. Каждый пункт списка состоит из подпунктов. Они видны (просто в зависимости от выбранного меню у них меняется id). Я кликаю по ним, вытаскиваю url (без наведения), после чего навожу на список и перехожу к следующему пункту. И так цикл повторяется.
3. Изначльно список состоит из 6 пунктов (по дефолту в списке стоит значение Default). Но при клике на пункт меню он исчезает из списка и соответственно их там становится 5.
Вот мой код
#Пункты из выпадающего меню
a_list_text = []
li_more = ul_nav.find_element_by_css_selector('li.r.more')
ActionChains(driver).move_to_element(li_more).perform()
a_more_list = li_more.find_elements_by_css_selector('div > div > p > a')
#Добавляем пункты в список
for a_more in a_more_list:
a_list_text.append(a_more.text)
#Проходим по пунктам
for a in a_list_text:
li_more = ul_nav.find_element_by_css_selector('li.r.more')
ActionChains(driver).move_to_element(li_more).perform()
#Создаём ещё один список с пунктами из меню
a_more_list = li_more.find_elements_by_css_selector('div > div > p > a')
for a_more_ in a_more_list:
#Так как пункты в списке меняются местами, сверяем равен ли текущий пункт выбранному. Если да, запускаем цикл, если нет - переходим к следкющему
if a == a_more_.text:
a_more_.click()
# time.sleep(2)
print(driver.current_url)
#Вытаскиваем подпункты
more_sub_ul_nav = driver.find_element_by_css_selector("ul.sub-menu.subactive[style='display: block;']")
more_sub_a_more_list = more_sub_ul_nav.find_elements_by_css_selector('li > a')
#Проходим по подпунктам (они видны, без наведения)
for more_sub_a_more in more_sub_a_more_list:
more_sub_a_more.click()
# time.sleep(2)
print(driver.current_url)
#Когда прошли по все подпунктам - обрываем цикл и переходим к следующему пункту
break
Traceback (most recent call last):
File "all_links.py", line 90, in <module>
count += parse(driver, 'https://****' + link_match.get("href"), count)
File "all_links.py", line 48, in parse
a_list_text.append(a_more.text)
File "/home/m0nte-cr1st0/.local/lib/python3.7/site-packages/selenium/webdriver/remote/webelement.py", line 76, in text
return self._execute(Command.GET_ELEMENT_TEXT)['value']
File "/home/m0nte-cr1st0/.local/lib/python3.7/site-packages/selenium/webdriver/remote/webelement.py", line 633, in _execute
return self._parent.execute(command, params)
File "/home/m0nte-cr1st0/.local/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "/home/m0nte-cr1st0/.local/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.StaleElementReferenceException: Message: The element reference of <a href=""> is stale; either the element is no longer attached to the DOM, it is not in the current frame context, or the document has been refreshed
В принципе, можно как-то try/except прикрутить, наверное. Я пробовал, но было 2 проблемы:
1. "Съедались" некоторые ссылки (видимо, неверно except настроил)
2. Всё-равно вылетала ошибка спустя какое-то время (видимо, неверно try вставил)
Уже который день пытаюсь побороть проблему - не получается. Может, кто-то что-то подскажет?.. Не знаю, куда ещё обратиться(