Найти следующий тег с помощью pyparsing

Я использую pyparsing для анализа HTML. Я беру все теги embed, но в некоторых случаях непосредственно следует тег a, за которым я также хочу захватить, если он доступен.

пример:

import pyparsing
target = pyparsing.makeHTMLTags("embed")[0]
target.setParseAction(pyparsing.withAttribute(src=pyparsing.withAttribute.ANY_VALUE))
target.ignore(pyparsing.htmlComment)

result = target.searchString(""".....
   <object....><embed>.....</embed></object><br /><a href="blah">blah</a>
   """)

Мне не удалось найти какое-либо смещение символов в объектах результата, иначе я мог бы просто взять фрагмент исходной входной строки и работать оттуда.

РЕДАКТИРОВАТЬ:

Кто-то спросил, почему я не использую BeautifulSoup. Это хороший вопрос, позвольте мне показать вам, почему я решил не использовать его, на примере кода:

import BeautifulSoup
import urllib
import re
import socket

socket.setdefaulttimeout(3)

# get some random blogs
xml = urllib.urlopen('http://rpc.weblogs.com/shortChanges.xml').read()

success, failure = 0.0, 0.0

for url in re.compile(r'\burl="([^"]+)"').findall(xml)[:30]:
    print url
    try:
        BeautifulSoup.BeautifulSoup(urllib.urlopen(url).read())
    except IOError:
        pass
    except Exception, e:
        print e
        failure += 1
    else:
        success += 1


print failure / (failure + success)

Когда я пытаюсь это сделать, BeautifulSoup терпит неудачу с ошибками синтаксического анализа 20-30% времени. Это не редкие крайние случаи. pyparsing медленный и громоздкий, но он не взорвался, независимо от того, что я к нему добавляю. Если бы я мог узнать, как лучше использовать BeautifulSoup, мне было бы очень интересно это узнать.


person ʞɔıu    schedule 20.11.2009    source источник
comment
Это очень странно: я использовал ваш точный код, запускал его три раза, и он успешно проанализировал все 90 полученных URL-адресов. Я использую Python 2.5.4 в Windows с BeautifulSoup 3.0.7a. Какие ошибки вы видите?   -  person Ned Batchelder    schedule 20.11.2009
comment
Python 2.5.1 в OS X, BeautifulSoup 3.1.0.1. Наиболее распространенными ошибками являются bad end tag: u"</scr' + 'ipt>" и malformed start tag.   -  person ʞɔıu    schedule 20.11.2009


Ответы (4)


Если есть необязательный тег <a>, который был бы интересен, если бы он следовал за тегом <embed>, добавьте его в шаблон поиска:

embedTag = pyparsing.makeHTMLTags("embed")[0]
aTag = pyparsing.makeHTMLTags("a")[0]
target = embedTag + pyparsing.Optional(aTag)
result = target.searchString(""".....   
    <object....><embed>.....</embed></object><br /><a href="blah">blah</a>
    """)

print result.dump()

Если вы хотите зафиксировать местоположение символа выражения в вашем синтаксическом анализаторе, вставьте один из них с именем результата:

loc = pyparsing.Empty().setParseAction(lambda s,locn,toks: locn)
target = loc("beforeEmbed") + embedTag + loc("afterEmbed") + 
                                                 pyparsing.Optional(aTag)
person PaulMcG    schedule 20.11.2009
comment
Локация работала, но я не мог заставить работать Факультативную вещь. Вы уверены, что образец кода работает? - person ʞɔıu; 20.11.2009
comment
Что ж, этот пример не работает, потому что тег <a> не сразу следует за тегом <embed>. Я не следил за тем, что вы имели в виду под следить. Что вы подразумеваете под следовать? - person PaulMcG; 21.11.2009
comment
В этом примере за тегом embed следует что-то, показанное многоточием, тег close-embed, тег close-object, пустой тег BR и затем тег A. - person PaulMcG; 21.11.2009
comment
Могу ли я сделать что-то вроде embedTag + skipTo (endEmbedTag) + Optional (endObjectTag + brTag + aTag)? - person ʞɔıu; 22.11.2009
comment
embedTag + pyparsing.SkipTo(endEmbedTag, include=True) + pyparsing.Optional(endObjectTag + brTag + aTag) должен работать в этом конкретном случае. Но я не удивлюсь, если в вашем HTML будут другие теги в непредсказуемых местах. Если вы хотите сопоставить тег <embed>, за которым следует тег <a>, это может быть немного более надежным: embedTag + pyparsing.SkipTo(aTag, failOn=embedTag) + aTag | embedTag. В этом случае SkipTo переходит непосредственно к следующему aTag, но терпит неудачу, если первым найден другой embedTag. Но я нахожусь здесь в Чистой Стране Спекуляций, так что вам придется заполнить остальное. - person PaulMcG; 22.11.2009

Зачем вам писать собственный парсер HTML? Стандартная библиотека включает HTMLParser, и BeautifulSoup может справиться с любой задачей, с которой не может справиться HTMLParser.

person Ned Batchelder    schedule 20.11.2009
comment
Я знаю, что такое pyparsing, мне просто интересно, почему вы используете его для грязной работы по разбору HTML, когда существующие специализированные модули уже существуют. - person Ned Batchelder; 20.11.2009
comment
Я обновил вопрос, указав причину, по которой я не использую BeautifulSoup. Краткий ответ: потому что BeautifulSoup получает много ошибок синтаксического анализа, но у меня нет такой же проблемы с pyparsing. Однако, если есть лучший способ использовать BeautifulSoup, о котором я не знаю, или есть что-то еще, что мне не хватает, мне было бы очень интересно узнать об этом. - person ʞɔıu; 20.11.2009

вы не предпочитаете использовать обычное регулярное выражение? или потому что у него дурная привычка парсить html? :D

re.findall("<object.*?</object>(?:<br /><a.*?</a>)?",a)
person YOU    schedule 20.11.2009
comment
все на SO теперь знают, что синтаксический анализ HTML с помощью регулярных выражений является преступлением против Человека; процитировать: stackoverflow.com/questions/1732348/ - person ʞɔıu; 20.11.2009
comment
:D Понятно, это мое первое впечатление за эти 2 дня, когда я тоже присоединился. - person YOU; 20.11.2009
comment
На самом деле я не против использования регулярных выражений как таковых, но я использовал этот подход в прошлом и пытаюсь найти лучший способ. Я мог бы сделать это, но мне все равно нужен/хотелось бы, чтобы синтаксический анализатор анализировал атрибуты HTML и т. д., и я могу в конечном итоге использовать гибридный подход, используя немного обоих. - person ʞɔıu; 20.11.2009

Я смог запустить ваш код BeautifulSoup и не получил никаких ошибок. Я использую BeautifulSoup 3.0.7a.

Пожалуйста, используйте BeautifulSoup 3.0.7a; В версии 3.1.0.1 есть ошибки, из-за которых она вообще не работает в некоторых случаях (например, у вас).

person gibson    schedule 20.11.2009
comment
Добавил бы это как комментарий к первому вопросу, но у меня недостаточно представителей. - person gibson; 20.11.2009