设为首页 收藏本站
查看: 947|回复: 0

[经验分享] [学习]用python的BeautifulSoup分析html

[复制链接]

尚未签到

发表于 2015-4-19 06:39:19 | 显示全部楼层 |阅读模式
  序言
  之前用python爬取网页的时候,一直用的是regex或者自带的库sgmllib里的SGMLParser。但是遇到复杂一点的情况时,SGMLParser往往就不那么给力了!(哈,难道说我 too native了?毕竟beautifulSoup是继承sgmlparser的么~)所以,我寻寻觅觅寻寻觅觅,发现了BeautifulSoup这么个玩意。BeautifulSoup提供了很人性化的parser tree,有了它,我们可以简单的抽取出tagname, attrs, text等等等等...
  install什么的,看这里 -> http://www.crummy.com/software/BeautifulSoup/
  入门
  (ps:其实入门什么的看官方文档是最好的了,这里只是记录一下简单的用法。)
  (official document link : http://www.crummy.com/software/BeautifulSoup/bs3/documentation.zh.html)
    首先先介绍实际工作中最常用的几个方法:
    举例的html代码(就用官方例子好了):



1
2     
3         Page title
4     
5     
6         
7         This is paragraphone.
8         
9         
10         This is paragraphtwo.
11         
12      
13
  
  0、初始化
  



1 soup = BeautifulSoup(html) # html为html源代码字符串,type(html) == str
  
  1、用tag获取相应代码块的剖析树:
  
    既然要分析html,首先要找到对我们有用的tag块,beautiful提供了非常便利的方式。



#当用tag作为搜索条件时,我们获取的包含这个tag块的剖析树:
#ooo
#这里获取head这个块
head = soup.find('head')
# or
# head = soup.head
# or
# head = soup.contents[0].contents[0]
  运行后,我们会得到:



1
2     Page title
3
    这里小灯我还是推荐使用第二种方法,find方法在当前tag剖析树(当前这个html代码块中)寻找符合条件的子树并返回。find方法提供多种查询方式,包括用喜闻乐见的regex哦~之后会详细介绍。
    contents属性是一个列表,里面保存了该剖析树的直接儿子。
  如:



1 html = soup.contents[0] #  ...
2 head = html.contents[0] #  ...
3 body = html.contents[1] #  ...
  
  2、用contents[], parent, nextSibling, previousSibling寻找父子兄弟tag
  
  为了更加方便灵活的分析html代码块,beautifulSoup提供了几个简单的方法直接获取当前tag块的父子兄弟。
  假设我们已经获得了body这个tag块,我们想要寻找, , 第一个, 第二个这四个tag块:



# body = soup.bodyhtml = body.parent # html是body的父亲
head = body.previousSibling # head和body在同一层,是body的前一个兄弟
p1 = body.contents[0] # p1, p2都是body的儿子,我们用contents[0]取得p1
p2 = p1.nextSibling # p2与p1在同一层,是p1的后一个兄弟, 当然body.content[1]也可得到
print p1.text
# u'This is paragraphone.'
print p2.text
# u'This is paragraphtwo.'
#  注意:1,每个tag的text包括了它以及它子孙的text。2,所有text已经被自动转
#为unicode,如果需要,可以自行转码encode(xxx)
  
  然而,如果我们要寻找祖先或者孙子tag怎么办呢?? 用while循环吗? 不, beautifulsoup已经提供了方法。
  
  3、用find, findParent, findNextSibling, findPreviousSibling寻找祖先或者子孙 tag:
  
    有了上面的基础,这里应该很好理解了,例如find方法(我理解和findChild是一样的),就是以当前节点为起始,遍历整个子树,找到后返回。
  而这些方法的复数形式,会找到所有符合要求的tag,以list的方式放回。他们的对应关系是:find->findall, findParent->findParents, findNextSibling->findNextSiblings...
  如:



1 print soup.findAll('p')
2 # [This is paragraph one., This is paragraph two.]
  
  这里我们重点讲一下find的几种用法,其他的类比:
    find(name=None, attrs={}, recursive=True, text=None, **kwargs)
  (ps:只讲几种用法,完整请看官方link : http://www.crummy.com/software/BeautifulSoup/bs3/documentation.zh.html#The%20basic%20find%20method:%20findAll%28name,%20attrs,%20recursive,%20text,%20limit,%20**kwargs%29)
  1) 搜索tag:



1 find(tagname)        # 直接搜索名为tagname的tag 如:find('head')
2 find(list)           # 搜索在list中的tag,如: find(['head', 'body'])
3 find(dict)           # 搜索在dict中的tag,如:find({'head':True, 'body':True})
4 find(re.compile('')) # 搜索符合正则的tag, 如:find(re.compile('^p')) 搜索以p开头的tag
5 find(lambda)         # 搜索函数返回结果为true的tag, 如:find(lambda name: if len(name) == 1) 搜索长度为1的tag
6 find(True)           # 搜索所有tag
  
  2) 搜索属性(attrs):



1 find(id='xxx')                                  # 寻找id属性为xxx的
2 find(attrs={id=re.compile('xxx'), algin='xxx'}) # 寻找id属性符合正则且algin属性为xxx的
3 find(attrs={id=True, algin=None})               # 寻找有id属性但是没有algin属性的
  3) 搜索文字(text):
  注意,文字的搜索会导致其他搜索给的值如:tag, attrs都失效。
  方法与搜索tag一致
  4) recursive, limit:
  recursive=False表示只搜索直接儿子,否则搜索整个子树,默认为True。
  当使用findAll或者类似返回list的方法时,limit属性用于限制返回的数量,如findAll('p', limit=2): 返回首先找到的两个tag
  
  *4、用next,previous寻找上下文tag(少用)
  
  这里我们主要看看next, next是取得当前的tag的下一个(按代码从上到下的顺序)tag块。这与contents是不一样的,千万别混淆了哦^ ^
  我们举个栗子来看看



1
2     a
3     b
4     c
5
  我们看看next的实际效果:



1 a = soup.a
2 b = soup.b
3 n1 = b.next
4 n2 = n1.next
  输出一下:



1 print a.next
2 # u'a'
3 print n1
4 # u'b'
5 print n2
6 # c
  所以,next仅仅是获取文档上的“下一个”的tag,和剖析树中的位置无关。
  当然也有findNext和findAllNext方法。
  至于previous, 表示上一个tag块,就类比一下吧~^ ^
  =======
  待续
  
  
  
  
  
  
  
  
  
  
  
  
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-58495-1-1.html 上篇帖子: Python基础05 缩进和选择 下篇帖子: 一步步用python制作游戏外挂
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表