Парсер BeautifulSoup добавляет точки с запятой к голым амперсандам, искажая URL? - PullRequest
7 голосов
/ 25 августа 2011

Я пытаюсь проанализировать какой-то сайт в python, на котором есть ссылки на другие сайты, но в текстовом формате, а не в теге "a". Используя BeautifulSoup я получаю неправильный ответ. Рассмотрим этот код:

import BeautifulSoup

html = """<html>
            <head>
              <title>Test html</title>
            </head>
            <body>
              <div>
                example.com/a.php?b=2&c=15
              </div>
            </body>
          </html>"""

parsed = BeautifulSoup.BeautifulSoup(html)
print parsed

когда я запускаю приведенный выше код, я получаю следующий вывод:

<html>
  <head>
    <title>Test html</title>
  </head>
  <body>
    <div>
      example.com/a.php?b=2&c;=15
    </div>
  </body>
</html>

Обратите внимание на ссылку в "div" и часть b = 2 & c; = 15. Это отличается от оригинального HTML. Почему BeautifulSoup так портится со ссылками. Пытается ли он автоматически создавать HTML-объекты? Как это предотвратить?

1 Ответ

7 голосов
/ 25 августа 2011

Очевидно, что у BS недооцененная проблема при разборе амперсандов внутри URL , я только что искал в их дискуссионном форуме «точка с запятой». Согласно этой дискуссии 2009 года, обнаженная & строго недействительна и должна быть заменена на &amp;, хотя браузеры принимают это, так что кажется, что все в порядке с педантизмом.

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

Обходной путь: В любом случае, ваш обходной путь, скорее всего, будет re.sub(...) для захвата и расширения & -> &amp; только внутри URL-адресов. Возможно, вам нужна обратная функция для сжатия их на выходе. Вам понадобится более красивое регулярное выражение для захвата только амперсандов внутри URL, но в любом случае:

# Minimal string to tickle this
#html = "<html>example.com/a.php?b=2&c=15&d=42</html>"
html = "<html>example.com/a.php?b=2&c=15&amp;d=29&e=42</html>"

html = re.sub(r'&(?!amp;)', r'&amp;', html)

parsed = BeautifulSoup.BeautifulSoup(html)
>>> print parsed.text.encode('utf-8')
'example.com/a.php?b=2&amp;c=15'

>>> re.sub(r'&amp;', r'&', parsed.text.encode('utf-8'))
'example.com/a.php?b=2&c=15'

Могут быть и другие, более BS-тонические подходы. Вы можете помочь протестировать бета-версию 4.0.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...