记一些bs4常用的东西
终点是后面的css选择器 很方便
对象的种类
1.Tag
2.NavigableString
3.BeautifulSoup
4.Comment
Tag
tag对象与XML或HTML原生文档中的tag相同,主要属性是name,attributes
1 2 | tag.name #u'b' |
一个tag可能有很多个属性. tag <b class="boldest"> 有一个 “class” 的属性,值为 “boldest” . tag的属性的操作方法与字典相同:
1 | tag[ 'class' ] # u'boldest' |
也可以直接”点”取属性, 比如: .attrs :
1 | tag.attrs # {u'class': u'boldest'} |
tag的属性可以被添加,删除或修改. tag的属性操作方法与字典一样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | tag[ 'class' ] = 'verybold' tag[ 'id' ] = 1 tag # <blockquote class="verybold" id="1">Extremely bold</blockquote> del tag[ 'class' ] del tag[ 'id' ] tag # <blockquote>Extremely bold</blockquote> tag[ 'class' ] # KeyError: 'class' print (tag.get( 'class' )) # None |
NavigableString
BeautifulSoup用NavigableString 来包装tag中的字符串
1 2 3 4 | tag.string # u'Extremely bold' type (tag.string) # <class 'bs4.element.NavigableString'> |
一个 NavigableString 字符串与Python中的Unicode字符串相同,并且还支持包含在 遍历文档树 和 搜索文档树 中的一些特性. 通过 unicode() 方法可以直接将 NavigableString对象转换成Unicode字符串
BeautifulSoup
BeautifulSoup 对象表示的是一个文档的全部内容.大部分时候,可以把它当作 Tag 对象,它支持 遍历文档树 和 搜索文档树 中描述的大部分的方法.
因为 BeautifulSoup 对象并不是真正的HTML或XML的tag,所以它没有name和attribute属性.但有时查看它的 .name 属性是很方便的,所以 BeautifulSoup 对象包含了一个值为 “[document]” 的特殊属性 .name
1 2 | soup.name # u'[document]' |
遍历文档树
一个Tag可能包含多个字符串或其它的Tag,这些都是这个Tag的子节点.Beautiful Soup提供了许多操作和遍历子节点的属性.
注意: Beautiful Soup中字符串节点不支持这些属性,因为字符串没有子节点
.contents 和 .children
tag的 .contents 属性可以将tag的子节点以列表的方式输出:
我觉得不太好用
还不如直接find_all之后for出来呢
parent
获取父节点
兄弟节点 — .next_sibling 和 .previous_sibling
find_all()
find_all( name , attrs , recursive , string , **kwargs )
find_all() 方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件.这里有几个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | soup.find_all( "title" ) # [<title>The Dormouse's story</title>] soup.find_all( "p" , "title" ) # [<p class="title"><b>The Dormouse's story</b></p>] soup.find_all( "a" ) # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] soup.find_all( id = "link2" ) # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>] import re soup.find(string = re. compile ( "sisters" )) # u'Once upon a time there were three little sisters; and their names were\n' |
有几个方法很相似,还有几个方法是新的,参数中的 string 和 id 是什么含义? 为什么 find_all("p", "title") 返回的是CSS Class为”title”的<p>标签? 我们来仔细看一下 find_all() 的参数
1 2 | soup.find_all( id = 'link2' ) # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>] |
如果传入 href 参数,Beautiful Soup会搜索每个tag的”href”属性:
1 2 | soup.find_all(href = re. compile ( "elsie" )) # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>] |
搜索指定名字的属性时可以使用的参数值包括 字符串 , 正则表达式 , 列表, True .
下面的例子在文档树中查找所有包含 id 属性的tag,无论 id 的值是什么:
1 2 3 4 | soup.find_all( id = True ) # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] |
使用多个指定名字的参数可以同时过滤tag的多个属性:
1 2 | soup.find_all(href = re. compile ( "elsie" ), id = 'link1' ) # [<a class="sister" href="http://example.com/elsie" id="link1">three</a>] |
有些tag属性在搜索不能使用,比如HTML5中的 data-* 属性:
1 2 3 | data_soup = BeautifulSoup( '<div data-foo="value">foo!</div>' ) data_soup.find_all(data - foo = "value" ) # SyntaxError: keyword can't be an expression |
但是可以通过 find_all() 方法的 attrs 参数定义一个字典参数来搜索包含特殊属性的tag:
1 | data_soup.find_all(attrs = { "data-foo" : "value" }) # [<div data-foo="value">foo!</div>] |
按CSS搜索
按照CSS类名搜索tag的功能非常实用,但标识CSS类名的关键字 class 在Python中是保留字,使用 class 做参数会导致语法错误.从Beautiful Soup的4.1.1版本开始,可以通过 class_参数搜索有指定CSS类名的tag:
1 2 3 4 | soup.find_all( "a" , class_ = "sister" ) # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] |
class_ 参数同样接受不同类型的 过滤器 ,字符串,正则表达式,方法或 True :
1 2 3 4 5 6 7 8 9 10 11 | soup.find_all( class_ = re. compile ( "itl" )) # [<p class="title"><b>The Dormouse's story</b></p>] def has_six_characters(css_class): return css_class is not None and len (css_class) = = 6 #这TM也行???我惊了 soup.find_all( class_ = has_six_characters) # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] |
tag的 class 属性是 多值属性 .按照CSS类名搜索tag时,可以分别搜索tag中的每个CSS类名:
1 2 3 4 5 6 | css_soup = BeautifulSoup( '<p class="body strikeout"></p>' ) css_soup.find_all( "p" , class_ = "strikeout" ) # [<p class="body strikeout"></p>] css_soup.find_all( "p" , class_ = "body" ) # [<p class="body strikeout"></p>] |
搜索 class 属性时也可以通过CSS值完全匹配:
1 2 | css_soup.find_all( "p" , class_ = "body strikeout" ) # [<p class="body strikeout"></p>] |
完全匹配 class 的值时,如果CSS类名的顺序与实际不符,将搜索不到结果:
1 2 3 4 | soup.find_all( "a" , attrs = { "class" : "sister" }) # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] |
string 参数
我看了文档之后还真发现这个参数其实还是有些用处的,比如说直接在find/find_all里通过匹配或者正则搜索string,好像有点逆天····
通过 string 参数可以搜搜文档中的字符串内容.与 name 参数的可选值一样, string 参数接受 字符串 , 正则表达式 , 列表, True . 看例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | soup.find_all(string = "Elsie" ) # [u'Elsie'] soup.find_all(string = [ "Tillie" , "Elsie" , "Lacie" ]) # [u'Elsie', u'Lacie', u'Tillie'] soup.find_all(string = re. compile ( "Dormouse" )) [u "The Dormouse's story" , u "The Dormouse's story" ] def is_the_only_string_within_a_tag(s): " "Return True if this string is the only child of its parent tag." " return (s = = s.parent.string) soup.find_all(string = is_the_only_string_within_a_tag) # [u"The Dormouse's story", u"The Dormouse's story", u'Elsie', u'Lacie', u'Tillie', u'...'] |
虽然 string 参数用于搜索字符串,还可以与其它参数混合使用来过滤tag.Beautiful Soup会找到 .string 方法与 string 参数值相符的tag.下面代码用来搜索内容里面包含“Elsie”的<a>标签:
1 2 | soup.find_all( "a" , string = "Elsie" ) # [<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>] |
其他的参数还有limit,recursive参数
limit就是在find里直接加上limit=n很简单
recursive:调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False .
最好用的应该还是CSS选择器 我到目前还没怎么用过 下次写爬虫的时候一定要用了熟悉一下
CSS选择器
Beautiful Soup支持大部分的CSS选择器 http://www.w3.org/TR/CSS2/selector.html , 在 Tag 或 BeautifulSoup 对象的 .select() 方法中传入字符串参数, 即可使用CSS选择器的语法找到tag:
select 返回的是一个tag的list CSS选择器用select这个太方便了!!!!!
1 2 3 4 5 | soup.select( "title" ) # [<title>The Dormouse's story</title>] soup.select( "p nth-of-type(3)" ) # [<p class="story">...</p>] |
通过tag标签逐层查找:
1 2 3 4 5 6 7 | soup.select( "body a" ) # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] soup.select( "html head title" ) # [<title>The Dormouse's story</title>] |
找到某个tag标签下的直接子标签:
soup.select("head > title") # [<title>The Dormouse's story</title>] soup.select("p > a") # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] soup.select("p > a:nth-of-type(2)") # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>] soup.select("p > #link1") # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>] soup.select("body > a") # []
找到兄弟节点标签:
soup.select("#link1 ~ .sister") # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] soup.select("#link1 + .sister") # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
通过CSS的类名查找:
1 2 3 4 5 6 7 8 9 | soup.select( ".sister" ) # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] soup.select( "[class~=sister]" ) # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] |
通过tag的id查找:
1 2 3 4 5 | soup.select( "#link1" ) # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>] soup.select( "a#link2" ) # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>] |
同时用多种CSS选择器查询元素:
1 2 3 | soup.select( "#link1,#link2" ) # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>] |
通过是否存在某个属性来查找:
1 2 3 4 | soup.select( 'a[href]' ) # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] |
通过属性的值来查找:
1 2 3 4 5 6 7 8 9 10 11 12 13 | soup.select( 'a[href="http://example.com/elsie"]' ) # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>] soup.select( 'a[href^="http://example.com/"]' ) # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] soup.select( 'a[href$="tillie"]' ) # [<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] soup.select( 'a[href*=".com/el"]' ) # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>] |
基本上用到这些就差不多了 后面有觉得重要的再补充进来
测试文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | #! /usr/bin/env python # -*- coding:utf8 -*- # __author__="leokim" from bs4 import BeautifulSoup html_doc = """ <html><head><title>The Dormouse's story</title></head> <body> <p class="title"><b>The Dormouse's story</b></p> <p class="story">Once upon a time there were three little sisters; and their names were <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>, <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; and they lived at the bottom of a well.</p> <p class="story">...</p> """ soup = BeautifulSoup(html_doc, 'html.parser' ) #print(type(soup)) #<class 'bs4.BeautifulSoup'> #print(type(soup.head)) #<class 'bs4.element.Tag'> #print(type(soup.title)) #<class 'bs4.element.Tag'> # print(soup.title.string) #The Dormouse's story #看来Tag是有string属性的 #print(type(soup.title.string)) #<class 'bs4.element.NavigableString'> #print(soup.find_all('a')) #[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, <a clas #s="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="siste #r" href="http://example.com/tillie" id="link3">Tillie</a>] #print(type(soup.find_all('a'))) #<class 'bs4.element.ResultSet'> #print(type(soup.find('a'))) #<class 'bs4.element.Tag'> #find返回的是Tag 而 find_all返回的是ResultSet # for a in soup.find_all('a'): # print(type(a)) # print(a.string) #<class 'bs4.element.Tag'> #<class 'bs4.element.Tag'> #<class 'bs4.element.Tag'> #ResoultSet 是Tag的集合可以通过for把Tag单独拿出来之后进行tag相关的操作 #所以我之前用了find_all("xxx").find_all('xxx')是解析不出来的,应该要单独把Tag循环出来操作 #print(type(soup.find('a').string)) #<class 'bs4.element.NavigableString'> #title_tag = soup.title #print(title_tag.parent) #<head><title>The Dormouse's story</title></head> data_soup = BeautifulSoup( '<div data-foo="value">foo!</div>' ) data_soup.find_all( "data-foo" = "value" ) |
通过语言设置来查找:
1 2 3 4 5 6 7 8 9 10 11 | multilingual_markup = """ <p>Hello</p> <p>Howdy, y'all</p> <p>Pip-pip, old fruit</p> <p>Bonjour mes amis</p> """ multilingual_soup = BeautifulSoup(multilingual_markup) multilingual_soup.select( 'p[lang|=en]' ) # [<p>Hello</p>, # <p>Howdy, y'all</p>, # <p>Pip-pip, old fruit</p>] |
返回查找到的元素的第一个
1 2 | soup.select_one( ".sister" ) # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a> |
对于熟悉CSS选择器语法的人来说这是个非常方便的方法.Beautiful Soup也支持CSS选择器API, 如果你仅仅需要CSS选择器的功能,那么直接使用 lxml 也可以, 而且速度更快,支持更多的CSS选择器语法,但Beautiful Soup整合了CSS选择器的语法和自身方便使用API.