Подумайте об этом «в шагах» ... учитывая, что некое x
является корнем рассматриваемого вами поддерева
x.findAll(text='price')
- это список всех элементов в этом поддереве, содержащий текст 'price'
. Родители этих предметов тогда, конечно, будут:
[t.parent for t in x.findAll(text='price')]
и если вы хотите оставить только тех, чье "имя" (тег) 'th'
, тогда, конечно,
[t.parent for t in x.findAll(text='price') if t.parent.name=='th']
и вам нужны «ближайшие братья и сестры» из них (но только если они тоже 'th'
с), поэтому
[t.parent.nextSibling for t in x.findAll(text='price')
if t.parent.name=='th' and t.parent.nextSibling and t.parent.nextSibling.name=='th']
Здесь вы видите проблему с использованием понимания списка: слишком много повторений, поскольку мы не можем присвоить промежуточные результаты простым именам. Поэтому давайте переключимся на старый добрый цикл ...:
Редактировать : добавлен допуск для строки текста между родителем th
и «следующим братом», а также допуск для последнего, равный td
вместо этого, для комментария ОП.
for t in x.findAll(text='price'):
p = t.parent
if p.name != 'th': continue
ns = p.nextSibling
if ns and not ns.name: ns = ns.nextSibling
if not ns or ns.name not in ('td', 'th'): continue
print ns.string
Я добавил ns.string
, который будет предоставлять содержимое следующего брата тогда и только тогда, когда они будут просто текстовыми (без дополнительных вложенных тегов) - конечно, вы можете вместо этого анализировать дальше на этом этапе, в зависимости от приложения. потребности -!). Точно так же я представляю, что вы будете делать не просто print
, а что-то более умное, но я даю вам структуру.
Говоря о структуре, обратите внимание, что дважды я использую if...: continue
: это уменьшает вложенность по сравнению с альтернативой инвертирования условия if
и отступа всех следующих операторов в цикле - и "flat лучше, чем nested "- это один из коанов в Zen of Python (import this
в интерактивном режиме, чтобы увидеть их всех и медитировать; -).