Skip to content

Instantly share code, notes, and snippets.

@andmerk93
Last active February 13, 2024 16:19
Show Gist options
  • Save andmerk93/b0ebc144f53467e51db208065574c79a to your computer and use it in GitHub Desktop.
Save andmerk93/b0ebc144f53467e51db208065574c79a to your computer and use it in GitHub Desktop.
Скрипт на Selenium, чтоб скачать книжки в fb2 из своей библиотеки Litres
'''
Скрипт на Selenium, чтоб скачать книжки в fb2
из своей библиотеки Litres.
Скрипт сам не скачивает книги,
только генерит txt-список прямых ссылок.
По списку ссылок потом отлично отрабатывает
плагин DownThemAll для Firefox.
Программа запускает существующую версию firefox,
где уже есть сохранненные логин и пароль,
пристегивает к ней geckodriver, а к нему Selenium.
При падении, завершает процессы, выжидает время,
и автоматически запускает заново.
'''
from datetime import datetime as dt
from subprocess import Popen
import time
from selenium.webdriver import FirefoxOptions, Remote
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import StaleElementReferenceException, TimeoutException
def print_time(num):
'''
Печать в консоль порядкового номера книжки (файла)
и времени выполнения загрузки
'''
print(num, (dt.now() - start_time).seconds, 'sec')
def parse_books_urls(driver, *args):
'''
Функция получения прямых ссылок
на страницы книг из коллекции.
Просто листает страницу до конца,
пока новые элементы появляются.
'''
elems_quantity = 0
elems = 0
while True:
elems = driver.find_elements(By.CLASS_NAME, 'ArtsGrid-module__artWrapper_1j1xJ')
if elems_quantity == len(elems):
elems_quantity = len(elems)
break
elems_quantity = len(elems)
try:
driver.find_element(By.CLASS_NAME, 'MyBooksWrapper-module__content_1NbYR').send_keys(Keys.END)
# Нужно было заменить на конкретный Exception
# Селениума, но я это своевременно не сделал
except Exception:
continue
return elems
def parse_direct_link(driver, url):
'''
Рекурсивная функция, которая получает прямую ссылку
на загрузку книги в fb2.
Рекурсия нужна для повторения в случае ошибки.
'''
driver.get(url)
try:
big_list = [
i.get_attribute('href')
for i in driver.find_elements(By.TAG_NAME, 'a')
]
except StaleElementReferenceException:
print('Got error')
return parse_direct_link(driver, url)
for i in big_list:
if (i is not None) and ('fb2.zip' in i):
return i
return ''
def write_direct_links(driver, elems, start=0):
'''
Функция получает прямые ссылки fb2,
пишет их в консоль и в файл
Переменная start - порядковый номер книжки (файла)
Использовалась при падении браузера, когда отлаживал функцию
'''
with open('parsed_links.txt', '+a') as file:
for num, url in enumerate(elems[start:]):
print_time(num + start)
link = parse_direct_link(driver, url)
file.write(link + '\n')
def runner(func, elems=[]):
firefox = Popen(
('C:\\Program Files\\Mozilla Firefox\\firefox.exe', '-start-debugger-server', '2828', '-marionette')
)
geckodriver = Popen(
('D:\\python\\geckodriver.exe', '--connect-existing', '--marionette-port', '2828')
)
driver = Remote(
command_executor='http://127.0.0.1:4444',
options=FirefoxOptions()
)
driver.get('https://www.litres.ru/my-books/purchased/')
driver.implicitly_wait(0.5)
try:
func(driver, elems)
except TimeoutException:
geckodriver.terminate()
firefox.terminate()
print('Im fall :(')
time.sleep(300)
if __name__ == '__main__':
time.sleep(0)
start_time = dt.now()
book_urls = runner(parse_books_urls)
runner(write_direct_links, book_urls)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment