BeautifulSoup4 python 3
This commit is contained in:
+55
-55
@@ -21,22 +21,22 @@ def _alias(attr):
|
||||
return alias
|
||||
|
||||
|
||||
class NamespacedAttribute(unicode):
|
||||
class NamespacedAttribute(str):
|
||||
|
||||
def __new__(cls, prefix, name, namespace=None):
|
||||
if name is None:
|
||||
obj = unicode.__new__(cls, prefix)
|
||||
obj = str.__new__(cls, prefix)
|
||||
elif prefix is None:
|
||||
# Not really namespaced.
|
||||
obj = unicode.__new__(cls, name)
|
||||
obj = str.__new__(cls, name)
|
||||
else:
|
||||
obj = unicode.__new__(cls, prefix + ":" + name)
|
||||
obj = str.__new__(cls, prefix + ":" + name)
|
||||
obj.prefix = prefix
|
||||
obj.name = name
|
||||
obj.namespace = namespace
|
||||
return obj
|
||||
|
||||
class AttributeValueWithCharsetSubstitution(unicode):
|
||||
class AttributeValueWithCharsetSubstitution(str):
|
||||
"""A stand-in object for a character encoding specified in HTML."""
|
||||
|
||||
class CharsetMetaAttributeValue(AttributeValueWithCharsetSubstitution):
|
||||
@@ -47,7 +47,7 @@ class CharsetMetaAttributeValue(AttributeValueWithCharsetSubstitution):
|
||||
"""
|
||||
|
||||
def __new__(cls, original_value):
|
||||
obj = unicode.__new__(cls, original_value)
|
||||
obj = str.__new__(cls, original_value)
|
||||
obj.original_value = original_value
|
||||
return obj
|
||||
|
||||
@@ -70,9 +70,9 @@ class ContentMetaAttributeValue(AttributeValueWithCharsetSubstitution):
|
||||
match = cls.CHARSET_RE.search(original_value)
|
||||
if match is None:
|
||||
# No substitution necessary.
|
||||
return unicode.__new__(unicode, original_value)
|
||||
return str.__new__(str, original_value)
|
||||
|
||||
obj = unicode.__new__(cls, original_value)
|
||||
obj = str.__new__(cls, original_value)
|
||||
obj.original_value = original_value
|
||||
return obj
|
||||
|
||||
@@ -152,7 +152,7 @@ class PageElement(object):
|
||||
|
||||
def format_string(self, s, formatter='minimal'):
|
||||
"""Format the given string using the given formatter."""
|
||||
if not callable(formatter):
|
||||
if not isinstance(formatter, collections.Callable):
|
||||
formatter = self._formatter_for_name(formatter)
|
||||
if formatter is None:
|
||||
output = s
|
||||
@@ -272,7 +272,7 @@ class PageElement(object):
|
||||
def insert(self, position, new_child):
|
||||
if new_child is self:
|
||||
raise ValueError("Cannot insert a tag into itself.")
|
||||
if (isinstance(new_child, basestring)
|
||||
if (isinstance(new_child, str)
|
||||
and not isinstance(new_child, NavigableString)):
|
||||
new_child = NavigableString(new_child)
|
||||
|
||||
@@ -489,7 +489,7 @@ class PageElement(object):
|
||||
result = (element for element in generator
|
||||
if isinstance(element, Tag))
|
||||
return ResultSet(strainer, result)
|
||||
elif isinstance(name, basestring):
|
||||
elif isinstance(name, str):
|
||||
# Optimization to find all tags with a given name.
|
||||
result = (element for element in generator
|
||||
if isinstance(element, Tag)
|
||||
@@ -640,7 +640,7 @@ class PageElement(object):
|
||||
return self.parents
|
||||
|
||||
|
||||
class NavigableString(unicode, PageElement):
|
||||
class NavigableString(str, PageElement):
|
||||
|
||||
PREFIX = ''
|
||||
SUFFIX = ''
|
||||
@@ -653,15 +653,15 @@ class NavigableString(unicode, PageElement):
|
||||
passed in to the superclass's __new__ or the superclass won't know
|
||||
how to handle non-ASCII characters.
|
||||
"""
|
||||
if isinstance(value, unicode):
|
||||
return unicode.__new__(cls, value)
|
||||
return unicode.__new__(cls, value, DEFAULT_OUTPUT_ENCODING)
|
||||
if isinstance(value, str):
|
||||
return str.__new__(cls, value)
|
||||
return str.__new__(cls, value, DEFAULT_OUTPUT_ENCODING)
|
||||
|
||||
def __copy__(self):
|
||||
return self
|
||||
|
||||
def __getnewargs__(self):
|
||||
return (unicode(self),)
|
||||
return (str(self),)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
"""text.string gives you text. This is for backwards
|
||||
@@ -701,23 +701,23 @@ class PreformattedString(NavigableString):
|
||||
|
||||
class CData(PreformattedString):
|
||||
|
||||
PREFIX = u'<![CDATA['
|
||||
SUFFIX = u']]>'
|
||||
PREFIX = '<![CDATA['
|
||||
SUFFIX = ']]>'
|
||||
|
||||
class ProcessingInstruction(PreformattedString):
|
||||
|
||||
PREFIX = u'<?'
|
||||
SUFFIX = u'?>'
|
||||
PREFIX = '<?'
|
||||
SUFFIX = '?>'
|
||||
|
||||
class Comment(PreformattedString):
|
||||
|
||||
PREFIX = u'<!--'
|
||||
SUFFIX = u'-->'
|
||||
PREFIX = '<!--'
|
||||
SUFFIX = '-->'
|
||||
|
||||
|
||||
class Declaration(PreformattedString):
|
||||
PREFIX = u'<!'
|
||||
SUFFIX = u'!>'
|
||||
PREFIX = '<!'
|
||||
SUFFIX = '!>'
|
||||
|
||||
|
||||
class Doctype(PreformattedString):
|
||||
@@ -734,8 +734,8 @@ class Doctype(PreformattedString):
|
||||
|
||||
return Doctype(value)
|
||||
|
||||
PREFIX = u'<!DOCTYPE '
|
||||
SUFFIX = u'>\n'
|
||||
PREFIX = '<!DOCTYPE '
|
||||
SUFFIX = '>\n'
|
||||
|
||||
|
||||
class Tag(PageElement):
|
||||
@@ -843,7 +843,7 @@ class Tag(PageElement):
|
||||
for string in self._all_strings(True):
|
||||
yield string
|
||||
|
||||
def get_text(self, separator=u"", strip=False,
|
||||
def get_text(self, separator="", strip=False,
|
||||
types=(NavigableString, CData)):
|
||||
"""
|
||||
Get all child strings, concatenated using the given separator.
|
||||
@@ -915,7 +915,7 @@ class Tag(PageElement):
|
||||
def __contains__(self, x):
|
||||
return x in self.contents
|
||||
|
||||
def __nonzero__(self):
|
||||
def __bool__(self):
|
||||
"A tag is non-None even if it has no contents."
|
||||
return True
|
||||
|
||||
@@ -1014,7 +1014,7 @@ class Tag(PageElement):
|
||||
|
||||
# First off, turn a string formatter into a function. This
|
||||
# will stop the lookup from happening over and over again.
|
||||
if not callable(formatter):
|
||||
if not isinstance(formatter, collections.Callable):
|
||||
formatter = self._formatter_for_name(formatter)
|
||||
|
||||
attrs = []
|
||||
@@ -1025,8 +1025,8 @@ class Tag(PageElement):
|
||||
else:
|
||||
if isinstance(val, list) or isinstance(val, tuple):
|
||||
val = ' '.join(val)
|
||||
elif not isinstance(val, basestring):
|
||||
val = unicode(val)
|
||||
elif not isinstance(val, str):
|
||||
val = str(val)
|
||||
elif (
|
||||
isinstance(val, AttributeValueWithCharsetSubstitution)
|
||||
and eventual_encoding is not None):
|
||||
@@ -1034,7 +1034,7 @@ class Tag(PageElement):
|
||||
|
||||
text = self.format_string(val, formatter)
|
||||
decoded = (
|
||||
unicode(key) + '='
|
||||
str(key) + '='
|
||||
+ EntitySubstitution.quoted_attribute_value(text))
|
||||
attrs.append(decoded)
|
||||
close = ''
|
||||
@@ -1112,7 +1112,7 @@ class Tag(PageElement):
|
||||
"""
|
||||
# First off, turn a string formatter into a function. This
|
||||
# will stop the lookup from happening over and over again.
|
||||
if not callable(formatter):
|
||||
if not isinstance(formatter, collections.Callable):
|
||||
formatter = self._formatter_for_name(formatter)
|
||||
|
||||
pretty_print = (indent_level is not None)
|
||||
@@ -1210,16 +1210,16 @@ class Tag(PageElement):
|
||||
raise ValueError(
|
||||
'Final combinator "%s" is missing an argument.' % tokens[-1])
|
||||
if self._select_debug:
|
||||
print 'Running CSS selector "%s"' % selector
|
||||
print('Running CSS selector "%s"' % selector)
|
||||
for index, token in enumerate(tokens):
|
||||
if self._select_debug:
|
||||
print ' Considering token "%s"' % token
|
||||
print(' Considering token "%s"' % token)
|
||||
recursive_candidate_generator = None
|
||||
tag_name = None
|
||||
if tokens[index-1] in self._selector_combinators:
|
||||
# This token was consumed by the previous combinator. Skip it.
|
||||
if self._select_debug:
|
||||
print ' Token was consumed by the previous combinator.'
|
||||
print(' Token was consumed by the previous combinator.')
|
||||
continue
|
||||
# Each operation corresponds to a checker function, a rule
|
||||
# for determining whether a candidate matches the
|
||||
@@ -1325,14 +1325,14 @@ class Tag(PageElement):
|
||||
next_token = tokens[index+1]
|
||||
def recursive_select(tag):
|
||||
if self._select_debug:
|
||||
print ' Calling select("%s") recursively on %s %s' % (next_token, tag.name, tag.attrs)
|
||||
print '-' * 40
|
||||
print(' Calling select("%s") recursively on %s %s' % (next_token, tag.name, tag.attrs))
|
||||
print('-' * 40)
|
||||
for i in tag.select(next_token, recursive_candidate_generator):
|
||||
if self._select_debug:
|
||||
print '(Recursive select picked up candidate %s %s)' % (i.name, i.attrs)
|
||||
print('(Recursive select picked up candidate %s %s)' % (i.name, i.attrs))
|
||||
yield i
|
||||
if self._select_debug:
|
||||
print '-' * 40
|
||||
print('-' * 40)
|
||||
_use_candidate_generator = recursive_select
|
||||
elif _candidate_generator is None:
|
||||
# By default, a tag's candidates are all of its
|
||||
@@ -1343,7 +1343,7 @@ class Tag(PageElement):
|
||||
check = "[any]"
|
||||
else:
|
||||
check = tag_name
|
||||
print ' Default candidate generator, tag name="%s"' % check
|
||||
print(' Default candidate generator, tag name="%s"' % check)
|
||||
if self._select_debug:
|
||||
# This is redundant with later code, but it stops
|
||||
# a bunch of bogus tags from cluttering up the
|
||||
@@ -1365,8 +1365,8 @@ class Tag(PageElement):
|
||||
new_context_ids = set([])
|
||||
for tag in current_context:
|
||||
if self._select_debug:
|
||||
print " Running candidate generator on %s %s" % (
|
||||
tag.name, repr(tag.attrs))
|
||||
print(" Running candidate generator on %s %s" % (
|
||||
tag.name, repr(tag.attrs)))
|
||||
for candidate in _use_candidate_generator(tag):
|
||||
if not isinstance(candidate, Tag):
|
||||
continue
|
||||
@@ -1381,21 +1381,21 @@ class Tag(PageElement):
|
||||
break
|
||||
if checker is None or result:
|
||||
if self._select_debug:
|
||||
print " SUCCESS %s %s" % (candidate.name, repr(candidate.attrs))
|
||||
print(" SUCCESS %s %s" % (candidate.name, repr(candidate.attrs)))
|
||||
if id(candidate) not in new_context_ids:
|
||||
# If a tag matches a selector more than once,
|
||||
# don't include it in the context more than once.
|
||||
new_context.append(candidate)
|
||||
new_context_ids.add(id(candidate))
|
||||
elif self._select_debug:
|
||||
print " FAILURE %s %s" % (candidate.name, repr(candidate.attrs))
|
||||
print(" FAILURE %s %s" % (candidate.name, repr(candidate.attrs)))
|
||||
|
||||
current_context = new_context
|
||||
|
||||
if self._select_debug:
|
||||
print "Final verdict:"
|
||||
print("Final verdict:")
|
||||
for i in current_context:
|
||||
print " %s %s" % (i.name, i.attrs)
|
||||
print(" %s %s" % (i.name, i.attrs))
|
||||
return current_context
|
||||
|
||||
# Old names for backwards compatibility
|
||||
@@ -1439,7 +1439,7 @@ class SoupStrainer(object):
|
||||
else:
|
||||
attrs = kwargs
|
||||
normalized_attrs = {}
|
||||
for key, value in attrs.items():
|
||||
for key, value in list(attrs.items()):
|
||||
normalized_attrs[key] = self._normalize_search_value(value)
|
||||
|
||||
self.attrs = normalized_attrs
|
||||
@@ -1448,7 +1448,7 @@ class SoupStrainer(object):
|
||||
def _normalize_search_value(self, value):
|
||||
# Leave it alone if it's a Unicode string, a callable, a
|
||||
# regular expression, a boolean, or None.
|
||||
if (isinstance(value, unicode) or callable(value) or hasattr(value, 'match')
|
||||
if (isinstance(value, str) or isinstance(value, collections.Callable) or hasattr(value, 'match')
|
||||
or isinstance(value, bool) or value is None):
|
||||
return value
|
||||
|
||||
@@ -1461,7 +1461,7 @@ class SoupStrainer(object):
|
||||
new_value = []
|
||||
for v in value:
|
||||
if (hasattr(v, '__iter__') and not isinstance(v, bytes)
|
||||
and not isinstance(v, unicode)):
|
||||
and not isinstance(v, str)):
|
||||
# This is almost certainly the user's mistake. In the
|
||||
# interests of avoiding infinite loops, we'll let
|
||||
# it through as-is rather than doing a recursive call.
|
||||
@@ -1473,7 +1473,7 @@ class SoupStrainer(object):
|
||||
# Otherwise, convert it into a Unicode string.
|
||||
# The unicode(str()) thing is so this will do the same thing on Python 2
|
||||
# and Python 3.
|
||||
return unicode(str(value))
|
||||
return str(str(value))
|
||||
|
||||
def __str__(self):
|
||||
if self.text:
|
||||
@@ -1527,7 +1527,7 @@ class SoupStrainer(object):
|
||||
found = None
|
||||
# If given a list of items, scan it for a text element that
|
||||
# matches.
|
||||
if hasattr(markup, '__iter__') and not isinstance(markup, (Tag, basestring)):
|
||||
if hasattr(markup, '__iter__') and not isinstance(markup, (Tag, str)):
|
||||
for element in markup:
|
||||
if isinstance(element, NavigableString) \
|
||||
and self.search(element):
|
||||
@@ -1540,7 +1540,7 @@ class SoupStrainer(object):
|
||||
found = self.search_tag(markup)
|
||||
# If it's text, make sure the text matches.
|
||||
elif isinstance(markup, NavigableString) or \
|
||||
isinstance(markup, basestring):
|
||||
isinstance(markup, str):
|
||||
if not self.name and not self.attrs and self._matches(markup, self.text):
|
||||
found = markup
|
||||
else:
|
||||
@@ -1554,7 +1554,7 @@ class SoupStrainer(object):
|
||||
if isinstance(markup, list) or isinstance(markup, tuple):
|
||||
# This should only happen when searching a multi-valued attribute
|
||||
# like 'class'.
|
||||
if (isinstance(match_against, unicode)
|
||||
if (isinstance(match_against, str)
|
||||
and ' ' in match_against):
|
||||
# A bit of a special case. If they try to match "foo
|
||||
# bar" on a multivalue attribute's value, only accept
|
||||
@@ -1589,7 +1589,7 @@ class SoupStrainer(object):
|
||||
# None matches None, False, an empty string, an empty list, and so on.
|
||||
return not match_against
|
||||
|
||||
if isinstance(match_against, unicode):
|
||||
if isinstance(match_against, str):
|
||||
# Exact string match
|
||||
return markup == match_against
|
||||
|
||||
|
||||
Reference in New Issue
Block a user