刚开始接触 bs4 的时候,我也很迷茫,觉得 string 属性和 text 属性是一样的,不明白为什么要分成两个属性。

html = '<p>hello world</p>'
soup = BeautifulSoup(html, 'lxml')
p = soup.p
print(p.string)  # hello word
print(p.text)   # hello word

输出的结果是一样的。但实际上,string 属性的返回类型是 bs4.element.NavigableString,而 text 属性的返回类型是 str。

print(type(p.string))   # <class 'bs4.element.NavigableString'>
print(type(p.text)) # <class 'str'>

不要小看了这点区别,看下面的示例:

html = '''<html>
<td>some text</td>
<td></td>
<td><p>more text</p></td>
<td>even <p>more text</p></td>
</html>''' soup = BeautifulSoup(html, 'lxml')
tds = soup.find_all('td') for td in tds:
print(td.string) for td in tds:
print(td.text)

string 属性的输出结果为:

some text
None
more text
None

text 属性的输出结果为:

some text

more text
even more text

理解了 string 属性和 text 属性的返回类型,就可以明白结果为什么是这样的了。

第一项,返回都是 “some text”,这可以理解;

第二项,string 返回 None,因为不存在 NavigableString 节点;

第三项,text 返回的是标签的所有字符串连接成的字符串,所以是“more text”

第四项,bs4 的文档中指出:(地址:https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/#string)

  如果 tag 只有一个 NavigableString 类型子节点,那么这个 tag 可以使用 .string 得到子节点。
  如果一个 tag 仅有一个子节点,那么这个 tag 也可以使用 .string 方法,输出结果与当前唯一子节点的 .string 结果相同。
  如果 tag 包含了多个子节点,tag 就无法确定 .string 方法应该调用哪个子节点的内容, .string 的输出结果是 None。

  那么自然 string 属性返回的结果是 None,text 属性返回的结果是“even more text”

另外,要注意的是 find 方法中的 text 参数,官方解释是:text 参数用于搜索字符串会找到 .string 方法与 text 参数值相符的tag。

也就是说,虽然参数名是 text,但实际上搜索的是 string 属性。

看下面的例子,我们需要查找到包含附件链接的<a>标签

html = '''<div>
<p>
附件:
<a href='xxx'>下载</a></p>
</div>
'''

用 string 属性来获取的话,代码如下:

soup = BeautifulSoup(html, 'lxml')
tab = soup.find(text=re.compile('附件'))
print(type(tab)) # <class 'bs4.element.NavigableString'>
print(tab) # 附件

可以看到获取到的是 NavigableString 标签,要获取<a>标签,可以配合 find_next_sibling() 方法。

如果使用使用 text 属性的话,就必须传递方法来实现,但结果可能就不是你想要的了

def txt(tag):
return re.search('附件', tag.text) is not None print(soup.find_all(txt))

结果如下,把每一层显示的都包含进来了。

[<html><body><div>
<p>
附件:
<a href="xxx">下载</a></p>
</div>
</body></html>, <body><div>
<p>
附件:
<a href="xxx">下载</a></p>
</div>
</body>, <div>
<p>
附件:
<a href="xxx">下载</a></p>
</div>, <p>
附件:
<a href="xxx">下载</a></p>]

相关博文推荐:

Python:bs4的使用

Python:requests:详解超时和重试

Python:bs4中 string 属性和 text 属性的区别及背后的原理的更多相关文章

  1. jquery html属性和text属性的区别

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  2. C# 中 string.Empty、""、null的区别

    原文C# 中 string.Empty."".null的区别 一.string.Empty 和 "" 1.Empty是string类中的一个静态的只读字段,它是 ...

  3. java中String new和直接赋值的区别

        Java中String new和直接赋值的区别     对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才 ...

  4. MaskEdit组件的EditText属性和Text属性

    MaskEdit组件主要是EditMask属性 是string属性. 掩码字符串EditMask属性分为3个部分,分别用分号隔开,形式是“XXXXX;X;X” 第一部分是掩码字符串的主要部分,它确定输 ...

  5. java中String、StringBuffer、StringBuilder的区别

    java中String.StringBuffer.StringBuilder是编程中经常使用的字符串类,他们之间的区别也是经常在面试中会问到的问题.现在总结一下,看看他们的不同与相同. 1.可变与不可 ...

  6. C#中string.Empty和""、null的区别

    string.Empty是string类的一个静态常量,而""则表示一个空字符串. string是一种特殊的引用类型,它的null值则表示没有分配内存. 使用ILSpy反编译Str ...

  7. Java中String类两种实例化的区别(转)

    原文:http://blog.csdn.net/wangdajiao/article/details/52087302 一.String类的第一种方式 1.直接赋值 例:String str = &q ...

  8. Java基础——java中String、StringBuffer、StringBuilder的区别

    (转自:http://www.cnblogs.com/xudong-bupt/p/3961159.html) java中String.StringBuffer.StringBuilder是编程中经常使 ...

  9. .NET 中String 和StringBuilder 以及他们的区别

    stirng对象是不可变的,每次使用String类的方法进行运算时(赋值.拼接),都会在内存中生成新的字符串对象,这就要为新对象分配新的内存空间. StringBuilder 实例的 int Capa ...

随机推荐

  1. kv.go

    package clientv3 import (     pb "github.com/coreos/etcd/etcdserver/etcdserverpb" //protob ...

  2. bzoj2806 [Ctsc2012]Cheat

    我们的目的就是找到一个最大的L0,使得该串的90%可以被分成若干长度>L0的字典串中的子串. 明显可以二分答案,对于二分的每个mid 我们考虑dp:f[i]表示前i个字符,最多能匹配上多少个字符 ...

  3. 【英国毕业原版】-《博尔顿大学毕业证书》Bolton一模一样原件

    ☞博尔顿大学毕业证书[微/Q:2544033233◆WeChat:CC6669834]UC毕业证书/联系人Alice[查看点击百度快照查看][留信网学历认证&博士&硕士&海归& ...

  4. Maven安装教程详解

    一.准备工作 1.确定电脑上已经成功安装jdk7.0以上版本                 2.win10操作系统                 3.maven安装包            下载地 ...

  5. Java集合--TreeSet详细解析

    目录 1.构造函数 2.增 3.删 4.比较器 总结 谈到TreeSet的特点,估计大家脑海里想到的都是:有序,不可重复,红黑树,基于Treemap实现,自定义排序等特点.这篇博客帮助大家从源码梳理下 ...

  6. netty源码学习

    概述 Netty is an asynchronous event-driven network application framework for rapid development of main ...

  7. c#Socket服务器与客户端的开发(2)

    上一篇文章我们使用原生的socket分别实现了服务器和客户端, 本篇文章使用SuperSocket来开发实现服务器, 之前也介绍了SuperSocket是一个轻量级, 跨平台而且可扩展的 .Net/M ...

  8. 有趣的8个IT冷知识

    阅读本文大概需要 2.8 分钟. 想要成为一名成功的程序员,我们除了了解不同编程语言的设计思路,也应当了解编程的发展历史,从而判断未来的编程技术将走向何方.接下就为大家普及下计算机发展历程中的8个冷门 ...

  9. Kubernetes集群部署史上最详细(二)Prometheus监控Kubernetes集群

    使用Prometheus监控Kubernetes集群 监控方面Grafana采用YUM安装通过服务形式运行,部署在Master上,而Prometheus则通过POD运行,Grafana通过使用Prom ...

  10. 【纯技术贴】.NETStandard FreeSql v0.0.9 功能预览

    年关将至,首页技术含量文章真是越来越少,理解大家盼着放假过年,哥们我何尝不是,先给大家拜个早年. 兄弟我从11月底发了神经,开启了 ORM 功能库的开发之旅,历时两个月编码和文档整理,目前预览版本更新 ...