Python BeautifulSoup разбирает конкретный текст - PullRequest
0 голосов
/ 09 января 2012

Я анализирую html-файл и хочу найти часть файла, в которой написано «Smaller Reporting Company» и рядом с ней стоит «X» или «Флажок», либо нет. Флажок обычно делается с помощью шрифта Wingdings или кода ASCII. В приведенном ниже HTML-коде вы увидите, что рядом с ним стоит þ.

У меня нет проблем с отображением результатов поиска текста по регулярному выражению, но у меня возникают проблемы при переходе к следующему шагу и поиске флажка.

Я буду использовать это для анализа ряда различных html-файлов, которые не все будут иметь одинаковый формат, но большинство из них будет использовать таблицу и текст ascii, как в этом примере.

Вот код HTML:

<HTML>
<HEAD><TITLE></TITLE></HEAD>
<BODY>
<DIV align="left">Indicate by check mark whether the registrant is a large accelerated filer, an accelerated filer, a non-accelerated filer, or a smaller reporting company. See the definitions of &#147;large accelerated filer,&#148; &#147;accelerated filer&#148; and &#147;smaller reporting company&#148;. (Check one):
</DIV>

<DIV align="center">
<TABLE style="font-size: 10pt" cellspacing="0" border="0" cellpadding="0" width="100%">
<!-- Begin Table Head -->
<TR valign="bottom">
    <TD width="22%">&nbsp;</TD>
    <TD width="3%">&nbsp;</TD>
    <TD width="22%">&nbsp;</TD>
    <TD width="3%">&nbsp;</TD>
    <TD width="22%">&nbsp;</TD>
    <TD width="3%">&nbsp;</TD>
    <TD width="22%">&nbsp;</TD>
</TR>
<TR></TR>
<!-- End Table Head -->
<!-- Begin Table Body -->
<TR valign="bottom">
    <TD align="center" valign="top"><FONT style="white-space: nowrap"> Large accelerated filer <FONT style="font-family: Wingdings">&#111;</FONT></FONT>
    </TD>
    <TD>&nbsp;</TD>
    <TD align="center" valign="top"><FONT style="white-space: nowrap">Accelerated filer <FONT style="font-family: Wingdings">&#111;</FONT></FONT>
    </TD>
    <TD>&nbsp;</TD>
    <TD align="center" valign="top"><FONT style="white-space: nowrap"> Non-accelerated filer <FONT style="font-family: Wingdings">&#111;</FONT> </FONT>
    <FONT style="white-space: nowrap">(Do not check if a smaller reporting company)</FONT>
    </TD>
    <TD>&nbsp;</TD>
    <TD align="center" valign="top"><FONT style="white-space: nowrap"> Smaller reporting company <FONT style="font-family: Wingdings">&#254;</FONT></FONT></TD>
</TR>
<!-- End Table Body -->
</TABLE>
</DIV></BODY></HTML>

Вот мой код Python:

import os, sys, string, re
from BeautifulSoup import BeautifulSoup

rawDataFile = "testfile1.html"
f = open(rawDataFile)
soup = BeautifulSoup(f)
f.close()

search = soup.findAll(text=re.compile('[sS]maller.*[rR]eporting.*[cC]ompany'))
print search

Вопрос: Как я мог настроить это, чтобы иметь второй поиск, который зависит от первого поиска? Поэтому, когда я нахожу «меньшую компанию по отчетности», я могу искать следующие несколько строк, чтобы увидеть, есть ли код ascii? Я просматривал суповые документы. Я пытался найти и найти далее, но я не смог заставить его работать.

Ответы [ 3 ]

0 голосов
/ 09 января 2012

Если вы знаете, что положение крылатого персонажа не изменится, вы можете использовать .next.

>>> nodes = soup.findAll(text=re.compile('[sS]maller.*[rR]eporting.*[cC]ompany'))
>>> nodes[-1].next.next  # last item in list is the only good one... kinda crap
u'&#254;'

Или вы можете подняться, а затем find оттуда:

>>> nodes[-1].parent.find('font',style="font-family: Wingdings").next
u'&#254;'

Или вы можете сделать это наоборот:

>>> soup.findAll(text='&#254;')[0].previous.previous
u' Smaller reporting company '

Предполагается, что вы знаете, какие крылатые символы вы ищете.

У последней стратегии есть дополнительный бонус - отфильтровывать другую хрень, которую ловит ваше регулярное выражение, что, я полагаю, вам не очень нужно; затем вы можете просто просмотреть результаты, зная, что вы работаете только с правильным списком, так что вы можете просмотреть if по своему вкусу.

0 голосов
/ 09 января 2012

lxml имеет допустимый анализатор HTML. Вам не нужен bsoup (который в настоящее время устарел его автором), и вам следует избегать регулярных выражений для анализа HTML.

Вот первый черновой вариант того, что вы ищете:

guff = """\
<HTML>
<HEAD><TITLE></TITLE></HEAD>
[snip]
</DIV></BODY></HTML>
"""
from lxml.html import fromstring
doc = fromstring(guff)
for td_el in doc.iter('td'):
    font_els = list(td_el.iter('font'))
    if not font_els: continue
    print
    for el in font_els:
        print (el.text, el.attrib)

Это производит:

(' Large accelerated filer ', {'style': 'white-space: nowrap'})
('o', {'style': 'font-family: Wingdings'})

('Accelerated filer ', {'style': 'white-space: nowrap'})
('o', {'style': 'font-family: Wingdings'})

(' Non-accelerated filer ', {'style': 'white-space: nowrap'})
('o', {'style': 'font-family: Wingdings'})
('(Do not check if a smaller reporting company)', {'style': 'white-space: nowrap
'})

(' Smaller reporting company ', {'style': 'white-space: nowrap'})
(u'\xfe', {'style': 'font-family: Wingdings'})
0 голосов
/ 09 января 2012

Вы можете попробовать выполнить итерацию по структуре и проверить значения во внутренних тегах или проверить значения во внешних тегах. Я не могу вспомнить, как это сделать, и в итоге я использовал для этого lxml, но я думаю, что bsoup может это сделать.

Если вы не можете получить bsoup, проверьте lxml. Это потенциально быстрее в зависимости от того, что вы делаете. Также есть хуки для использования bsoup с lxml.

...