NavigableString和PrettyTable碰撞的火花

NavigableString和PrettyTable

在解析网页时,常会使用 BeautifulSoup 模块中的 .string 或 .strings 来获取一个标签中的单个或多个字符串,但实际上获取到的字符串并不是 Python 中标准的 str 类型,而是 NavigableString 类型

在大多数时候 NavigableString 类型都可以当做普通字符串使用,但是在涉及递归调用的时候就会遇到麻烦,比如“陷入递归无法自拔”……

比如, PrettyTable 常用来打印规整的表格,当 PrettyTable 和 NavigableString 遇到一起的时候就有必要注意一下了,因为 PrettyTable 中的不少方法都涉及到 deepcopy 的调用,而深拷贝的背后就是使用的递归

这个时候,见到下面这堆报错就不要奇怪了

Traceback (most recent call last):
  File "./crawlScheduleAndGrade.py", line 184, in <module>
    print(scheduleTable)
  File "/home/ubuntu/.local/lib/python3.6/site-packages/prettytable.py", line 237, in __str__
    return self.__unicode__()
  File "/home/ubuntu/.local/lib/python3.6/site-packages/prettytable.py", line 243, in __unicode__
    return self.get_string()
  File "/home/ubuntu/.local/lib/python3.6/site-packages/prettytable.py", line 984, in get_string
    rows = self._get_rows(options)
  File "/home/ubuntu/.local/lib/python3.6/site-packages/prettytable.py", line 926, in _get_rows
    rows = copy.deepcopy(self._rows[options["start"]:options["end"]])
  File "/usr/lib/python3.6/copy.py", line 150, in deepcopy
    y = copier(x, memo)
  File "/usr/lib/python3.6/copy.py", line 215, in _deepcopy_list
    append(deepcopy(a, memo))
  File "/usr/lib/python3.6/copy.py", line 150, in deepcopy
    y = copier(x, memo)
  File "/usr/lib/python3.6/copy.py", line 215, in _deepcopy_list
    append(deepcopy(a, memo))
  File "/usr/lib/python3.6/copy.py", line 180, in deepcopy
    y = _reconstruct(x, memo, *rv)
  (中间省略 n 行)
  File "/usr/lib/python3.6/copy.py", line 240, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/lib/python3.6/copy.py", line 159, in deepcopy
    copier = getattr(x, "__deepcopy__", None)
  File "/usr/lib/python3/dist-packages/bs4/element.py", line 732, in __getattr__
    if attr == 'string':
RecursionError: maximum recursion depth exceeded in comparison

最后一行提示超出了允许的最大递归深度,因为为了避免溢出,Python 默认的最大递归深度是 1000

>>> import sys
>>> sys.getrecursionlimit()
1000

单纯对最后一行报错信息进行搜索会找到不少回答都是建议修改这一上限,也就是说把允许的最大深度调大一些就行了,但是这里遇到的问题不在于此,这里只需要确保传递给 PrettyTable 的是标准 str 类型就行了
比如下面几个解决方式:

  • 使用 .text 代替 .string ,通过 .text 获得的就是标准的 str 类型

  • 对 .string 或 .strings 的 NavigableString 对象进行强制转换 str()

  • BeautifulSoup 官方实例是这么使用的

for string in soup.strings:
    print(repr(string))

这里使用 repr 和 str 都差不多

发表评论

电子邮件地址不会被公开。 必填项已用*标注