<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def remove_tags(dirty, allowed_tags=(), allowed_trees=(), strip=None):
 """Selectively remove tags. This removes all tags in ``dirty``, stripping also the contents of tags matching the XPath selector in ``strip``, and keeping all tags that are subtags of tags in ``allowed_trees`` and tags in ``allowed_tags``. Args: dirty(Union[str, scrapy.selector.Selector, lxml.etree._Element]):
 the input to clean up. allowed_tags(Container):
 tags to be kept in the output, but not necessarily its subtags. allowed_trees(Container):
 tags to be kept, along with all its subtags, in the output. strip(str):
 optional xpath selector. If it matches a tag, its contents will also be stripped. Useful axes are ``@`` for attribute access and ``self`` to select a given tag. Returns: str: the textual content of ``dirty``, with some tags kept and some text removed. Examples: u'<b><i>Only</i></b> this text remains.' u'<b>Only</b> this text remains.' u'<b>Only</b> this text remains.' """

    if isinstance(dirty, six.string_types):
        element = etree.fromstring(u''.join(('<DUMMYROOTTAG>', dirty, '</DUMMYROOTTAG>')))
    elif isinstance(dirty, etree._Element):
        element = dirty
    else:  # assuming scrapy Selector
        element = dirty.root

    if element.tag in allowed_trees:
        return etree.tostring(element, encoding='unicode')

    tail = element.tail or u''

    if strip and element.xpath(strip):
        return tail

    subtext = u''.join(
        remove_tags(child, allowed_tags=allowed_tags, allowed_trees=allowed_trees, strip=strip)
        for child in element
    )
    text = element.text or u''

    if element.tag in allowed_tags:
        for child in element:
            element.remove(child)
        element.text = u''.join((text, subtext))
        return etree.tostring(element, encoding='unicode')

    return u''.join((text, subtext, tail))