Как изменить lxml autolink, чтобы он был более либеральным? - PullRequest
1 голос
/ 12 апреля 2011

Я использую функцию автоматического связывания из большой библиотеки lxml, как описано здесь: http://lxml.de/api/lxml.html.clean-module.html

Моя проблема заключается в том, что он обнаруживает только те URL-адреса, которые начинаются с http://. Я хотел бычтобы использовать более широкое регулярное выражение для определения URL, как это: http://daringfireball.net/2010/07/improved_regex_for_matching_urls

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

lxml\html\clean.py", line 571, in _link_text
host = match.group('host')
IndexError: no such group

Какие-нибудь гуру Python / Regex, которые знают, как заставить это работать?

Ответы [ 2 ]

2 голосов
/ 12 апреля 2011

Есть две вещи, которые нужно сделать, чтобы адаптировать регулярное выражение к автолинку lxml. Сначала оберните все совпадения с шаблоном URL в группу (?P<body> .. ) - это позволит lxml узнать, что находится внутри атрибута href="".

Далее, оберните хост-часть в группу (?<host> .. ) и передайте параметр avoid_hosts=[] при вызове функции автосвязи. Причиной этого является то, что используемый вами шаблон регулярного выражения не всегда находит хост (иногда часть host будет None), поскольку он соответствует частичным URL-адресам и шаблонам, похожим на URL-адрес.

Я изменил регулярное выражение, включив в него вышеупомянутые изменения, и получил тестовый пример:

import re
import lxml.html
import lxml.html.clean

url_regexp = re.compile(r"""(?i)\b(?P<body>(?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|(?P<host>[a-z0-9.\-]+[.][a-z]{2,4}/))(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))""")

DOC = """<html><body>
    http://foo.com/blah_blah
    http://foo.com/blah_blah/.
    http://www.extinguishedscholar.com/wpglob/?p=364.
    http://✪df.ws/1234
    rdar://1234
    rdar:/1234
    message://%3c330e7f840905021726r6a4ba78dkf1fd71420c1bf6ff@mail.gmail.com%3e
    What about &lt;mailto:gruber@daringfireball.net?subject=TEST&gt; (including brokets).
    bit.ly/foo
</body></html>"""

tree = lxml.html.fromstring(DOC)
body = tree.find('body')
lxml.html.clean.autolink(body, [url_regexp], avoid_hosts=[])
print lxml.html.tostring(tree)

Выход:

<html><body>
    <a href="http://foo.com/blah_blah">http://foo.com/blah_blah</a>
    <a href="http://foo.com/blah_blah/">http://foo.com/blah_blah/</a>.
    <a href="http://www.extinguishedscholar.com/wpglob/?p=364">http://www.extinguishedscholar.com/wpglob/?p=364</a>.
    <a href="http://%C3%A2%C2%9C%C2%AAdf.ws/1234">http://&#226;&#156;&#170;df.ws/1234</a>
    <a href="rdar://1234">rdar://1234</a>
    <a href="rdar:/1234">rdar:/1234</a>
    <a href="message://%3c330e7f840905021726r6a4ba78dkf1fd71420c1bf6ff@mail.gmail.com%3e">message://%3c330e7f840905021726r6a4ba78dkf1fd71420c1bf6ff@mail.gmail.com%3e</a>
    What about &lt;<a href="mailto:gruber@daringfireball.net?subject=TEST">mailto:gruber@daringfireball.net?subject=TEST</a>&gt;
    (including brackets).
    <a href="bit.ly/foo">bit.ly/foo</a>
</body></html>
0 голосов
/ 12 апреля 2011

Вы на самом деле не предоставляете достаточно информации, чтобы быть уверенным, но держу пари, что у вас есть проблемы с обратными слешами в регулярном выражении Грубера. Попробуйте использовать необработанную строку, которая разрешает обратную косую черту без экранирования, и тройные кавычки, которые позволяют вам использовать кавычки в строке без необходимости экранировать их. Э.Г.

re.compile(r"""(?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))""")
...