Токенизация и маркировка исходного кода HTML с использованием Python - PullRequest
1 голос
/ 22 апреля 2019

У меня есть некоторый аннотированный исходный код HTML, где код похож на то, что вы получите, используя requests, а аннотации представляют собой метки с индексом символов, с которого начинается помеченный элемент, и

Например,исходный код может быть:

<body><text>Hello world!</text><text>This is my code. And this is a number 42</text></body>

, а метки могут быть, например:

[{'label':'salutation', 'start':12, 'end':25},
 {'label':'verb', 'start':42, 'end':45},
 {'label':'size', 'start':75, 'end':78}]

Ссылаясь на слова «Hello world», «is» и «42» соответственно.Мы заранее знаем, что метки не перекрываются.

Я хочу обработать исходный код и аннотации для получения списка токенов, подходящих для формата HTML.

Например, это можетсоздайте здесь что-то вроде этого:

['<body>', '<text>', 'hello', 'world', '</text>', '<text>', 'this', 'is', 'my', 'code', 'and', 'this', 'is', 'a', 'number', '[NUMBER]', '</text>', '</body>']

Кроме того, он должен сопоставить аннотации с токенизацией, создав последовательность меток той же длины, что и токенизация, например:

['NONE', 'NONE', 'salutation', 'salutation', 'NONE', 'NONE', 'NONE', 'verb', 'NONE', 'NONE', 'NONE', 'NONE', 'NONE', 'NONE', 'NONE', 'size', 'NONE', 'NONE']

Какой самый простой способ сделать это в Python?

Ответы [ 2 ]

1 голос
/ 22 апреля 2019

Вы можете использовать рекурсию с BeautifulSoup для создания списка всех тегов и содержимого, которые затем можно использовать для соответствия меткам:

from bs4 import BeautifulSoup as soup
import re
content = '<body><text>Hello world!</text><text>This is my code. And this is a number 42</text></body>'
def tokenize(d):
  yield f'<{d.name}>'
  for i in d.contents:
     if not isinstance(i, str):
       yield from tokenize(i)
     else:
       yield from i.split()
  yield f'</{d.name}>'

data = list(tokenize(soup(content, 'html.parser').body))

Вывод:

['<body>', '<text>', 'Hello', 'world!', '</text>', '<text>', 'This', 'is', 'my', 'code.', 'And', 'this', 'is', 'a', 'number', '42', '</text>', '</body>']

Затем, чтобы соответствовать меткам:

labels = [{'label':'salutation', 'start':12, 'end':25}, {'label':'verb', 'start':42, 'end':45}, {'label':'size', 'start':75, 'end':78}] 
tokens = [{**i, 'word':content[i['start']:i['end']-1].split()} for i in labels]
indices = {i:iter([[c, c+len(i)+1] for c in range(len(content)) if re.findall('^\W'+i, content[c-1:])]) for i in data}  
new_data = [[i, next(indices[i], None)] for i in data]
result = [(lambda x:'NONE' if not x else x[0])([c['label'] for c in tokens if b and c['start'] <= b[0] and b[-1] <= c['end']]) for a, b in new_data]

Вывод:

['NONE', 'NONE', 'salutation', 'salutation', 'NONE', 'NONE', 'NONE', 'verb', 'NONE', 'NONE', 'NONE', 'NONE', 'NONE', 'NONE', 'NONE', 'size', 'NONE', 'NONE']
0 голосов
/ 22 апреля 2019

Пока я сделал эту работу, используя HTMLParser:

from html.parser import HTMLParser
from tensorflow.keras.preprocessing.text import text_to_word_sequence

class HTML_tokenizer_labeller(HTMLParser):
  def __init__(self, annotations, *args, **kwargs):
    super(HTML_tokenizer_labeller, self).__init__(*args, **kwargs)
    self.tokens = []
    self.labels = []
    self.annotations = annotations

  def handle_starttag(self, tag, attrs):
    self.tokens.append(f'<{tag}>')
    self.labels.append('OTHER')

  def handle_endtag(self, tag):
    self.tokens.append(f'</{tag}>')
    self.labels.append('OTHER')

  def handle_data(self, data):
    print(f"getpos = {self.getpos()}")
    tokens = text_to_word_sequence(data)

    pos = self.getpos()[1]
    for annotation in annotations:
      if annotation['start'] <= pos <= annotation['end']:
        label = annotation['tag']
        break
    else: label = 'OTHER'

    self.tokens += tokens
    self.labels += [label] * len(tokens)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...