BeautifulSoup是Python的一个第三方库,可用于帮助解析html/XML等内容,以抓取特定的网页信息。目前最新的是v4版本,这里主要总结一下我使用的v3版本解析html的一些常用方法。
准备
1.Beautiful Soup安装
为了能够对页面中的内容进行解析,本文使用Beautiful Soup。当然,本文的例子需求较简单,完全可以使用分析字符串的方式。
执行
1
|
sudo easy_install beautifulsoup4 |
即可安装。
2.requests模块的安装
requests模块用于加载要请求的web页面。
在python的命令行中输入import requests,报错说明requests模块没有安装。
我这里打算采用easy_install的在线安装方式安装,发现系统中并不存在easy_install命令,输入sudo apt-get install python-setuptools来安装easy_install工具。
执行sudo easy_install requests安装requests模块。
基础
1.初始化
导入模块
1
2
3
4
|
#!/usr/bin/env python from BeautifulSoup import BeautifulSoup #process html #from BeautifulSoup import BeautifulStoneSoup #process xml #import BeautifulSoup #all |
创建对象:str初始化,常用urllib2或browser返回的html初始化BeautifulSoup对象。
1
2
3
4
5
6
7
|
doc = [ 'hello' , ' This is paragraph one of ptyhonclub.org.', ' This is paragraph two of pythonclub.org.', ''] soup = BeautifulSoup(''.join(doc)) |
指定编码:当html为其他类型编码(非utf-8和asc ii),比如GB2312的话,则需要指定相应的字符编码,BeautifulSoup才能正确解析。
1
2
|
htmlCharset = "GB2312" soup = BeautifulSoup(respHtml, fromEncoding = htmlCharset) |
2.获取tag内容
寻找感兴趣的tag块内容,返回对应tag块的剖析树
1
2
3
4
|
head = soup.find( 'head' ) #head = soup.head #head = soup.contents[0].contents[0] print head |
返回内容:hello
说明一下,contents属性是一个列表,里面保存了该剖析树的直接儿子。
1
2
3
|
html = soup.contents[ 0 ] # <html> ... </html> head = html.contents[ 0 ] # <head> ... </head> body = html.contents[ 1 ] # <body> ... </body> |
3.获取关系节点
使用parent获取父节点
1
2
|
body = soup.body html = body.parent # html是body的父亲 |
使用nextSibling, previousSibling获取前后兄弟
1
2
3
|
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]也可得到 |
contents[]的灵活运用也可以寻找关系节点,寻找祖先或者子孙可以采用findParent(s), findNextSibling(s), findPreviousSibling(s)
4.find/findAll用法详解
函数原型:find(name=None, attrs={}, recursive=True, text=None, **kwargs),findAll会返回所有符合要求的结果,并以list返回。
tag搜索
1
2
3
4
5
6
|
find(tagname) # 直接搜索名为tagname的tag 如:find('head') find( list ) # 搜索在list中的tag,如: find(['head', 'body']) find( dict ) # 搜索在dict中的tag,如:find({'head':True, 'body':True}) find(re. compile (' ')) # 搜索符合正则的tag, 如:find(re.compile(' ^p')) 搜索以p开头的tag find( lambda ) # 搜索函数返回结果为true的tag, 如:find(lambda name: if len(name) == 1) 搜索长度为1的tag find( True ) # 搜索所有tag |
attrs搜索
1
2
3
4
5
6
7
8
|
find( id = 'xxx' ) # 寻找id属性为xxx的 find(attrs = { id = re. compile ( 'xxx' ), algin = 'xxx' }) # 寻找id属性符合正则且algin属性为xxx的 find(attrs = { id = True , algin = None }) # 寻找有id属性但是没有algin属性的 resp1 = soup.findAll( 'a' , attrs = { 'href' : match1}) resp2 = soup.findAll( 'h1' , attrs = { 'class' : match2}) resp3 = soup.findAll( 'img' , attrs = { 'id' : match3}) |
text搜索
文字的搜索会导致其他搜索给的值如:tag, attrs都失效。方法与搜索tag一致
1
2
3
4
5
|
print p1.text # u'This is paragraphone.' print p2.text # u'This is paragraphtwo.' # 注意:1,每个tag的text包括了它以及它子孙的text。2,所有text已经被自动转为unicode,如果需要,可以自行转码encode(xxx) |
recursive和limit属性
recursive=False表示只搜索直接儿子,否则搜索整个子树,默认为True。当使用findAll或者类似返回list的方法时,limit属性用于限制返回的数量,如findAll('p', limit=2): 返回首先找到的两个tag。
实例
本文以博客的文档列表页面为例,利用python对页面中的文章名进行提取。
文章列表页中的文章列表部分的url如下:
1
2
3
4
5
6
7
|
< ul class = "listing" > < li class = "listing-item" >< span class = "date" >2014-12-03</ span >< a href = "/post/linux_funtion_advance_feature" title = "Linux函数高级特性" >Linux函数高级特性</ a > </ li > < li class = "listing-item" >< span class = "date" >2014-12-02</ span >< a href = "/post/cgdb" title = "cgdb的使用" >cgdb的使用</ a > </ li > ... </ ul > |
代码:
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
|
#!/usr/bin/env python # -*- coding: utf-8 -*- ' a http parse test programe ' __author__ = 'kuring lv' import requests import bs4 archives_url = "http://kuring.me/archive" def start_parse(url) : print "开始获取(%s)内容" % url response = requests.get(url) print "获取网页内容完毕" soup = bs4.BeautifulSoup(response.content.decode( "utf-8" )) #soup = bs4.BeautifulSoup(response.text); # 为了防止漏掉调用close方法,这里使用了with语句 # 写入到文件中的编码为utf-8 with open ( 'archives.txt' , 'w' ) as f : for archive in soup.select( "li.listing-item a" ) : f.write(archive.get_text().encode( 'utf-8' ) + "\n" ) print archive.get_text().encode( 'utf-8' ) # 当命令行运行该模块时,__name__等于'__main__' # 其他模块导入该模块时,__name__等于'parse_html' if __name__ = = '__main__' : start_parse(archives_url) |