首页 > 代码库 > python学习之----导航树
python学习之----导航树
findAll 函数通过标签的名称和属性来查找标签 。但是如果你需要通过标签在文档中的位
置来查找标签,该怎么办?这就是导航树(Navigating Trees)的作用。在第1 章里,我们
看过用单一方向进行BeautifulSoup 标签树的导航:
bsObj.tag.subTag.anotherSubTag
现在我们用虚拟的在线购物网站http://www.pythonscraping.com/pages/page3.html 作为要抓取的示例网页
这个HTML 页面可以映射成一棵树(为了简洁,省略了一些标签),如下所示:
? html
— body
— div.wrapper
— h1
— div.content
— table#giftList
— tr
— th
— th
— th
— th
— tr.gift#gift1
— td
— td
— span.excitingNote
— td
— td
— img
— ……其他表格行省略了……
— div.footer
在后面几节内容里,我们仍然以这个HTML 标签结构为例。
1. 处理子标签和其他后代标签
在计算机科学和一些数学领域中,你经常会听到“虐子”事件(比喻对一些子事件
的处理方式):移动它们,储存它们,删除它们,甚至杀死它们。值得庆幸的是,在
BeautifulSoup 里,子标签的处理方式没那么残忍。
和许多其他库一样,在BeautifulSoup 库里,孩子(child)和后代(descendant)有显著的
不同:和人类的家谱一样,子标签就是一个父标签的下一级,而后代标签是指一个父标签
下面所有级别的标签。例如,tr 标签是tabel 标签的子标签,而tr、th、td、img 和span
标签都是tabel 标签的后代标签(我们的示例页面中就是如此)。所有的子标签都是后代标
签,但不是所有的后代标签都是子标签。
一般情况下,BeautifulSoup 函数总是处理当前标签的后代标签。例如,bsObj.body.h1 选
择了body 标签后代里的第一个h1 标签,不会去找body 外面的标签。
类似地,bsObj.div.findAll("img") 会找出文档中第一个div 标签,然后获取这个div 后
代里所有的img 标签列表。
如果你只想找出子标签,可以用.children 标签:
from urllib.request import urlopen from bs4 import BeautifulSoup html = urlopen("http://www.pythonscraping.com/pages/page3.html") bsObj = BeautifulSoup(html) for child in bsObj.find("table",{"id":"giftList"}).children: print(child)
这段代码会打印giftList 表格中所有产品的数据行。如果你用descendants() 函数而不是
children() 函数,那么就会有二十几个标签打印出来,包括img 标签、span 标签,以及每
个td 标签。掌握子标签与后代标签的差别十分重要!
2. 处理兄弟标签
BeautifulSoup 的next_siblings() 函数可以让收集表格数据成为简单的事情,尤其是处理
带标题行的表格:
from urllib.request import urlopen from bs4 import BeautifulSoup html = urlopen("http://www.pythonscraping.com/pages/page3.html") bsObj = BeautifulSoup(html) for sibling in bsObj.find("table",{"id":"giftList"}).tr.next_siblings: print(sibling)
这段代码会打印产品列表里的所有行的产品,第一行表格标题除外。为什么标题行被跳过
了呢?有两个理由。首先,对象不能把自己作为兄弟标签。任何时候你获取一个标签的兄
弟标签,都不会包含这个标签本身。其次,这个函数只调用后面的兄弟标签。例如,如果
我们选择一组标签中位于中间位置的一个标签,然后用next_siblings() 函数,那么它就
只会返回在它后面的兄弟标签。因此,选择标签行然后调用next_siblings,可以选择表
格中除了标题行以外的所有行。
和next_siblings 一样, 如果你很容易找到一组兄弟标签中的最后一个标签, 那么
previous_siblings 函数也会很有用。
当然,还有next_sibling 和previous_sibling 函数,与next_siblings 和previous_siblings
的作用类似,只是它们返回的是单个标签,而不是一组标签。
3. 父标签处理
在抓取网页的时候,查找父标签的需求比查找子标签和兄弟标签要少很多。通常情况
下,如果以抓取网页内容为目的来观察HTML 页面,我们都是从最上层标签开始的,然
后思考如何定位我们想要的数据块所在的位置。但是,偶尔在特殊情况下你也会用到
BeautifulSoup 的父标签查找函数,parent 和parents。例如:
from urllib.request import urlopen from bs4 import BeautifulSoup html = urlopen("http://www.pythonscraping.com/pages/page3.html") bsObj = BeautifulSoup(html) print(bsObj.find("img",{"src":"../img/gifts/img1.jpg" }).parent.previous_sibling.get_text())
这段代码会打印../img/gifts/img1.jpg 这个图片对应商品的价格(这个示例中价格是
$15.00)。
这是如何实现的呢?下面的图形是我们正在处理的HTML 页面的部分结构,用数字表示步
骤的话:
? <tr>
— <td>
— <td>
— <td>(3)
— "$15.00" (4)
— <td>(2)
— <img src="http://www.mamicode.com/img/gifts/img1.jpg"> (1)
(1) 选择图片标签src="http://www.mamicode.com/img/gifts/img1.jpg";
(2) 选择图片标签的父标签(在示例中是<td> 标签);
(3) 选择<td> 标签的前一个兄弟标签previous_sibling(在示例中是包含美元价格的<td>
标签);
(4) 选择标签中的文字,“$15.00”。
python学习之----导航树