上一节说到tag, 这里接着讲, tag有个属性叫做string, tag.string其实就是我们要掌握的四个对象中的第二个 ---- NavigableString, 它代表的是该tag内的text(甚至包括空白字符, 该tag内如果有别的tag, 必须前后紧挨不带空格, 否则返回None, 这一点的原因在下面提到了.), 其实这个NavigableString就是对于普通的Unicode的字符串的封装, 除了他提供一些对方便html结构树进行搜索的方法, 同时我们可以用.replace_with()来替换tag的内容, 我们可以用 unicode() 来将它转化为普通string.
1 tag.string 2 # u'Extremely bold' 3 type(tag.string) 4 # <class 'bs4.element.NavigableString'> 5 6 unicode_string = unicode(tag.string) 7 unicode_string 8 # u'Extremely bold' 9 type(unicode_string) 10 # <type 'unicode'> 11 12 tag.string.replace_with("No longer bold") 13 tag 14 # <blockquote>No longer bold</blockquote>
最后一个要说的对象叫做Comment, Comment 其实就是特殊的NavigableString对象. 经过实现发现只有紧挨这父tag写, 才有效果, 否则会返回None.(原因也在下面提到了)
1 markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>" 2 #<b> <!--前面有一个空格--></b> --> 这样会直接返回None 3 soup = BeautifulSoup(markup) 4 comment = soup.b.string 5 type(comment) 6 # <class 'bs4.element.Comment'>
了解了这四类对象, 接下来我们就可以探究如何找到所需要的内容...
下面是最简单的方式 :
soup.head # <head><title>The Dormouse's story</title></head> 如果有多个返回第一个 soup.body.b # <b>The Dormouse's story</b> 先找到第一个body, 再找body中的第一个b soup.b #如果上例中b是最先出现的, 那么也可以直接索引得到.
.contents 和 .children:
这两者的区别在于.contents返回的是列表, .children返回的是generator(但是其实内容都是一样的)...
比如对于
1 <body> 2 <b> 3 aabbccdd 4 </b> 5 </body>
1 soup = BeautifulSoup(open('test.html'), 'lxml') 2 print(soup.body.contents)
结果是:
['\n', <b> aabbccdd </b>, '\n']
值得一提的是BeautifulSoup也有自己的contents.
.descendants :
这个和.children唯一的区别在于前者返回所有子孙后者只返回直系孩子, 就不多说了.
.string :
如果一个tag只有一个children并且那个children还是NavigableString(这种情况就是tag的内容是纯文字), 那么我们可以用.string来获得它.
1 <b> 2 aabbccdd 3 </b>
上述html的b.contents是这样的 :
['\n aabbccdd\n']
对于这种, 就是符合上面所说的情况的, 就可以用b.string来获得它...
同时如果一个tag只有一个children并且它的children是另外一个tag, 且另外一个tag有一个.string, 那么这个tag的.string就等于它的孩子的.string.
对于这个例子是不行的 :
1 <body> 2 <b> 3 aabbccdd 4 </b> 5 </body>
对这个例子来说, 调用.contents的结果是这样的:
['\n', <b> aabbccdd </b>, '\n']
除非把上面的例子写成这样 :
<body><b> aabbccdd </b></body>
这就是为什么我上面说要想得到.string必须tag前后紧挨不能有空格的原因.