Получение закладок из chromium-based браузеров с помощью Python
Почти все браузеры, основанные на chromium, хранят закладки похожим образом. Меняются только директории, в которые эти браузеры установлены. Исключением является только Mozilla Firefox. При этом закладки хранятся в открытом виде, так что, любой желающий может получить к ним доступ. Не сказать, чтобы это была супер секретная информация. Но все же, стоило бы продумать этот момент. В данной статье мы рассмотрим код, который в автоматизированном режиме получает все закладки из распространенных браузеров с помощью Python.
Поиск установленных браузеров:
Создадим файл browser_check.py. В нем, напишем код, который будет производить поиск браузеров по пути указанному в одном из словарей.
Импортируем необходимые библиотеки для работы скрипта и определим список, в который будем помещать словари с найденными браузерами:
import os.path import sys from pathlib import Path from bookmarks_find import rec browser = []
Следующим шагом будет создание двух словарей, в которые поместим пути к распространенным браузерам на операционных системах Windows и Linux, так как поиск браузеров будет производиться по путям, которые специфичны для каждой из операционных систем.
win32 = {"Yandex Browser": "~\\AppData\\Local\\Yandex\\YandexBrowser\\User Data\\Default\\Bookmarks", "Google Chrome": "~\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Bookmarks", "Microsoft Edge": "~\\AppData\\Local\\Microsoft\\Edge\\User Data\\Default\\Bookmarks", "Brave Browser": "~\\AppData\\Local\\BraveSoftware\\Brave-Browser\\User Data\\Default\\Bookmarks", "Opera Browser": "~\\AppData\\Roaming\\Opera Software\\Opera Stable\\Default\\Bookmarks", "Vivaldi Browser": "~\\AppData\\Local\\BraveSoftware\\Brave-Browser\\User Data\\Default\\Bookmarks", "Chromium": "~\\AppData\\Local\\Chromium\\User Data\\Default\\Bookmarks"} linux = {"Brave Browser": "~/.config/BraveSoftware/Brave-Browser/Default/Bookmarks", "Google Chrome": "~/.config/google-chrome/Default/Bookmarks", "Yandex Browser": "~/.config/yandex-browser/Default/Bookmarks", "Microsoft Edge": "~/.config/microsoft-edge/Default/Bookmarks", "Opera Browser": "~/.config/opera/Default/Bookmarks", "Vivaldi Browser": "~/.config/vivaldi/Default/Bookmarks", "Chromium": "~/.config/chromium/Default/Bookmarks", "NAVER Whale Browser": "~/.config/naver-whale/Default/Bookmarks", "Slimjet": "~/.config/slimjet/Default/Bookmarks"}
Создадим функцию browser_find(platform: dict) -> None, которая на входе будет получать словарь с путями к закладкам браузеров и проверять их существование. Если путь существует, в объявленный ранее список browser будет добавляться словарь с названием браузера и путем к его закладкам.
def browser_find(platform: dict) -> None: for key, value in platform.items(): if Path(os.path.expanduser(value)).exists(): browser.append({key: os.path.expanduser(value)})
Следует обратить внимание на тот факт, что пути к закладкам браузеров указаны при установке их в директории по умолчанию. Если же пользователь поменял расположение директории с браузером, то он найден не будет.
Двигаемся далее и создадим функцию main, в которой будем определять платформу, на которой запущен скрипт. В принципе, если у вас MacOS, то нужно добавить еще один словарь с путями и условие, в котором определяется ваша система. Но, в данном случае детектируются только две операционные системы: Windows и Linux.
В зависимости от того, какая из систем установлена на компьютере с запущенным скриптом, забираем нужный словарь с путями к закладкам и передаем его в функцию browser_find, которую напишем в отдельном файле.
После этого проверяем, есть ли что-то в списке с браузерами. Если список пуст, выводим сообщение для пользователя, что браузеры не найдены. Если же список не пуст, итерируемся по нему в цикле, забираем словари и получаем название браузера, которое содержится в переменной key и путь к закладкам, содержащийся в переменной value.
def main() -> None: global browser, win32, linux cnt_res = 0 if sys.platform.lower() == "win32": browser_find(win32) elif sys.platform.lower() == "linux": browser_find(linux) if browser: print(f"[+] Найдено браузеров: {len(browser)}") for item in browser: for key, value in item.items(): if res := rec(value): cnt_res += 1 print(f"[+] Найдены закладки для браузера: {key}") with open(f'{key}.txt', 'a', encoding='utf-8') as file: file.write(f"{key}\n\n") for nm, row in enumerate(res): file.write(f"{nm+1} | {row.get("name")} | {row.get("url")}\n") if cnt_res == 0: print("[!] Не удалось получить закладки из найденных браузеров") else: print(f"[!] Закладки сохранены для {cnt_res} браузера(ов)") else: print("[!] Браузеры по стандартным путям установки не найдены") if __name__ == "__main__": main()
Передаем полученное значение в функцию по парсингу json. На самом деле, файл с закладками, это json-файл с достаточно большой структурой вложенности.
В зависимости от того, что вернет функция парсинга, а возвращает она или список со словарями, в которых содержаться полученные значения или False, двигаемся дальше. Если мы получаем список, то открываем файл с названием браузера на запись. Обратите внимание на то, что в данном случае файл открыт в режиме дозаписи, о чем свидетельствует параметр «a». Затем итерируемся по полученному списку, забираем из словарей имена ссылок и сами ссылки, и записываем в текстовый файл.
import os.path import sys from pathlib import Path from bookmarks_find import rec browser = [] win32 = {"Yandex Browser": "~\\AppData\\Local\\Yandex\\YandexBrowser\\User Data\\Default\\Bookmarks", "Google Chrome": "~\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Bookmarks", "Microsoft Edge": "~\\AppData\\Local\\Microsoft\\Edge\\User Data\\Default\\Bookmarks", "Brave Browser": "~\\AppData\\Local\\BraveSoftware\\Brave-Browser\\User Data\\Default\\Bookmarks", "Opera Browser": "~\\AppData\\Roaming\\Opera Software\\Opera Stable\\Default\\Bookmarks", "Vivaldi Browser": "~\\AppData\\Local\\BraveSoftware\\Brave-Browser\\User Data\\Default\\Bookmarks", "Chromium": "~\\AppData\\Local\\Chromium\\User Data\\Default\\Bookmarks"} linux = {"Brave Browser": "~/.config/BraveSoftware/Brave-Browser/Default/Bookmarks", "Google Chrome": "~/.config/google-chrome/Default/Bookmarks", "Yandex Browser": "~/.config/yandex-browser/Default/Bookmarks", "Microsoft Edge": "~/.config/microsoft-edge/Default/Bookmarks", "Opera Browser": "~/.config/opera/Default/Bookmarks", "Vivaldi Browser": "~/.config/vivaldi/Default/Bookmarks", "Chromium": "~/.config/chromium/Default/Bookmarks", "NAVER Whale Browser": "~/.config/naver-whale/Default/Bookmarks", "Slimjet": "~/.config/slimjet/Default/Bookmarks"} def browser_find(platform: dict) -> None: for key, value in platform.items(): if Path(os.path.expanduser(value)).exists(): browser.append({key: os.path.expanduser(value)}) def main() -> None: global browser, win32, linux cnt_res = 0 if sys.platform.lower() == "win32": browser_find(win32) elif sys.platform.lower() == "linux": browser_find(linux) if browser: print(f"[+] Найдено браузеров: {len(browser)}") for item in browser: for key, value in item.items(): if res := rec(value): cnt_res += 1 print(f"[+] Найдены закладки для браузера: {key}") with open(f'{key}.txt', 'a', encoding='utf-8') as file: file.write(f"{key}\n\n") for nm, row in enumerate(res): file.write(f"{nm+1} | {row.get("name")} | {row.get("url")}\n") if cnt_res == 0: print("[!] Не удалось получить закладки из найденных браузеров") else: print(f"[!] Закладки сохранены для {cnt_res} браузера(ов)") else: print("[!] Браузеры по стандартным путям установки не найдены") if __name__ == "__main__": main()
Парсинг закладок из json-файла:
Рассмотрим немного структуру файла, который нам необходимо парсить.
Обратите внимание на ветку «roots», в которой и находятся все закладки. Так как закладки в браузере, это не просто последовательный набор названий и ссылок, то их группировка происходит по директориям создаваемым пользователем. Данные директории имеют название «children» и имеют тип «folder». Также, к примеру, на Панели закладок могут быть как директории с закладками, так и просто закладки для быстрого доступа. Тип закладок без папок «url».
Создадим файл bookmarks_find.py и приступим к написанию кода. Для начала импортируем библиотеки, которые понадобятся в данном скрипте.
Создадим функцию rec(file: str) -> (list, bool), в которую передается путь к закладкам браузера. Возвращает же данная функция список со словарями, в которых содержится имя и url закладки. В случае же, если закладки найти не удалось, возвращается False.
Объявляем список urls, в который будем помещать найденные закладки в виде словарей. Откроем файл с закладками для чтения, поместим его содержимое в переменную roots.
Так как значение данной переменной будет являться словарем, проитерируемся по нему в цикле, указав ветку «roots» в качестве стартовой. Получим ключ и значение и проверим, есть ли в нем название «children». Если да, передаем полученную ветку в функцию process_tree, которую мы создадим чуть позже для обработки. Также передаем в эту функцию список urls. По сути, при передаче списка, если вспомнить его свойства, мы передаем указатель на оригинальный список, так как его копирования в данном случае не происходит. А значит, при его изменении в других функциях измениться и оригинальный словарь.
def rec(file: str) -> (list, bool): urls = [] with open(file, "r", encoding="utf-8") as jsn: roots = json.load(jsn) for key, value in roots["roots"].items(): if "children" in value: process_tree(value["children"], urls) return urls if urls else False
После того, как завершим итерацию по файлу, проверяем, пуст или нет список. Если список не пуст, возвращаем его из функции. Если пуст - возвращаем False.
Теперь создадим функцию process_tree(children_ist: dict, urls: list) -> None, которая получает на входе словарь из полученной директории и указатель на список, в котором будут храниться найденные ссылки в виде словарей.
def process_tree(children_ist: dict, urls: list) -> None: for item in children_ist: process_urls(item, urls) process_folders(item, urls)
Здесь все просто. Данная функция как переходник, в котором мы итерируемся по полученному словарю и передаем полученные значения в следующие функции для обработки.
Создадим функцию process_urls(item: dict, urls: list) -> None, которая на входе получает словарь со значениями и ссылку на список. У данной функции предназначение – выявить ссылки в переданном словаре. Для этого проверяем, есть ли в переданном словаре ключ «type» и является ли его значение «url». Если да, забираем название ссылки и саму ссылку и добавляем в виде словаря в список urls.
def process_urls(item: dict, urls: list) -> None: if "type" in item and item["type"] == "url": urls.append({"name": item['name'], "url": item['url']})
И еще одна функция, которая будет необходима для проверки, не является ли полученный словарь директорией со ссылками «children». Создадим функцию process_folders(item: dict, urls: list) -> None, которая на входе получает словарь со значениями и ссылку на список.
Здесь все тоже просто, проверяем, есть или нет «children» в переданном словаре. Если есть, передаем его рекурсивно в функцию process_tree для дальнейшей обработки.
def process_folders(item: dict, urls: list) -> None: if "children" in item: process_tree(item["children"], urls)
Полный код скрипта:
import json def rec(file: str) -> (list, bool): urls = [] with open(file, "r", encoding="utf-8") as jsn: roots = json.load(jsn) for key, value in roots["roots"].items(): if "children" in value: process_tree(value["children"], urls) return urls if urls else False def process_tree(children_ist: dict, urls: list) -> None: for item in children_ist: process_urls(item, urls) process_folders(item, urls) def process_urls(item: dict, urls: list) -> None: if "type" in item and item["type"] == "url": urls.append({"name": item['name'], "url": item['url']}) def process_folders(item: dict, urls: list) -> None: if "children" in item: process_tree(item["children"], urls)
На этом вроде бы все. Основные скрипты и функции написаны, осталось только проверить, как это будет работать.
Открываем терминал и запускаем скрипт:
В процессе работы скрипт выведет несколько сообщений: о том, сколько было найдено браузеров, для какого из браузеров найдены закладки и для какого количества из найденных закладки сохранены.
Если скрипт найдет браузеры в системе, в директории скрипта будут созданы файлы с названиями найденных браузеров, в которых содержатся закладки.
Как видно на скриншоте, у меня установлено два браузера. Давайте откроем один из файлов и посмотрим на часть его содержимого.
Как видим, закладки найдены. За годы работы в данном браузере их накопилось чуть более 3000. Конечно же, показывать все я не буду, потому, только самое начало, для того, чтобы убедиться, что скрипт работает.
Скрипт работает как на Windows, так и на Linux. Вот скрин с работой скрипта в Fedora Workstation, в которой браузеры установлены по умолчанию, с помощью пакетов.
В данной статье мы научились рекурсивно парсить файл json, узнали, каким способом можно определить операционную систему, установленную на компьютере, а также сохранять данные из json в текстовый файл.
В перспективе, применений данному скрипту можно найти достаточно много. Все зависит только от вашей фантазии.
А на этом все. Спасибо за внимание.