Как выбрать контекстные слова / символы, окружающие тег <a>, используя BeautifulSoup? - PullRequest
1 голос
/ 10 апреля 2019

Я обрабатываю HTML с веб-сканера, используя BeautifulSoup. HTML-код запускается через фильтры, которые «упрощают» HTML-код, удаляя и заменяя теги, так что документ содержит только теги <html>, body, <div> и <a> и видимый текст.

В настоящее время у меня есть функция, которая в настоящее время извлекает URL-адреса и текст привязки с этих страниц. В дополнение к этому, я хотел бы также извлечь N «контекстных слов», предшествующих и следующих за тегом <a> для каждой ссылки. Например, если у меня есть следующий документ:

<html><body>
<div>This is <a href="www.example.com">a test</a>
<div>There was a big fluffy dog outside the <a href="www.petfood.com">pet food store</a> with such a sad face.<div>
</div>
</body></html>

Тогда, если N = 8, я хочу получить следующие 8 "контекстных слов" для каждой ссылки:

'www.example.com' --> ('This', 'is', 'There', 'was', 'a', 'big', 'fluffy', 'dog')`

'www.petfood.com' --> ('fluffy', 'dog', 'outside', 'the', 'with', 'such', 'a', 'sad')

Первая ссылка (www.example.com) имеет только два слова, предшествующих перед началом начала документа, поэтому возвращаются эти два слова, а также 6 после тега <a>, в результате чего получается N=8. Также обратите внимание, что возвращаемые слова пересекают границу тега <a>, содержащего <div>.

Вторая ссылка (www.petfood.com) имеет N\2 = 4 слова перед ней и 4 после нее, поэтому они возвращаются в качестве контекста. То есть, если возможно, N слов разделяются между предыдущими и теми, которые следуют за тегом <a>.

Я знаю, как это сделать, если текст находится в том же <div>, что и ссылка, но я не могу понять, как сделать это через <div> границы, подобные этой. По сути, для извлечения «контекстных слов» я хочу обработать документ так, как если бы он был просто единым блоком видимого текста со ссылками, игнорируя содержащий div.

Как можно извлечь текст, окружающий теги <a>, как это, используя BeautifulSoup? Для простоты я даже был бы удовлетворен ответом, который просто возвращает N символов видимого текста перед / после тега (и я могу просто справиться с токенизацией / разбиением себя).

1 Ответ

2 голосов
/ 10 апреля 2019

Вот функция, которая принимает весь код HTML и N в качестве входных данных, и для каждого вхождения элемента <a> создает кортеж с URL-адресом ссылки в качестве первого элемента и списком из N контекстных слов в качестве второго элемента.Возвращает кортежи в списке.

def getContext(html,n):
    output = []
    soup = BeautifulSoup(html, 'html.parser')
    for i in soup.findAll("a"):
        n_side = int(n/2)

        text = soup.text.replace('\n',' ')

        context_before = text.split(i.text)[0]
        words_before = list(filter(bool,context_before.split(" ")))

        context_after = text.split(i.text)[1]
        words_after = list(filter(bool,context_after.split(" ")))

        if(len(words_after) >= n_side):
            words_before = words_before[-n_side:]
            words_after = words_after[:(n-len(words_before))]
        else:
            words_after = words_after[:n_side]
            words_before = words_before[-(n-len(words_after)):]

        output.append((i["href"], words_before + words_after))
    return output

Функция анализирует HTML с BeautifulSoup и находит все элементы <a>.Для каждого результата извлекается только текст (с использованием soup.text) и удаляется любой символ новой строки.Весь текст затем разделяется на две части с использованием текста ссылки.Каждая сторона разбирается в список слов, фильтруется, чтобы избавиться от любых пробелов, и разбивается на части так, что извлекается максимум N контекстных слов.

Например:

html = '''<html><body>
<div>This is <a href="www.example.com">a test</a> 
<div>There was a big fluffy dog outside the <a href="www.petfood.com">pet food store</a> with such a sad face.<div>
</div>
</body></html>'''

print(*getContext(html,8))

Выходы:

('www.example.com', ['This', 'is', 'There', 'was', 'a', 'big', 'fluffy', 'dog'])
('www.petfood.com', ['fluffy', 'dog', 'outside', 'the', 'with', 'such', 'a', 'sad'])

Демонстрация: https://repl.it/@glhr/55609756-link-context

Редактировать: обратите внимание, что ловушкой этой реализации является то, что она использует текст ссылки в качестве разделителя, чтобы различать before и after,Это может быть проблемой, если текст ссылки повторяется в документе HTML, где-то перед самой ссылкой, например.

<div>This test is <a href="www.example.com">test</a>

Простой обходной путь - добавить специальные символы в текст ссылки, чтобы сделать его уникальным, например:

def getContext(html,n):
    output = []
    soup = BeautifulSoup(html, 'html.parser')
    for i in soup.findAll("a"):
        i.string.replace_with(f"[[[[{i.text}]]]]")
        # rest of code here

превратит <div>This test is <a href="www.example.com">test</a> в <div>This test is <a href="www.example.com">[[[[test]]]]</a>.

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