code: def get_html_tree(html):
      
  
      parser = lxml.html.HTMLParser(encoding='utf-8')
      html = html.encode('utf8')
  
      try:
          tree = lxml.html.fromstring(html, parser=parser)
      except lxml.etree.Error:
          # E.g. empty document. Use dummy <div>
          tree = lxml.html.fromstring('<div></div>')
  
      # If the document doesn't start with a top level tag, wrap it with a <div>
      # that will be later stripped out for consistent behavior.
      if tree.tag not in lxml.html.defs.top_level_tags:
          html = b'<div>%s</div>' % html
          tree = lxml.html.fromstring(html, parser=parser)
  
      # HACK for Outlook emails, where tags like <o:p> are rendered as <p>. We
      # can generally ignore these tags so we replace them with <span>, which
      # doesn't cause a line break. Also, we can't look up the element path of
      # tags that contain colons. When rendering the tree, we will restore the
      # tag name.
      for el in tree.iter():
          if el.nsmap or (isinstance(el.tag, string_class) and ':' in el.tag):
              if el.nsmap:
                  actual_tag_name = '{}:{}'.format(list(el.nsmap.keys())[0], el.tag)
              else:
                  actual_tag_name = el.tag
              el.tag = 'span'
              el.attrib['__tag_name'] = actual_tag_name
  
      return tree
docs: Given the HTML string, returns a LXML tree object. The tree is wrapped in
      <div> elements if it doesn't have a top level tag or parsing would
      otherwise result in an error. The wrapping can be later removed with
      strip_wrapping().