BeautifulSoup CSS 选择器

来源:互联网 发布:迅龙数据恢复怎么样 编辑:程序博客网 时间:2024/06/11 13:35


CSS3 选择器

在 CSS 中,选择器是一种模式,用于选择需要添加样式的元素。

"CSS" 列指示该属性是在哪个 CSS 版本中定义的。(CSS1、CSS2 还是 CSS3。)

选择器例子例子描述CSS.class.intro选择 class="intro" 的所有元素。1#id#firstname选择 id="firstname" 的所有元素。1**选择所有元素。2elementp选择所有 <p> 元素。1element,elementdiv,p选择所有 <div> 元素和所有 <p> 元素。1element elementdiv p选择 <div> 元素内部的所有 <p> 元素。1element>elementdiv>p选择父元素为 <div> 元素的所有 <p> 元素。2element+elementdiv+p选择紧接在 <div> 元素之后的所有 <p> 元素。2[attribute][target]选择带有 target 属性所有元素。2[attribute=value][target=_blank]选择 target="_blank" 的所有元素。2[attribute~=value][title~=flower]选择 title 属性包含单词 "flower" 的所有元素。2[attribute|=value][lang|=en]选择 lang 属性值以 "en" 开头的所有元素。2:linka:link选择所有未被访问的链接。1:visiteda:visited选择所有已被访问的链接。1:activea:active选择活动链接。1:hovera:hover选择鼠标指针位于其上的链接。1:focusinput:focus选择获得焦点的 input 元素。2:first-letterp:first-letter选择每个 <p> 元素的首字母。1:first-linep:first-line选择每个 <p> 元素的首行。1:first-childp:first-child选择属于父元素的第一个子元素的每个 <p> 元素。2:beforep:before在每个 <p> 元素的内容之前插入内容。2:afterp:after在每个 <p> 元素的内容之后插入内容。2:lang(language)p:lang(it)选择带有以 "it" 开头的 lang 属性值的每个 <p> 元素。2element1~element2p~ul选择前面有 <p> 元素的每个 <ul> 元素。3[attribute^=value]a[src^="https"]选择其 src 属性值以 "https" 开头的每个 <a> 元素。3[attribute$=value]a[src$=".pdf"]选择其 src 属性以 ".pdf" 结尾的所有 <a> 元素。3[attribute*=value]a[src*="abc"]选择其 src 属性中包含 "abc" 子串的每个 <a> 元素。3:first-of-typep:first-of-type选择属于其父元素的首个 <p> 元素的每个 <p> 元素。3:last-of-typep:last-of-type选择属于其父元素的最后 <p> 元素的每个 <p> 元素。3:only-of-typep:only-of-type选择属于其父元素唯一的 <p> 元素的每个 <p> 元素。3:only-childp:only-child选择属于其父元素的唯一子元素的每个 <p> 元素。3:nth-child(n)p:nth-child(2)选择属于其父元素的第二个子元素的每个 <p> 元素。3:nth-last-child(n)p:nth-last-child(2)同上,从最后一个子元素开始计数。3:nth-of-type(n)p:nth-of-type(2)选择属于其父元素第二个 <p> 元素的每个 <p> 元素。3:nth-last-of-type(n)p:nth-last-of-type(2)同上,但是从最后一个子元素开始计数。3:last-childp:last-child选择属于其父元素最后一个子元素每个 <p> 元素。3:root:root选择文档的根元素。3:emptyp:empty选择没有子元素的每个 <p> 元素(包括文本节点)。3:target#news:target选择当前活动的 #news 元素。3:enabledinput:enabled选择每个启用的 <input> 元素。3:disabledinput:disabled选择每个禁用的 <input> 元素3:checkedinput:checked选择每个被选中的 <input> 元素。3:not(selector):not(p)选择非 <p> 元素的每个元素。3::selection::selection选择被用户选取的元素部分。3

BeautifulSoup :一些常用功能的使用和测试

也懒得转Markdown语法了,评论都在代码里了。其中句子后面写着OK的,那就说明测试通过,可以正常使用。

# -*- coding: utf-8 -*-'''    # Author    : Solomon Xie    # Usage     : 测试BeautifulSoup一些用法及容易出bug的地方    # Enviroment: Python 2.7, Windows 7 (32bit), Chinese Language Pack'''import time, reimport bs4 # 必须导入,因为需要做一些bs4专有类型的判断from bs4 import BeautifulSoupdef test_BeautifulSoup():    """        # BeautifulSoup的一些问题实在让人蛋大。        # 这里研究下吧。    """    '''        # 基础部分        # 关于bs4的解析速度 #################        # 仔细阅读文档后发现,文档解析器对速度至关重要!        # 如果没有安装cchardet模块,那么光一个网页就要7秒!!        # 还不包括获取网页时间。然而试过后,如过山车一般:        # 安装了cchardet以后7秒变成了一瞬。        # 然而,用了几天后又变回了7秒,卸载了cchardet又变回了一瞬间!        # 另外,BeautifulSoup升级到4以后,导入方法变了,如下:    '''    from bs4 import BeautifulSoup    '''        # 关于被解析文档的编码格式 ##########        # 又不淡定了,官方说无论被传入什么编码的文档,都会被统一为unicode        # 实际上有时候我发现,必须以unicode传入才能获得正确结果。。。        # 这里试验发现,还真的是如此!必须传入decode过的码    '''    html_doc = open('test-Zhilian-list-page-sm1.html', 'r').read().decode('utf-8')    # ^ 这个html文件其实是智联招聘搜索页的源码,可以自己保存下来直接试一试。    '''        # 关于bs4的文档解析器 ##############        # 又是一个大坑:bs升级到4后,实例化时需要明确指定文档解析器,如:        # soup = BeautifulSoup(html_doc, 'lxml')        # 但是著名的lxml在这里就是个大坑啊,        # 因为它会直接略过html所有没写规范的tag,而不管人家多在乎那些信息        # 因为这个解析器的事,我少说也折腾了好几个小时才找到原因吧。        # 总结:记住,选择html5lib!效率没查多少,最起码容错率强,不会乱删你东西!    '''    soup = BeautifulSoup(html_doc, 'html5lib')    '''        # 关于bs4的输出格式 #################        # prettify()官方解释是一律输出utf-8格式,        # 其实却是unicode类型!!所以必须在prettify()里面指定编码。    '''    # output = soup.prettify('utf-8')    # print repr(output)    '''        # 所谓的多种搜索节点方式##############        就是不知道为什么:        无论怎么测验,find()和find_all()就是死活不管用!        只有用官方文档里的英文版《爱丽丝》测试才没问题。        也就是说,问题还是出在了文字编码上?        可是当我试着查找英文时,搜索结果还是为零-_-!        到了最后,bs4中众多的搜索工具上,        唯一能用的就是select()了,即CSS选择器。        虽然极其好用,但还是有限制性。        不死心,所以我还是再试验一下find_all()的毛病吧。    '''    # == find_all()之搜索标签名称 ============ OK    # result = soup.find_all('dl') # OK    # == find_all()之搜索标签属性 ============ not all OK    # result = soup.find_all(id='newlist_list_div') # OK    # result = soup.find_all(href=re.compile('.htm')) # Failed 竟然不支持href搜索,和官方说的不一样    # result = soup.find_all(name='vacancyid') # Failed 不支持标签的name属性搜索    # == find_all()之按CSS搜索 ============ OK    # result = soup.find_all('div', class_='clearfix') # OK    # result = soup.find_all('div', class_=re.compile('newlist_detail')) # OK    # result = soup.find_all(class_=re.compile('newlist_detail')) # OK    # == find_all()之按内容text搜索 ============     # find_all()加上text参数后,    # 返回的是字符串!而不是tag!!    # 类型为:<class 'bs4.element.NavigableString'>    # result = soup.find_all(text='会计') # OK 内容必须完全相等才算!(不含子标签)     # result = soup.find_all(text=u'数据') # OK 内容必须完全相等 无所谓unicode了    # result = soup.find_all(text=re.compile(u'学历:')) # OK unicode是绝对要!否则不行!    # == select() , CSS选择器搜索引擎 ============     '''        CSS选择器的语法请看w3cschool的文档:        http://www.w3school.com.cn/cssref/selector_nth-of-type.asp        下面总结了在BeautifulSoup中的语法搜索:        标签搜索,如:'input' ,搜索所有标签为input的元素        宽泛路径,如:'body a' ,就是body内所有a元素        绝对路径,如:'body > div > div > p' ,必须完全符合路径才能搜到        ID搜索  ,如:'#tag-1' ,搜索id为tag1的标签        混合搜索,如:'div #tag1', 搜索id为xx的div标签            'div[class*=newlist_detail] ~ div[class*=newlist_detail]' ,大混合        属性存在,如:'a[href]' ,搜索所有存在href属性的a标签        类名搜索,如:'[class=clearfix]' ,找到class名等于clearfix的标签            '[class^=newlist_detail]' ,找到class名中以"newlist_detail"开头的标签            '[class$=zwmc]'           ,找到class名中以"zwmc"结尾的标签            '[class*=clearfix]'       ,找到class名中包含"zwmc"的标签        兄弟搜索,如:            '#links ~ .clearfix' ,找到id为links标签的所有class等于"clearfix"的兄弟标签            '#links + .clearfix' ,找到id为links标签的下一个class等于"clearfix"的兄弟标签        序列搜索,如:'p nth-of-type(3)' ,这个说白了就是选择第3个p标签            'p nth-of-type(odd)' 表示奇数的p标签            'p nth-of-type(even)' 表示偶数的p标签            'p nth-of-type(n)' 表示所有的p标签            'p nth-of-type(3n)' 表示3的倍数的p标签            'p nth-of-type(4n+1)' 表示4的倍数加1的p标签,如第5个、第9个    '''    # result = soup.select('dl > p') # OK tag路径搜索    # result = soup.select('div[class*=newlist_detail] ~ div') # OK 各种混合搜索    # result = soup.select('[class*=zwmc]') # OK 各种混合搜索    con = soup.select('div[class^=newlist_detail]')[0]    result = con.select('[class*=zwmc]')    # print type(result[0])    print len(result)     # out = soup.select('[class*=zwmc]')    # print len(out)    # for item in out:    #     print item.get_text().encode('utf-8')def bsText(tags=[], info=''):    if len(tags):        t = tags[0] # 因为只会有一个对象        # select()选择器返回的是tag标签        # 而find_all()用text查询是返回的是字符串!        if isinstance(t, bs4.element.Tag):            return t.get_text().encode('utf-8')        elif isinstance(t, bs4.element.NavigableString):            return t.string.encode('utf-8')    else:        return '无[%s]信息'%info# 计算时间def timeup(func):    start = time.clock()    func()    end = time.clock()    timeuse = end-start    print '\n[%s()]函数一共使用了%d秒时间。\n' %(func.__name__, timeuse)    return timeuseif __name__ == '__main__':    timeup(test_BeautifulSoup)
技术宅的成就感


BeautifulSoup支持最常用的CSS selectors,这是将字符串转化为Tag对象或者BeautifulSoup自身的.select()方法。

本篇所使用的html为:

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>"""
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

举例,你可以这样搜索便签

soup.select("title")   #使用select函数# [<title>The Dormouse's story</title>]soup.select("p nth-of-type(3)")# [<p class="story">...</p>]
  • 1
  • 2
  • 3
  • 4
  • 5

另外,你也可以搜索在其他父标签内部的标签,即通过标签的所属关系寻找标签

soup.select("body a")   #搜索在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")  #搜索在html->head标签内部的标签# [<title>The Dormouse's story</title>]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

可以直接寻找在其他标签内部的标签

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")# []
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

通过tags标签获得元素的同胞兄弟

soup.select("#link1 ~ .sister")  #获得id为link1,class为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")   #获得id为link1,class为sister的兄弟标签内容(下一个兄弟便签)# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

通过CSS的类获得tags标签:

soup.select(".sister") #获得所有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>]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>]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

通过id获得标签:

soup.select("#link1") #通过设置参数为id来获取该id对应的tag# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]soup.select("a#link2")  #这里区别于上一个单纯的使用id,又增添了tag属性,使查找更加具体# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
  • 1
  • 2
  • 3
  • 4
  • 5

通过设置select函数的参数为列表,来获取tags。只要匹配列表中的任意一个则就可以捕获。

soup.select(“#link1,#link2”) #捕获id为link1或link2的标签# [<a class=”sister” href=”http://example.com/elsieid=”link1”>Elsie</a>, # <a class=”sister” href=”http://example.com/lacieid=”link2”>Lacie</a>]
  • 1
  • 2
  • 3

按照标签是否存在某个属性来获取:

soup.select('a[href]') #获取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

通过某个标签的具体某个属性值来查找tags:

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

这里需要解释一下: 
soup.select(‘a[href^=”http://example.com/”]’) 意思是查找href属性值是以”http://example.com/“值为开头的标签,可以查看博客介绍。 
soup.select(‘a[href$=”tillie”]’) 意思是查找href属性值是以tillie为结尾的标签。 
soup.select(‘a[href*=”.com/el”]’) 意思是查找href属性值中存在字符串”.com/el”的标签,所以只有href=”http://example.com/elsie”一个匹配。

如何查询符合查询条件的第一个标签:

soup.select_one(".sister") #只查询符合条件的第一个tag# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
  • 1
  • 2