Почему мое средство очистки HTML не удаляет теги?

#python #html #web-scraping #beautifulsoup #html-sanitizing

#python #HTML #очистка веб-страниц #beautifulsoup #html-очистка

Вопрос:

Я написал следующий простой HTML-фильтр, используя requests и BeautifulSoup , который должен принимать список разрешенных тегов и атрибутов и удаляет любые теги, которых нет в списке:

 def filter_tags(soup, tags_to_keep, allowed_attrs=None):

    for tag in soup.body.descendants:
        if tag.name in tags_to_keep:
            new_attrs = dict()
            for k,v in tag.attrs.items():
                if allowed_attrs and k in allowed_attrs:
                    new_attrs[k] = v
            tag.attrs = new_attrs

        elif isinstance(tag, NavigableString):
            continue

        else:
            # insert one whitespace char so words on either side of tag aren't concat'ed together
            tag.insert_before(" ")
            tag.decompose()

    return soup
  

Я вызываю функцию следующим образом: soup = filter_tags(soup, tags_to_keep=['html', 'body', 'div', 'a'], allowed_attrs=['href']) .

Эта функция, похоже, работает для простых входных данных, подобных этому:

 <body>
    <div id="cats">
        This is a test
        <a href="http://www.google.com">Google!</a> 
        More text
    </div>
    <div>
        More text
        <script>...oh javascript...</script>
    </div>
</body>
  

Под «работает» я подразумеваю, что оно корректно удаляет теги <script> и <img> и id= атрибут, сохраняя при этом указанные теги и href= attr), поэтому впоследствии это выглядит так:

 <body>
    <div>
        This is a test
        <a href="http://www.google.com">Google!</a> 
        More text
    </div>
    <div>
        More text
    </div>
</body>
  

Однако для более сложного HTML он полностью завершается ошибкой (примером страницы, которая завершается ошибкой, является http://www.cnn.com ), И <script> Теги, атрибуты тегов и т.д. Не Удаляются из HTML. Я получаю вывод, подобный этому:

 import requests
from bs4 import BeautifulSoup
soup = BeautifulSoup(requests.get('http://www.cnn.com').text, 'lxml')
filter_tags(soup, tags_to_keep=['body', 'a', 'div'], allowed_attrs=['href'])

              |
              |
              V    

... <li class="m-legal__list__item last-child">
<a class="m-legal__links" data-analytics="footer_cnn-newsource" href="http://cnnnewsource.com">CNN Newsource</a></li>
</ul></div></div></div></div></div></footer>
<div class="OUTBRAIN" data-ob-template="cnn" data-src="" data-widget-id="TR_1"></div>
 <script>(function (d) ...
  

Как вы можете видеть, он не удаляет ни один из тегов / атрибутов, таких как <script> или class= в более сложном HTML, подобном этому, но я не могу понять, почему, основываясь на моих простых тестах, где это, кажется, работает нормально…

Что не так с моей функцией выше, из-за чего ей не удается удалить теги / атрибуты для сложного HTML? Моя интуиция заключается в том, что это может быть как-то связано с изменением дерева DOM с помощью .decompose() по мере прохождения .descendants , но я не могу сказать наверняка. Если проблема в этом, какова альтернатива методу, который я пытаюсь использовать здесь?

Комментарии:

1. какую библиотеку вы используете для получения HTML-содержимого CNN? запросы?

2. Да, я использую requests и BeautifulSoup . Извините, я уточню это в основном сообщении. Однако я вручную проверил HTML из www.cnn.com , и requests правильно загружает его. filter_html() Функция просто не удаляет из нее другие подобные <script> теги, хотя она удаляет их для простого примера выше.

3. да, только что протестировал его на своем компьютере, и я получаю ту же проблему. Надеюсь, кто-нибудь сможет помочь.

4. Кажется, .descendants что оно не возвращает дочерние теги глубже одного уровня, попробуйте .find_all() .

5. т.М. Адам — Из документов bs4 для .descendants : » Атрибут .descendants позволяет вам рекурсивно перебирать все дочерние элементы тега: его прямые дочерние элементы, дочерние элементы его прямых дочерних элементов и так далее «.