Уведомления

Группа в Telegram: @pythonsu

#1 Июль 21, 2014 22:03:33

antib
От:
Зарегистрирован: 2010-02-23
Сообщения: 37
Репутация: +  0  -
Профиль   Отправить e-mail  

Python3 FB2, метаданные

Спасибо, это похоже то, что нужно, особенно fb2desc.



ОС - linux mint, Python ver 3.3

Офлайн

#2 Июль 28, 2014 22:07:19

antib
От:
Зарегистрирован: 2010-02-23
Сообщения: 37
Репутация: +  0  -
Профиль   Отправить e-mail  

Python3 FB2, метаданные

Вроде получилось.
Надо будет проверить на fb2 из разных источников - если есть файлы с пустым description и по факту выполняющим его роль annotation, значит возможны и другие закидоны, но в целом заработало. Спасибо за советы.

import xml.etree.ElementTree as et
def check_elem (elem, target, field = None):
	"""Return True if target string found in element children's text attr"""
	if hasattr(elem, "text"):
		if target in str(elem.text).lower():
			if not field:
				return True
			else:
				if field in elem.tag.lower():
					return True
				else:
					print ("close, but no")
		else:
			if len (elem)>0:
				for child in elem:
					x = check_elem(child, target, field=field)
					if x:
						return True
	
def check_descr (fname, target, field = None):
	"""Returns True if target string found in description texts of fb2 file\
	else returns False
	fname - file name
	target - string to find
	field - field name (element.tag), default None (all tags)"""
	tree = et.parse(fname)
	root = tree.getroot()
	#root[0] - description , root[1] - body
	target = target.lower()
	if field:
		field = field.lower()
	if len(root[0])>0:
		print ("Checking description for \'{}\'".format(target))
		for thing in root[0]:
			x=check_elem(thing, target=target, field=field)
			if x:
				return True
	elif len(root[1])>0:
		for thing in root[1]:
			if "annotation" in thing.tag or "title" in thing.tag:
				print ("Checking annotation for \'{}\'".format(target))
				for thing1 in thing:
					x=check_elem(elem=thing1, target=target, field=field)
					if x:
						return True
	else:
		return False



ОС - linux mint, Python ver 3.3

Офлайн

#3 Июль 28, 2014 23:41:44

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10031
Репутация: +  857  -
Профиль   Отправить e-mail  

Python3 FB2, метаданные

antib
if hasattr(elem, "text"):

>>> import xml.etree.ElementTree as et
>>> 
>>> doc = et.fromstring('<x/>')
>>> hasattr(doc, 'text')
True
>>>

antib
if target in str(elem.text).lower():

>>> import xml.etree.ElementTree as et
>>> 
>>> doc = et.fromstring('<x>abc</x>')
>>> doc.text
'abc'
>>> type(doc.text)
<class 'str'>
>>>


>>> import xml.etree.ElementTree as et
>>> 
>>> doc = et.fromstring('<x>abc<y>def1</y><y>def2</y></x>')
>>> 
>>> lst = doc.findall('y')
>>> lst
[<Element 'y' at 0xb73f33c4>, <Element 'y' at 0xb73f3414>]
>>> [i.text for i in lst]
['def1', 'def2']
>>>



Офлайн

#4 Июль 30, 2014 21:11:35

antib
От:
Зарегистрирован: 2010-02-23
Сообщения: 37
Репутация: +  0  -
Профиль   Отправить e-mail  

Python3 FB2, метаданные

Ок, проверка на наличие text лишняя, но уменьшение регистра нужна.

py.user.next
antib

if target in str(elem.text).lower():


>>> import xml.etree.ElementTree as et
>>>
>>> doc = et.fromstring('<x>abc</x>')
>>> doc.text
'abc'
>>> type(doc.text)
<class ‘str’>
>>>

In [1]: import xml.etree.ElementTree as et
In [2]: doc1 = et.fromstring("<x>abc</x>")
In [3]: doc1.text
Out[3]: 'abc'
In [4]: doc2 = et.fromstring("<z>AbC</z>")
In [5]: doc2.text
Out[5]: 'AbC'
In [6]: doc2.text == doc1.text
Out[6]: False
In [7]: doc2.text.lower() == doc1.text
Out[7]: True



ОС - linux mint, Python ver 3.3

Отредактировано antib (Июль 30, 2014 21:19:30)

Офлайн

#5 Июль 30, 2014 23:09:54

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10031
Репутация: +  857  -
Профиль   Отправить e-mail  

Python3 FB2, метаданные

antib
но уменьшение регистра нужна

Это к тому, что text - это уже объект типа str.



Офлайн

#6 Июль 31, 2014 19:44:42

antib
От:
Зарегистрирован: 2010-02-23
Сообщения: 37
Репутация: +  0  -
Профиль   Отправить e-mail  

Python3 FB2, метаданные

Ну да. Я хочу выбирать те fb2, в которых в строках метаданных находится ключевое слово. Я что-то сделал неэффективно?



ОС - linux mint, Python ver 3.3

Офлайн

#7 Июль 31, 2014 23:07:44

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10031
Репутация: +  857  -
Профиль   Отправить e-mail  

Python3 FB2, метаданные

antib
Я что-то сделал неэффективно?

antib
if target in str(elem.text).lower():

В этой строке объект elem.text приводишь к str, когда он и так уже str. Если же он не str, то он типа NoneType - тоже нет смысла приводить к str.

antib
Я хочу выбирать те fb2, в которых в строках метаданных находится ключевое слово.

Нужно выделить сначала данные, а потом проверять их. Так у тебя источник данных отвяжется от fb2. То есть ты сможешь потом вытаскивать данные не только из fb2, но и ещё откуда-нибудь.

Отвязав данные от fb2, ты поймёшь, что не ограничиваешься средствами обработки xml. В данном случае получается, что данные из fb2 ты вытаскиваешь с помощью xml, а проверку данных ты делаешь с помощью re.



Отредактировано py.user.next (Июль 31, 2014 23:11:22)

Офлайн

#8 Авг. 1, 2014 21:58:35

antib
От:
Зарегистрирован: 2010-02-23
Сообщения: 37
Репутация: +  0  -
Профиль   Отправить e-mail  

Python3 FB2, метаданные

py.user.next
В этой строке объект elem.text приводишь к str, когда он и так уже str. Если же он не str, то он типа NoneType - тоже нет смысла приводить к str.

Ну, искать строку в none вызывает ошибку (да, похоже я её так замалчиваю). Может стоит добавить проверку типа данных и при nonetype сравнение не проводить, или делать try/except на предмет TypeError.

py.user.next
Отвязав данные от fb2, ты поймёшь, что не ограничиваешься средствами обработки xml. В данном случае получается, что данные из fb2 ты вытаскиваешь с помощью xml, а проверку данных ты делаешь с помощью re.

Т.е. сначала вытащить все данные из файла, а потом уже их сравнивать. Так оно кажется стройнее, но что по факту мешает проверять их при помощи re сразу же?



ОС - linux mint, Python ver 3.3

Отредактировано antib (Авг. 1, 2014 21:59:35)

Офлайн

#9 Авг. 2, 2014 00:55:03

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10031
Репутация: +  857  -
Профиль   Отправить e-mail  

Python3 FB2, метаданные

antib
Может стоит добавить проверку типа данных и при nonetype сравнение не проводить

if elem.text is not None:

antib
но что по факту мешает проверять их при помощи re сразу же?

То, что ты ограничиваешься re. Программа должна как можно меньше ограничиваться.

А у тебя появляется два ограничения:
1)
Во-первых, ты считаешь, что при нахождении тега обязательно надо сравнивать его текст с чем-то. Это что значит? Что если тебе надо будет просто найти теги, ни с чем ничего не сравнивая, ты не сможешь использовать эту часть кода.

2)
Во-вторых, ты считаешь, что текст нужно сравнивать через re. Это что значит? Что если ты придумаешь способ сравнения, более подходящий, чем re, ты должен будешь редактировать эту часть кода.

В первом случае ты должен будешь писать всё заново.
Во втором случае ты должен будешь проверять поиск заново.



Отредактировано py.user.next (Авг. 2, 2014 13:54:41)

Офлайн

#10 Авг. 3, 2014 19:30:00

antib
От:
Зарегистрирован: 2010-02-23
Сообщения: 37
Репутация: +  0  -
Профиль   Отправить e-mail  

Python3 FB2, метаданные

Это всё в общем случае правильно и интересно к обдумыванию, но реализовывать я это буду уже после того, как доделаю оставшееся. А лучше применю к своей основной поделке, от которой я отвлёкся на fb2. В противном случае решение практического частного случая будет отодвинуто в будущее ради более универсального решения. А то глядишь к поиску просто тегов поттянется создание sqlite базы на все fb2 в папке т.к. надо же их куда-то девать, что бы не искать по всем файлам заново и так далее.



ОС - linux mint, Python ver 3.3

Отредактировано antib (Авг. 3, 2014 19:37:10)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version