kshnkvn
@kshnkvn
yay ✌️ t.me/kshnkvn

КМП, или можете, пожалуйста, объяснить как устроены параметры Selenium webdriver?

Лезу в официальную документацию, смотрю как инициализировать webdriver, делаю:
from selenium import webdriver

driver = webdriver.Firefox(firefox_profile='D:\\Develop\\redirect_watotg\\profile.default',
                           executable_path='D:\\Develop\\redirect_watotg\\Lib\\geckodriver.exe')
print(driver.firefox_profile.path)
driver.get('https://web.whatsapp.com/')

Запускаю - работает. Чудеса! Смотрю вывод:
>>> C:\Users\kshnk\AppData\Local\Temp\tmp_mkfpnfj\webdriver-py-profilecopy

Смотрю в ту папку, которую я указал - пустая. Прохожу авторизацию на сайте, закрываю браузер, запускаю заново - нет авторизации. Другого и не ожидал, но все-же.
Лезу в гугл, нахожу ответ в репозитории selenium:
def __init__(self, profile_directory=None):
        """
        Initialises a new instance of a Firefox Profile
        :args:
         - profile_directory: Directory of profile that you want to use. If a
           directory is passed in it will be cloned and the cloned directory
           will be used by the driver when instantiated.
           This defaults to None and will create a new
           directory when object is created.
        """

Понял, с этим все окей. То-есть то, что я указал в атрибуте firefox_profile указывает на то, какой каталог должен использоваться как основа, но сам он задействован не будет, соответственно если он пустой изначально, то он таким и останется, Selenium не будет из временной папки возвращать данные обратно в указанную мною папку (а может есть решение, но я его не нашел). Ищу как поступить. Нашел на сайте mozilla. Попробовал:
from selenium import webdriver
from selenium.webdriver.firefox.options import Options

driver_options = Options()
driver_options.add_argument('-profile')
driver_options.add_argument('D:\\Develop\\redirect_watotg\\profile.default')

driver = webdriver.Firefox(options=driver_options,
                           executable_path='D:\\Develop\\redirect_watotg\\Lib\\geckodriver.exe',
                           service_args=["--marionette-port", "2828"])
print(driver.firefox_profile.path)

Строка print(driver.firefox_profile.path) больше не со мной:
Traceback (most recent call last):
File "D:/Develop/redirect_watotg/main.py", line 22, in
print(driver.firefox_profile.path)
AttributeError: 'NoneType' object has no attribute 'path'

Ну и ладно, удаляю её, запускаю снова - запустилось, смотрю в указанною папку - браузер туда положил все свои рабочие файлы, авторизовываюсь, закрываю браузер, запускаю повторно - авторизация на месте. Супер!
Следующие этап - мне нужен headless режим. Нахожу на все том-же (почти) сайте mozilla, добавляю всего одну строчку:
driver_options.add_argument('-headless')
Проверяю - работает. Все еще супер. Следующее - нужно сделать так, что-бы не загружались css (в идеале) и была возможность скачивать видео-файлы, т.к. на данный момент при нажатии на загрузку вылазит окно с вариантом сохранения, или открытия. Нахожу решение для отключения css и для включения возможности загрузки. Так-же глядя на код вспоминаю о print(driver.firefox_profile.path) и возвращаю его на место, убираю headless, что-бы посмотреть на результат. Итоговый вариант кода:
from selenium import webdriver
from selenium.webdriver.firefox.options import Options, FirefoxProfile


driver_options, driver_profile = Options(), FirefoxProfile()
# driver_options.add_argument('-headless')
driver_options.add_argument('-profile')
driver_options.add_argument('D:\\Develop\\redirect_watotg\\profile.default')
driver_profile.set_preference('permissions.default.stylesheet', 2)
driver_profile.set_preference('browser.download.folderList', 2)
driver_profile.set_preference('browser.download.manager.showWhenStarting', False)
driver_profile.set_preference('browser.download.dir', 'D:\\Develop\\redirect_watotg\\Downloads')
driver_profile.set_preference("browser.download.manager.closeWhenDone", False)
driver_profile.set_preference("browser.download.manager.focusWhenStarting", False)
driver_profile.set_preference('browser.helperApps.neverAsk.saveToDisk', "video/mp4")

driver = webdriver.Firefox(options=driver_options, firefox_profile=driver_profile,
                           executable_path='D:\\Develop\\redirect_watotg\\Lib\\geckodriver.exe',
                           service_args=["--marionette-port", "2828"])

print(driver.firefox_profile.path)
driver.get('https://web.whatsapp.com/')

Запускаю - все css на месте, при попытке загрузки вылазит окно с предложением открыть/сохранить MP4 Video File (VLC). Пока скрипт не останавливаю, иду в папку C:\Users\kshnk\AppData\Local\Temp\tmp_4shdr7q , о которой мне любезно рассказал print(), замечаю, что там всего только один файл, хотя по-идеи туда должны были скопироваться все файлы из указанной мною директории, при этом файл, который там есть (user.js) отсутствует в моей директории. Открываю его, вижу очень много строчек с разными параметрами, а среди них есть и указанные мною:
user_pref("permissions.default.stylesheet", 2);
user_pref("browser.download.folderList", 2);
user_pref("browser.download.manager.showWhenStarting", false);
user_pref("browser.download.dir", "D:\\Develop\\redirect_watotg\\Downloads");
user_pref("browser.download.manager.closeWhenDone", false);
user_pref("browser.download.manager.focusWhenStarting", false);
user_pref("browser.helperApps.neverAsk.saveToDisk", "video/mp4");

Смотрю на ссылку - выглядит странно, меняю на относительный 'Downloads', перезапускаю скрипт - результат тот-же.
На этом моменте я всё, больше ничего не нашел.
Пожалуйста, подскажите в каком моменте (кроме того, когда я решил пытаться в программирование - он очевиден) из всех вышеперечисленных мною я совершил ошибку и неверно интерпретировал найденные мною данные. Как итог у меня два вопроса:
1. Почему не копируются файлы во временную папку (хотя я не думаю, что это критично, но все-же так должно быть)?
2. Почему не работают set_preference()?
3. Чисто бонусом, если вдруг решение прошлых будет найдено - можно-ли проверить статус загрузки, или его название встроенными возможностями selenium, без отсебятины?

Всем спасибо, кто осилил это прочитать и огромное спасибо тем, кто решится помочь.

UPD
В строку
driver_profile.set_preference('browser.helperApps.neverAsk.saveToDisk', "video/mp4")

Добавил все существующие mime-типы - не помогло.

UPD 2
Изучил инспектор кода в Firefox, вкладку сеть - увидел, что при нажатии кнопки "Загрузить" ничего не появляется, но именно при загрузке фрейма с видео есть какой-то application/octet-stream, больше особо ничего, включая video/mp4. Решил добавить его - ничего, решил оставить только его - тоже ничего. Заметил, что при появлении окна открыть/загрузить в источнике "из" указано blob: Может в этом дело? Пошел дальше в гугл.

UPD 3
Так-так-так, методом тыка пришел к выводу, что ломает всю картину все параметры driver_options.add_argument(), убрал из инициализации options=driver_options и вуаля - заработали driver_profile.set_preference(), правда от идеи отключить CSS пришлось отказаться - сайт полностью ломается и скрипт с ним больше работать не может, но настроить загрузку удалось.
Но! Теперь вернулся к своей первоначальной проблеме - как указать директорию профиля, что-бы можно было сохранять сессию, ведь изначально эта директория добавлялась как раз таки функцией driver_options.add_argument().

UPD 4
Так, похоже лажа именно с driver_options.add_argument('-profile') - сам по себе он работает, но из-за него не работает ни один set_preference(), в то время как driver_options.add_argument('-headless') отлично со всеми дружит. Но вскрылась еще беда с set_preference('browser.download.dir', 'sdsadasd') - она не работает. Как вы можете заметить в качестве параметра крайне странный адрес, но функции плевать, что туда не напиши - она загружает все файлы в папку загрузки установленную по умолчанию.
Как итог - все еще актуальна проблема с созданием первоначального профиля и не рабочий параметр указания папки загрузки. В принципе вопрос решаем - тот-же профиль можно тупо после выполнения функции авторизации скопировать в нужную мне папку, а потом подгружать параметром FirefoxProfile('D:/Develop/redirect_watotg/profile.default') - такой вариант работает. Тоже самое можно сделать и с файлов загрузки, только нужно узнать под каким названием он загружается и когда именно он загрузился. Но все-же хотелось-бы разобраться с тем, что дает selenium.
P.S. Аномально огромная активность сегодня на тостере. И да, это уже больше похоже на блог, но я все еще надеюсь, что мне кто-то поможет.

UPD 5
Что-же, мой план провалился на корню - написал я значит две заветные строчки, которые должны были решить мою проблему с сохранением авторизации:
shutil.rmtree('D:/Develop/redirect_watotg/Profile')
shutil.copytree(profile_path, 'D:/Develop/redirect_watotg/Profile/')

Пока не увидел, что после авторизации у меня в папке "Profile" всего один файл - user.js и вспомнил начало истории: указывая папку профиля в FirefoxProfile() произойдет копирование файлов из папки профиля, а указанием папки и последующим созданием в ней файлов профиля занимался driver_options.add_argument(), который в моем случае не работает.
  • Вопрос задан
  • 550 просмотров
Решения вопроса 1
kshnkvn
@kshnkvn Автор вопроса
yay ✌️ t.me/kshnkvn
Итого нашел временные меры:
1. Для сохранения сессии копирую каталог, но т.к. некоторые файлы заняты процессом пришлось оборачивать блоков try-except. Хорошо, что именно файлы отвечающие за сохранение сессии успевают скопироваться, хотя в целом решение так себе:
path_file = open('D:/Develop/redirect_watotg/geckodriver.log')
matches = []
for line in path_file:
    if line.count('rust_mozprofile'):
        matches.append(line)
profile_path = 'C:/Users/kshnk/AppData/Local/Temp/' + matches[-1].split('\"')[-2].split('\\')[-1]
print(profile_path)
shutil.rmtree('D:/Develop/redirect_watotg/Profile')
try:
    shutil.copytree(profile_path, 'D:/Develop/redirect_watotg/Profile/')
except shutil.Error as e:
    print(e)

2. С именем скачанного файла чуть проще:
Перед вызовом функции загрузки файла:
before = os.listdir('D:/Downloads')
И после того, как функция завершила работу:
after = os.listdir('D:/Downloads')
difference = set(after) - set(before)
if len(difference) == 1:
    file_name = difference.pop()
    print(file_name)
    return file_name
else:
    return False


Надеюсь со временем найду более правильные решения, если будет актуально.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
29 мар. 2024, в 10:00
10000 руб./за проект
29 мар. 2024, в 09:59
750 руб./в час
29 мар. 2024, в 09:55
50000 руб./за проект