洗礼灵魂,修炼python(66)--爬虫篇—BeauitifulSoup进阶之“我让你忘记那个负心汉,有我就够了”

说明一下,这个标题可能有点突兀,结合上一篇一起看就行

 

前面已经对BeautifulSoup有了了解了,相信你基本已经学会怎么获取网页数据了,那么BeautifulSoup这么吊,还有没有其他的功能呢?当然是有的

前面说的Tag对象都还记得吧?像这样BeautifulSoup.title,得到的就是Tag对象,它其实还有一些属性:

1.contents:将tag的子节点以列表的方式输出

还是前面的例子:

# -*- coding:utf-8 -*-
import bs4
html='''
<html>
	<head>
	<title>这是第二节课</title>
	<meta charset='utf-8'> <!--meta是单标签-->
	<meta name='keywords' content='hello world,oh yeah'>
	</head>
	<!--<body bgcolor='green'>-->
	<body link='red' vinlk='green' alink='blue'>

		<h1>这是一个标题</h1>
		<!--超链接必须加上http://不然无法跳转-->
		<a href='http://www.baidu.com'>百度</a>
		<a href='http://www.163.com'>网易</a>
		<a href='http://www.qq.com'>腾讯</a>
		<a href='http://www.sina.com'>新浪</a>
        </body>
</html>
'''
test=bs4.BeautifulSoup(html,'html.parser')
print test.title

print test.title.contents

 

 结果:

 

字符型是utf-8,而我用的是python2,前面编码问题已经说过了,略过

 

既然是列表对吧,那么它就可以使用列表的方法了:

 

2.children:返回一个列表迭代器

 

 

既然是迭代器,那么就可以迭代出来了:

 

 

其实BeautifulSoup对象也有类似tag对象的children的属性:

3.descendants:类似tag对象的children的属性,不过返回的是一个生成器对象

 

同样的,使用for循环也可以迭代出来,这里直接略过。

 

上面的contents和children是什么属性呢?官方文档里有个称呼叫Tag对象的直接子节点。而descendants是BeautifulSoup的子孙节点

 

4.什么是节点呢?

结合我个人的理解:这里牵扯到一个知识点,树形结构知道吗?就是只某样事物类似树枝一样,由树干延伸到树枝,树枝再延伸到小树枝……这样不断的蔓延伸展,这种就是树形结构,而每一个过渡点就叫做节点。那么这里的html文档就好比一棵树,然后利用BeautifulSoup模块生成了BeautifulSoup对象,BeautifulSoup对象下面每一个属性就是一个节点,属性下面又有一个子节点,然后descendants其实就是BeautifulSoup对象的直接子节点,而contents和children就是由BeautifulSoup对象结合html标签生成的Tag对象的直接子节点(有点递归的意思,你可以结合理解)

 

既然有节点,结合上一篇说的,我们可以在Tag对象下使用string子节点属性获得html代码内的字符串内容,那么这样的内容就叫节点内容

 

我相信,你在自己动手练习时,一定遇到这种情况:

 

怎么是None呢?html里不是有数据title标签和meta标签等的吗?对吧?那么这为何是空呢?这里就是string属性的一个特性而来。

 

string属性特性:

官方文档是这么说的:

如果tag只有一个NavigableString类型(忘记什么是NavigableString类型回去看上一篇博文)子节点,那么这个tag可以使用string属性得到子节点。如果一个tag仅有一个子节点,那么这个tag也可以使用string属性,输出结果与当前唯一子节点的string属性结果相同。

换句话就是:

  • 如果一个标签里面没有子标签了,那么 string属性就会返回标签里面的内容。如果标签里面只有唯一的一个子标签了,那么string属性也会返回最里面的内容
  • 如果tag包含了多个子节点(子标签),tag就无法确定string属性应该调用哪个子节点的内容而返回None

 

那有朋友说,我就想返回多个内容怎么办?使用strings属性和stripped_strings属性

 

5.strings:获取多个内容,返回一个生成器对象:

 

 

遍历就直接略过了,你使用工程函数list转为列表或者用for迭代或者转为字符串或者使用函数repr输出都随便你了

 

6.stripped_strings :(看单词意思估计你都能猜到干嘛的了)同strings返回一个生成器对象,不过生成器对象内的元素已自动去除多余空白内容:

 

因为只返回字符串内容,而我那个html源码例子里属于head标签的只有这一句字符串内容,所以结果如上。

 

那么既然有子节点,自然还有父节点,前后节点,兄弟节点等等的。

 

7.父节点:parent属性,即就是当前节点的父级节点

 

使用parent属性会打印父级节点所有内容,使用parent.name属性则显示父级节点的名字

 

当然你会想,还有和父级节点同级的节点

8.全部父级节点:parents属性

同parents,略过

 

9.兄弟节点:和当前节点同一级别的节点

  • next_sibling属性获取该节点的下一个兄弟节点
  • previous_sibling属性获取当前节点的上一个兄弟节点,如果节点不存在,则返回 None

实际文档中的tag的 .next_sibling 和 .previous_sibling 属性通常是字符串或空白,因为空白或者换行也可以被视作一个节点,所以得到的结果可能是空白或者换行。

 

可以利用next_sibling.next_sibling获得下一个兄弟节点:

 

当然上一个兄弟节点也同样,略过

 

10.全部兄弟节点:获得当前节点的兄弟节点并返回一个生成器,使用属性next_siblings和previous_siblings

 

11.前后节点:与 next_sibling和previous_sibling不同,它并不是针对于兄弟节点,而是在所有节点,不分层次,谁在前就是前节点,谁在后就是后节点。使用next_element和previous_element

 

12.所有前后节点:向前或向后访问文档节点内容,返回一个生成器。使用next_elements和previous_elements 属性

 

既然BeautifulSoup这么强大,那么也可以搜索文档内容吧?是的

 

13. find_all( name , attrs , recursive , text , **kwargs ):搜索当前tag的所有tag子节点,以列表形式返回符合条件的所有tag对象,name参数即待搜索的html标签名

name参数:

1)name参数可以是一个字符串对象,即html标签

2)name参数可以是一个正则表达式,BeautifulSoup对象会默认使用正则表达式的match()方法匹配

这个就厉害了对吧?

 

3)name参数可以是一个列表,BeautifulSoup对象会将与列表中任一元素匹配的内容返回

 

 4)name参数可以是Bool函数的True,True即代表可以匹配任何值(即所有值)

 

5)name参数可以是一个函数/方法

 

自定义了一个has方法,只返回拥有href属性的标签

 

 

keyword参数

  • 如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索
  • 如果包含一个名字为id的参数,BeautifulSoup对象会搜索每个tag的”id”属性

 

1)如果参数是id:

 

由于前面的html标签里没有适合的标签,所以这里新设一个例子

txt='<a class="yang" href="http://example.com" id="link">test</a>'
test1=bs4.BeautifulSoup(txt,'html.parser')

print test1.find_all(id='link')

 

 结果:

 

2)如果参数是href:

 还是原来的例子

 

当然你可以使用多个指定名字的参数可以同时过滤tag的多个属性。略过

 

注意

  • 当关键词是class时,由于class也是python的关键词语句,当作关键词使用时,使用【class_】就行
  • 当遇到特殊情况不能被搜索时,可以使用attrs参数定义一个字典参数来搜索包含特殊属性的tag

不过以上情况基本少见,略过

 

text参数:可以搜索文档中的字符串内容,与name参数的可选值一样,可以是字符串 , 正则表达式 , 列表, True

略过

 

limit参数:如果文档很大那么搜索会很慢,而我们并不需要全部结果,使用limit参数限制返回结果的数量,效果与SQL中的limit关键字类似,当搜索到的结果数量达到limit的限制时,就停止搜索返回结果。

limit参数在很多地方都有用到

 

 本来html代码里有四个a标签,设置limit参数后只得到两个值

 

recursive参数:recursive值默认为True,即BeautifulSoup对象会默认检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数recursive=False

使用与不使用的差别

 

14.还有以下这些方法,使用基本和find_all类似,所以直接略过:

 

find( name,attrs, recursive, text, **kwargs ): 类似find_all(),不过find() 方法直接返回结果

 

find_parents()和find_parent()

find_all() 和 find()只搜索当前节点的所有子节点,孙子节点等。find_parents() 和 find_parent() 用来搜索当前节点的父辈节点,搜索方法与普通tag的搜索方法相同,搜索文档搜索文档包含的内容

 

find_next_siblings()和find_next_sibling()

这2个方法通过next_siblings 属性对当 tag 的所有后面解析的兄弟 tag 节点进行迭代, find_next_siblings() 方法返回所有符合条件的后面的兄弟节点,find_next_sibling() 只返回符合条件的后面的第一个tag节点

 

find_previous_siblings()和find_previous_sibling()

这2个方法通过previous_siblings 属性对当前 tag 的前面解析的兄弟 tag 节点进行迭代, find_previous_siblings() 方法返回所有符合条件的前面的兄弟节点, find_previous_sibling() 方法返回第一个符合条件的前面的兄弟节点

 

find_all_next()和find_next()

这2个方法通过next_elements 属性对当前 tag 的之后的 tag 和字符串进行迭代, find_all_next() 方法返回所有符合条件的节点, find_next() 方法返回第一个符合条件的节点

 

find_all_previous() 和 find_previous()

这2个方法通过previous_elements 属性对当前节点前面的 tag 和字符串进行迭代, find_all_previous() 方法返回所有符合条件的节点, find_previous()方法返回第一个符合条件的节点

 

 

那有朋友说,假如html代码里有css样式表等使用符号【#】的又怎么处理呢?

 

15.select()方法

可以对css样式表查询,返回列表对象

1)通过标签名查找

2)通过class类名查找

那个常用例子并没有class的,所以另设一个例子

txt='<a class="yang" href="http://example.com" id="link"><!-- test --></a>'
test1=bs4.BeautifulSoup(txt,'html.parser')
print test1.select('.yang')

 结果:

 

3)通过 id 名查找

与通过class查找一样:

txt='<a class="yang" href="http://example.com" id="link"><!-- test --></a>'
test1=bs4.BeautifulSoup(txt,'html.parser')
print test1.select('#link')

 结果:

 

4)组合查找

组合使用标签名与类名、id名进行查找,和单独查找原理一样,注意不在同一节点的空格隔开,同一节点的不加空格。详细的略过

5)子标签查找

原来的例子:

 

6)属性查找

可以加入属性元素,属性需要用中括号括起来,注意属性和标签属于同一节点,所以中间不能加空格,否则会无法匹配到

 

属性查找同样可以与上面的查找方式组合,不在同一节点的空格隔开,同一节点的不加空格

 

注意:

  • select()返回的既然是列表,那么可以运用所有符合列表的方法,自己去发现了
  • 利用select()可以达到同find_all效果相同

 

 

内容比较多,其实官方的文档都还有些,不过那些基本不怎么用了,所以就这些吧,只有查找提取的方法,这已经完完全全的够用了

 

 

posted @ 2017-11-10 18:39  Eeyhan  阅读(292)  评论(0编辑  收藏  举报