Beautiful Soup 用来方便的解析 html 和 xml 文档,实现快速的在文档树中查找、提取、跳转。
Beautifusoup 将整个文档分为四种对象:Beautifusoup对象、bs4.element.tag 简称 tag 对象、bs4.element.NavigableString 简称 string 对象、bs4.element.Comment 简称 comment 对象。Beautifusoup 对象表示整颗树,其他三种对象都可以看作是树上的节点。
<span class="green">Anna Pavlovna</span>
上边整个片段就是一个tag,span 是tag 的名称。Anna Pavlovna 是 string对象,被界定在 “ > ” 与 “ < ” 之间。 comment 对象其实是特殊的 string 对象,背界定在 "<!--" 和 “-->“ 之间,如下边片段中的 “some comment” .
"<b><!--some comment--></b>"
整颗文档树按照节点来组织,自然在跳转时,按照节点之间的关系:父节点(parent
),兄弟节点(sibling),子节点(children 这里指的是直接子节点),后代节点(descendants 包含直接子节点和间接子节点),前后节点(这里前后指的是按解析的顺序,所以前后节点可能是前边四种中的任何 一种)。另外,需要注意的是单数与复数的差别,单数返回的单个对象或者None,复数返回的是 list (空或非空)。
常用的文档过滤方法 .find_all 和 find 的说明。
函数原型:soup.findAll(name=None, attrs={}, recursive=True, text=None, limit=None, **kwargs)
比如:
过滤时,都是按照节点来过滤的,匹配到的都是整个节点。 text 参数名也可以用 string 来代替,貌似之前的有的版本叫为 text ,有的版本中叫 string。
实际查找的节点就两种:tag 和 string。name 参数要查找的 tag ,支持 字符串,字符串容器,布尔量True,函数。参数为方法时,按照鸭子类型,该方法的参数为tag 对象,函数的返回值的按 鸭子行为 进行约束,函数的返回值为布尔量即可。注意该方法实际是从来以递归迭代的方式每个tag都进行尝试。
def has_href_and_id(tag):
return tag.has_attr('class') and tag.has_attr('id')
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
标签a 有三个属性:class,href,id. 属性的值为 “=“ 右边的内容。这里的属性不在dir() 列表当中。通过 a.get(“id”) 或 a["id"] 来获取,后者在属性不存在时会抛出异常。
例子中可以用 .find("a", id = "link3") 进行限定。id = "link3" 被打包进 kwargs 关键字参数中。或者用 bsObj.findAll(**{"id":"link3"}) 让属性键值对解包传给 kwargs,或者 bsObj.findAll(attr = {"id":"link3"}) 使用关键字参数。.find("a", "link3") 则表示不指定属性的名字,只匹配值。
html = '<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>'
soup = BeautifulSoup(html, "lxml")
soup.find("a", href = re.compile("example"))
soup.find(re.compile("^a"), {"href" : re.compile("example")})
#<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a> # 输出
soup.find("a", {"id" : ("link", "link3")}) #属性也可以是字符串容器来表示,只要匹配容器中的一个元素即可
通过属性来过滤时,也可以为属性传入一个函数,注意此函数的参数使用的是属性,当然返回值一样是布尔量。
def func(value):
return value and re.compile("red").search(value) or value == "link3"
soup.find(id = func)
#<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a> #输出
这里提到的两次可以传入函数作为函数,注意在函数内部都先对参数进行非空判断,防止抛出异常。比如上边的 return value and ...
^-^ 正则表达式可以作为 Beautifusoup 查找方法中的任何一个参数。