Почему мое средство для очистки HTML не удаляет теги? - PullRequest
0 голосов
/ 21 марта 2019

Я написал следующий простой 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, но точно сказать не могу.Если это проблема, то какова альтернатива методу, который я пытаюсь использовать здесь?

...