BeautifulSoup解析空格

今天爬一个网站,它的class里有空格,导致我用BeautifulSoup半天没爬出来,后来看了文档,这叫多值属性:

HTML 4定义了一系列可以包含多个值的属性.在HTML5中移除了一些,却增加更多.最常见的多值的属性是 class (一个tag可以有多个CSS的class). 还有一些属性 rel , rev , accept-charset , headers , accesskey . 在Beautiful Soup中多值属性的返回类型是list:

1 css_soup = BeautifulSoup('<p class="body strikeout"></p>')
2 css_soup.p['class']
3 # ["body", "strikeout"]
4 
5 css_soup = BeautifulSoup('<p class="body"></p>')
6 css_soup.p['class']
7 # ["body"]

 

如果某个属性看起来好像有多个值,但在任何版本的HTML定义中都没有被定义为多值属性,那么Beautiful Soup会将这个属性作为字符串返回

1 id_soup = BeautifulSoup('<p id="my id"></p>')
2 id_soup.p['id']
3 # 'my id'

 

将tag转换成字符串时,多值属性会合并为一个值

1 rel_soup = BeautifulSoup('<p>Back to the <a rel="index">homepage</a></p>')
2 rel_soup.a['rel']
3 # ['index']
4 rel_soup.a['rel'] = ['index', 'contents']
5 print(rel_soup.p)
6 # <p>Back to the <a rel="index contents">homepage</a></p>

 

如果转换的文档是XML格式,那么tag中不包含多值属性

1 xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml')
2 xml_soup.p['class']
3 # u'body strikeout'

 

这是文档对多值属性的解释

所以在使用BeautifulSoup.find or BeautifulSoup.find_all的时候要注意

 

举个例子吧:

假如我现在的HTML是这样的:

>>> html = '<div class="l_post j_l_post l_post_bright  "></div>'

先对他用html.parser解析,然后我们看一看里面的class是什么

1 >>> Soup = BeautifulSoup(html,'html.parser')
2 >>> Soup.div['class']
3 ['l_post', 'j_l_post', 'l_post_bright', '']

咦,我们发现如果最后又空格的话会多一个'',我们用find_all或者find可以找到我们想要的这个标签,但是class可以只要第一个,也可以要整个列表都可以

notice:我在爬一个网站的时候发现了这个的问题,你用列表的化是只要有列表中任一一个元素都能匹配上

1 >>> Soup.find('div', attrs = {'class':'1_post'})
2 >>> Soup.find('div', attrs = {'class':'l_post'})
3 <div class="l_post j_l_post l_post_bright "></div>
4 >>> Soup.find('div', attrs = {'class':['l_post', 'j_l_post']})
5 <div class="l_post j_l_post l_post_bright "></div>
6 >>> Soup.find('div', attrs = {'class':['l_post', 'j_l_post', 'l_post_bright']})
7 <div class="l_post j_l_post l_post_bright "></div>
8 >>> Soup.find('div', attrs = {'class':['l_post', 'j_l_post', 'l_post_bright', '']})
9 <div class="l_post j_l_post l_post_bright "></div>

 

这里再补充一点知识吧,就是find,和find_all的用法,拿这个例子继续(对了,find_all因为常用,所有可以省略,可以直接写Soup(.....))

1 >>> Soup.find(attrs = {'class':['l_post', 'j_l_post', 'l_post_bright', '']})
2 <div class="l_post j_l_post l_post_bright "></div>
3 >>> Soup.find_all(attrs = {'class':['l_post', 'j_l_post', 'l_post_bright', '']})[0]
4 <div class="l_post j_l_post l_post_bright "></div>
5 >>> Soup.find_all('div', attrs = {'class':['l_post', 'j_l_post', 'l_post_bright', '']})[0]
6 <div class="l_post j_l_post l_post_bright "></div>

 

经过对BeautifulSoup的深度阅读后,觉得下面这个点对分析多值属性的html很重要:

按照CSS类名搜索tag的功能非常实用,但标识CSS类名的关键字 class 在Python中是保留字,使用 class 做参数会导致语法错误.从Beautiful Soup的4.1.1版本开始,可以通过 class_ 参数搜索有指定CSS类名的tag:

1 soup.find_all("a", class_="sister")
2 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
3 #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
4 #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

class_ 参数同样接受不同类型的 过滤器 ,字符串,正则表达式,方法或 True :

 1 soup.find_all(class_=re.compile("itl"))
 2 # [<p class="title"><b>The Dormouse's story</b></p>]
 3 
 4 def has_six_characters(css_class):
 5     return css_class is not None and len(css_class) == 6
 6 
 7 soup.find_all(class_=has_six_characters)
 8 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
 9 #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
10 #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

tag的 class 属性是 多值属性 .按照CSS类名搜索tag时,可以分别搜索tag中的每个CSS类名:

1 css_soup = BeautifulSoup('<p class="body strikeout"></p>')
2 css_soup.find_all("p", class_="strikeout")
3 # [<p class="body strikeout"></p>]
4 
5 css_soup.find_all("p", class_="body")
6 # [<p class="body strikeout"></p>]

搜索 class 属性时也可以通过CSS值完全匹配:

1 css_soup.find_all("p", class_="body strikeout")
2 # [<p class="body strikeout"></p>]

完全匹配 class 的值时,如果CSS类名的顺序与实际不符,将搜索不到结果:

1 soup.find_all("a", attrs={"class": "sister"})
2 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
3 #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
4 #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

 

以上是文档对class_的解释,但是我发现在有些网站的解析时这种方式还是行不通,所以在这种方式行不通的时候,我用了这种re

 1 InfoList = Soup.find_all(class_ = re.compile('l_post j_l_post l_post_bright')) 

比如说这个多值属性,我用前面的方法都不行,tag的class是“l_post j_l_post l_post_bright  ”,这样才解决了我的问题

posted @ 2018-05-07 13:42  duck_lu  阅读(731)  评论(0编辑  收藏  举报