刚开始接触 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. monitor.go

    package main import (     "fmt"     "net/http" ) // 查询监控信息的接口 func statsHandler( ...

  2. BZOJ_2588_Spoj 10628. Count on a tree_树剖+主席树

    BZOJ_2588_Spoj 10628. Count on a tree_树剖+主席树 题意: 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastan ...

  3. Python初学者必看(1)

    python介绍 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC语言 ...

  4. Sublime Text3插件安装(经典)

    今天我去听数学建模的培训,感觉很有意思,可是我没有报名(QAQ),没有参加培训的报名,不过幸好没有开始选拔比赛 所以我决定学习数学建模方面的知识,要好好学习了! 希望我未来的学弟学妹们!(不要像我这样 ...

  5. ASP.NET中的Cookie对象

    1.Cookie对象 Cookie对象一般用于在客户端保存一些针对某个用户的信息. Cookie本质上只是一小段文本字符串,改字符串一般保存在用户计算机特定文件夹下的某个文件中,每个Cookie都保存 ...

  6. 谈谈 ANR 之 Service 超时

    1. 核心源码 关键类 路径(/frameworks/base/) ActiveServices.java services/core/java/com/android/server/am/Activ ...

  7. 基于.NET CORE微服务框架 -谈谈surging 的messagepack、protobuffer、json.net 序列化

    1.前言 surging内部使用的是高性能RPC远程服务调用,如果用json.net序列化肯定性能上达不到最优,所以后面扩展了protobuf,messagepack序列化组件,以支持RPC二进制传输 ...

  8. 【STM32H7教程】第4章 STM32H7工程模板建立(MDK5)

    完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980 第4章   STM32H7工程模板建立(MDK5) 本章 ...

  9. Spark学习之Spark调优与调试(二)

    下面来看看更复杂的情况,比如,当调度器进行流水线执行(pipelining),或把多个 RDD 合并到一个步骤中时.当RDD 不需要混洗数据就可以从父节点计算出来时,调度器就会自动进行流水线执行.上一 ...

  10. C# Array数组是引用类型

    在C#中值类型都是由System.ValueType的直接派生类,System.ValueType本身又是直接从System.Object派生的.派生的意思是‘利用继承机制,新的类可以从已有的类中生出 ...