Форум русскоязычного сообщества Ubuntu


Считаете, что Ubuntu недостаточно дружелюбна к новичкам?
Помогите создать новое Руководство для новичков!

Автор Тема: Переименование файлов книг на основе их ISBN номера  (Прочитано 996 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Magi

  • Автор темы
  • Участник
  • *
  • Сообщений: 107
    • Просмотр профиля
Здравствуйте!

Есть сервис, по ISBN коду выдает инфу о книге, например:

http://www.lookupbyisbn.com/Search/Book/9781118688922/1

Есть вот такой кусок html-кода                
<a href="/Lookup/Book/1118688929/978-1-118-68892-2/1" title="Details for Essential Guide to Blood Groups">Essential Guide to Blood Groups</a><br />
                <b>1118688929</b>,&nbsp;
                    <u>Geoff Daniels, Imelda Bromilow</u>
                    <span>,&nbsp;</span>
               <i>Wiley-Blackwell</i>,&nbsp;<i>2013-11-11</i><br />
Вот так можно получить название
wget -qO - http://www.lookupbyisbn.com/Search/Book/9781118688922/1 | grep -Po '(?<=title="Details for )[^"]+' | sed 's/\&[^\;]*./ /g'

Подскажите, как можно распарсить html, чтобы в итоге переменной можно было бы присвоить: Название автор год?
Essential Guide to Blood Groups Geoff Daniels, Imelda Bromilow 2013
« Последнее редактирование: 07 Сентябрь 2018, 14:02:49 от Magi »

Оффлайн zg_nico

  • Заслуженный пользователь
  • Модератор форума
  • Старожил
  • *
  • Сообщений: 3450
  • Nil mortalibus arduum est
    • Просмотр профиля
Re: Парсинг html
« Ответ #1 : 04 Сентябрь 2018, 23:26:02 »
как можно распарсить html
Выбор именно bash чем продиктован в данном случае? Вот пример того, как парсер в общем случае делается на том же pyton. Поддерживается он в ubuntu по сути нативно.
В случае, если Вы по-прежнему хотите использовать bash, то следует применять не wget, а консольный браузер. Например, w3m по аналогии с примером, разобранным и описанным здесь, тогда несколько проще будет выдергивать информацию со страницы. Ссылка, которую Вы привели, у меня не открывается. Из фрагмента кода могу навскидку сказать, что парсировать будет сложно. Только если выдергивать теги <u></u> и <i></i>, после чего первый считать за автора и издательство (опционально - обрезать по запятой), второй - за год выпуска (при условии соответствия формату "ГГГГ-ММ-ДД"). Это все хоть внутри ячейки таблицы сосредоточено, или еще в какой контейнер оформлено (div хотя бы), или просто сплошным текстом на странице не пойми где?
« Последнее редактирование: 04 Сентябрь 2018, 23:37:14 от zg_nico »
Thunderobot G150-D2: Intel SkyLake Core i7-6700HQ 2.60GHz, 8Gb DDR4 2133 MHz, Intel HD530, NVidia GeForce GTX 960M 2Gb.  Ubuntu 16.04 64x [Unity], KUbuntu 18.04 64x.

Оффлайн Magi

  • Автор темы
  • Участник
  • *
  • Сообщений: 107
    • Просмотр профиля
Re: Парсинг html
« Ответ #2 : 04 Сентябрь 2018, 23:36:44 »
Bash я немного знаю, а python вообще нет. Спасибо за наводку с w3m!

Оффлайн zg_nico

  • Заслуженный пользователь
  • Модератор форума
  • Старожил
  • *
  • Сообщений: 3450
  • Nil mortalibus arduum est
    • Просмотр профиля
Re: Парсинг html
« Ответ #3 : 04 Сентябрь 2018, 23:52:07 »
Magi, ссылка открылась. Если зайти в инструменты разработчика в обозревателе, то можно ее пощупать перед построением парсера.
(Нажмите, чтобы показать/скрыть)
Тогда искомое Вами в общем случае:
Код: Javascript
  1. this.window.document.getElementsByTagName('li')[4].getElementsByTagName('a')[0].innerText
Цитировать
"Essential Guide to Blood Groups"
Код: Javascript
  1. this.window.document.getElementsByTagName('li')[4].getElementsByTagName('u')[0].innerText
Цитировать
"Geoff Daniels, Imelda Bromilow"
Код: Javascript
  1. this.window.document.getElementsByTagName('li')[4].getElementsByTagName('i')[1].innerText
Цитировать
"2013-11-11"
При условии сохранения верстки во всех случаях по обозначенному принципу указанные комбинации будут выводить всякий раз правильную информацию. Осталось разобраться как это применить в случае с bash...
Thunderobot G150-D2: Intel SkyLake Core i7-6700HQ 2.60GHz, 8Gb DDR4 2133 MHz, Intel HD530, NVidia GeForce GTX 960M 2Gb.  Ubuntu 16.04 64x [Unity], KUbuntu 18.04 64x.

Оффлайн Azure

  • Модератор раздела
  • Старожил
  • *
  • Сообщений: 6009
  • Windows10, i3wm on Debian9, Manjaro20.0
    • Просмотр профиля
Re: Парсинг html
« Ответ #4 : 05 Сентябрь 2018, 09:44:05 »
Парсить html|xml с помощью bash не очень хорошая идея. Надо брать что-то с нативными библиотеками. Ну или брать что-то из html-xml-utils для этого.
В Линукс можно сделать ВСЁ что угодно, достаточно знать КАК !

Оффлайн zg_nico

  • Заслуженный пользователь
  • Модератор форума
  • Старожил
  • *
  • Сообщений: 3450
  • Nil mortalibus arduum est
    • Просмотр профиля
Re: Парсинг html
« Ответ #5 : 05 Сентябрь 2018, 09:51:03 »
Накидал тут, - интересно стало. Первым делом устанавливаем дополнение для работы с DOM (парсирование HTML и XML):sudo apt install python-beautifulsoupДалее выполняем в терминале команду:
Цитировать
gedit $HOME/Парсер.py
В окне редактора вводим такой код:
Код: Python
  1. #!/usr/bin/env python
  2. #coding=utf-8
  3.  
  4. # подключаемые библиотеки:
  5. from urllib2 import urlopen     #работа с сетью
  6. from bs4 import BeautifulSoup   #работа с DOM
  7. import argparse                 #парсирование аргументов из командной строки
  8.  
  9. # Простейший целевой парсер web-ресурса на языке Python
  10. # Функционал: парсирует ответы ресурса www.lookupbyisbn.com,
  11. # выдергивая Название книги, автора(ов) и год выпуска
  12. # Дополнительно: понимает один URL в виде аргумента командной строки
  13.  
  14. #Сама функция парсирования:
  15. def pars_by_url(url):
  16.     response = urlopen(url)                 #выполняем запрос на сервер
  17.     html = response.read()                  #читаем полученный ответ
  18.     soup = BeautifulSoup(html,"lxml")       #по сути, интерпретируем ответ, формируя коллекцию DOM-элементов
  19.     OurCell = soup.find_all('li')[4]        #находим все теги <li></li> и вытягиваем 4ый элемент полученной коллекции
  20.     #текст гиперссылки (она там одна) в данной ячейке - это название книги
  21.     Book_name = OurCell.find_all('a')[0]
  22.     print "Название книги: ",Book_name.string
  23.     #содержимое тега <u></u> в данной ячейке - это авторы
  24.     Book_author = OurCell.find_all('u')[0]
  25.     print "Автор книги: ",Book_author.string
  26.     #содержимое второго по счету тега <i></i> - это год издания
  27.     Book_year = OurCell.find_all('i')[1]
  28.     print "Год издания:",Book_year.string
  29.     #можно все это в одну строку через разделители пустить - так в том же bash удобнее пользовать будет
  30.     #print "Название|Автор|Год издания"
  31.     #print Book_name.string,"|",Book_author.string,"|",Book_year.string
  32.  
  33. #Сама программа (разбираем аргументы, и вызываем парсер):
  34. def main():
  35.     callWith=argparse.ArgumentParser()                              #контейнер для приема аргументов из командной строки
  36.     callWith.add_argument('--url', help='URL парсируемой страницы') #единственный принимаемый аргумент - URL, куда осуществляется навигация
  37.     args=callWith.parse_args()                                      #вытаскиваем аргумент из командной строки
  38.     try:
  39.         if (args.url == None):                                      #если аргуент не задан. В примере - навигация на строку по-умолчанию      
  40.             pars_by_url("http://www.lookupbyisbn.com/Search/Book/9781118688922/1")
  41.         else:                                                       #если аргумент задан. Воспринимаем его за URL и не проверяя, что не правильно, отсылаем в работу
  42.             pars_by_url(args.url)
  43.     except:
  44.         print "Ошибка выполнения"
  45.  
  46. #вызов главной процедуры
  47. if __name__ == '__main__':
  48.     main()
Сохраняем и закрываем. Далее в том же терминале вводим:python $HOME/Парсер.pyОтветом станет ожидаемое:
Цитировать
Название книги:  Essential Guide to Blood Groups
Автор книги:  Geoff Daniels, Imelda Bromilow
Год издания: 2013-11-11
Если тот же индекс передать в виде параметра командной строки, то сделать это можно, к примеру, так: python $HOME/Парсер.py --url="http://www.lookupbyisbn.com/Search/Book/9781118688922/1"Ответ терминала не изменится. Теперь учитываем:
1. не программировал проверку данных. Совсем никакую. Задайте навигацию на произвольную страницу, где есть все три тега - интересную книгу получите на выходе ))
2. сайт, с которым работаем, достаточно тягомотен. У меня и в браузере-то открывается через раз. Словом, может потребоваться (и вероятно что потребуется) допиливание скрипта до вменяемого состояния в полевых условиях. Но из серии "на коленке для разового применения" - с пивом потянет ))
Примечание: Код писался и тестировался в kubuntu 18.04.1. В иных версиях синтаксис импорта библиотек отличается.
Thunderobot G150-D2: Intel SkyLake Core i7-6700HQ 2.60GHz, 8Gb DDR4 2133 MHz, Intel HD530, NVidia GeForce GTX 960M 2Gb.  Ubuntu 16.04 64x [Unity], KUbuntu 18.04 64x.

Оффлайн aSmile

  • Активист
  • *
  • Сообщений: 745
    • Просмотр профиля
Re: Парсинг html
« Ответ #6 : 05 Сентябрь 2018, 10:45:17 »
wget -qO - http://www.lookupbyisbn.com/Search/Book/9781118688922/1 | grep -Po '(?<=title="Details for )[^"]+' | sed 's/\&[^\;]*./ /g'

Есть знаменитый ответ по поводу парсинга html с помощью regex
https://stackoverflow.com/a/1732454/2814617

Оффлайн Magi

  • Автор темы
  • Участник
  • *
  • Сообщений: 107
    • Просмотр профиля
Re: Парсинг html
« Ответ #7 : 05 Сентябрь 2018, 11:52:32 »
Спасибо! Попробую разобраться :)

Изначально задача стоит найти с помощью pdfgrep в pdf файлах ISBN номер,
Как-то так
pdfgrep -H -o -P --regexp="ISBN(-1(?:(0)|3))?:?\x20(\s)*[0-9]+[- ][0-9]+[- ][0-9]+[- ][0-9]*[- ]*[xX0-9]" --page-range=1-10 --max-count 10 *.pdf | sed -e 's/ISBN//g' -e 's/-10//g' -e 's/-
13//g' -e 's/::/:/g' | tr -d " "| uniq                                                                                                                                                     

"Пробить" его по какой-нибудь базе (есть разные API и базы), а затем на основе полученных данных переименовать файл в "Название Автор год_издания.pdf"
На github'е есть несколько проектов, способных это делать (наиболее работоспособным мне показался вот этот https://github.com/na--/ebook-tools ) Но и он не переименовывает все книги. С русскими особенно плохо.

Далее есть желание сделать каталогизацию книг по тематикам. В многих книгах есть некий идентификатор DNLM, который выглядит примерно так. Что это я не не понял, но в книгах и гугле встречается в связи с медико-биологической тематикой.
Например, вот так.
[DNLM: 1. Hypnosis. 2. Neurotic Disorders—therapy. 3.Dominance, Cerebral. WM 415 P437c 1994]

У меня книги разложены по каталогам с тематиками на русском. Было бы здорово раскладывать их на основе анализа тематики из книги и сопоставления с имеющимся списком. Но там все не точно. В частности книга с таким DNLM

Cameral Analysis - A Method of Treating the Psychoneuroses Using Hypnosis David L. Pedersen 1994

может относится к психиатрии.
Пока я сделал только поиск тематики по книгам.




Оффлайн Magi

  • Автор темы
  • Участник
  • *
  • Сообщений: 107
    • Просмотр профиля
Подскажите, как
С помощью pdfgrep получил вот такой список.

Имя файла:ISBN

354034425X.pdf:354034425X                                                                                                                                                                 
354034425X.pdf:139783540344254                                                                                                                                                             
354040841X.pdf:354040841X                                                                                                                                                                 
354040841X.pdf:139783540408413                                                                                                                                                             
4431012486.pdf:4431012486                                                                                                                                                                 
450873656.pdf:9789244563472                                                                                                                                                               

Подскажите, как можно переименовать файлы на основе данных, полученных вышеописанным скриптом?

Оффлайн zg_nico

  • Заслуженный пользователь
  • Модератор форума
  • Старожил
  • *
  • Сообщений: 3450
  • Nil mortalibus arduum est
    • Просмотр профиля
zg_nico, где выделить всех? мышь труд?:(
Виктор, я Вам уже сто раз говорил: я Вас не понимаю. Потрудитесь излагать свои мысли яснее пожалуйста.
Thunderobot G150-D2: Intel SkyLake Core i7-6700HQ 2.60GHz, 8Gb DDR4 2133 MHz, Intel HD530, NVidia GeForce GTX 960M 2Gb.  Ubuntu 16.04 64x [Unity], KUbuntu 18.04 64x.

Оффлайн peregrine

  • FSM
  • СуперМодератор
  • Старожил
  • *
  • Сообщений: 7163
  • Gentoo x64 Ubuntu 16.04.1 x64
    • Просмотр профиля
zg_nico, перевожу на русский (victor00000 глухонемой, так что его тяжело понять) он возмущается что скрипт не гуевый для мышевозни. Но это оффтопик и немного флуд, так что первое устное для victor00000. За рецидив выпишу плюшек.

Оффлайн zg_nico

  • Заслуженный пользователь
  • Модератор форума
  • Старожил
  • *
  • Сообщений: 3450
  • Nil mortalibus arduum est
    • Просмотр профиля
victor00000, простите. А по поводу мышки - не дозрел я еще до создания графических интерфейсов. Да и вряд ли дозрею - не программист я. Так, пытаюсь иногда что-то писать. Но получается в основном то, что принято называть в среде программистов быдлокодом :)
peregrine, спасибо за пояснение. И простите за этот инцидент. Глупо получилось. Глупо и грязно.
Thunderobot G150-D2: Intel SkyLake Core i7-6700HQ 2.60GHz, 8Gb DDR4 2133 MHz, Intel HD530, NVidia GeForce GTX 960M 2Gb.  Ubuntu 16.04 64x [Unity], KUbuntu 18.04 64x.

Оффлайн ALiEN175

  • Старожил
  • *
  • Сообщений: 3987
  • Capture the truth
    • Просмотр профиля
Код: Bash
  1. while read I ; do
  2. NN=${I##*:}
  3. RN=${I%%:*}
  4. mv -v "$RN" "$NN"
  5. done < file_with_ISBN
ASUS P5K-C :: Intel Xeon E5450 :: 8 GB RAM :: Nvidia 8500GT :: XFCE
SAMSUNG N150 :: Intel Atom N450 :: 2 GB RAM :: Intel GMA3150 :: XFCE

Оффлайн Magi

  • Автор темы
  • Участник
  • *
  • Сообщений: 107
    • Просмотр профиля
Что-то все равно не так
w3m -dump http://www.lookupbyisbn.com/Search/Book/9781405135221/1/
Ок.
Скриптом - ошибка выполнения.

Оффлайн zg_nico

  • Заслуженный пользователь
  • Модератор форума
  • Старожил
  • *
  • Сообщений: 3450
  • Nil mortalibus arduum est
    • Просмотр профиля
Скриптом - ошибка выполнения
Вангую: в скрипте есть необработанное исключение, которое следует за рассматриваемой командой. Срипт-то покажете, или нам всем "ванговать"? :)
Сообразил: Вы мой парсер использовать пытаетесь. Он находит название книги, но не находит больше ничего. А я ведь предупреждал:
может потребоваться (и вероятно что потребуется) допиливание скрипта до вменяемого состояния в полевых условиях
Разница между страницами тыц и тыц, по-Вашему, не ощущается разве? Очевидно, что исходная версия от текущей отличается тем, что автор книги не указан. Иными словами, допустим вариант книги без указания автора, а это в скрипте не учтено. Чтобы учесть достаточно сделать как-то так. Вместо исходного фрагмента
Код: Python
  1.     #содержимое тега <u></u> в данной ячейке - это авторы
  2.     Book_author = OurCell.find_all('u')[0]
  3.     print "Автор книги: ",Book_author.string
  4.     #содержимое второго по счету тега <i></i> - это год издания
внести проверку на ошибку хотя бы (обращаю Ваше внимание на то, что не применяется табуляция для организации отступов, - применяется по 4 подряд идущих пробела вместо табуляции; в синтаксисе python это имеет ключевое значение: интерпретатор по табуляциям понимает где заканчивается тот же самый try:, в остальном коде у меня фигурировала такая табуляция [4 пробела], поэтому и в этом "патче" следует брать именно её; если просто копировали предыдущий код - скопируйте и вставьте этот):
Код: Python
  1.     #содержимое тега <u></u> в данной ячейке - это авторы
  2.     try:
  3.         Book_author = OurCell.find_all('u')[0]
  4.         print "Автор книги: ",Book_author.string
  5.     except:
  6.         print "Автор книги: [не указан]"
  7.     #содержимое второго по счету тега <i></i> - это год издания
Тогда на выходе получаем вместо
Цитировать
Название книги:  The Handbook of Clinical Linguistics
Ошибка выполнения
заветное
Цитировать
Название книги:  The Handbook of Clinical Linguistics
Автор книги: [не указан]
Год издания: 2008-04-28

Пользователь добавил сообщение 11 Сентябрь 2018, 18:41:16:
(Нажмите, чтобы показать/скрыть)
« Последнее редактирование: 11 Сентябрь 2018, 18:41:16 от zg_nico »
Thunderobot G150-D2: Intel SkyLake Core i7-6700HQ 2.60GHz, 8Gb DDR4 2133 MHz, Intel HD530, NVidia GeForce GTX 960M 2Gb.  Ubuntu 16.04 64x [Unity], KUbuntu 18.04 64x.

 

Страница сгенерирована за 0.264 секунд. Запросов: 26.