python爬虫入门教程--HTML文本的解析库BeautifulSoup(四)
前言
python爬虫系列文章的第3篇介绍了网络请求库神器Requests,请求把数据返回来之后就要提取目标数据,不同的网站返回的内容通常有多种不同的格式,一种是json格式,这类数据对开发者来说最友好。另一种XML格式的,还有一种最常见格式的是HTML文档,今天就来讲讲如何从HTML中提取出感兴趣的数据
自己写个HTML解析器来解析吗?还是用正则表达式?这些都不是最好的办法,好在,Python社区在这方便早就有了很成熟的方案,BeautifulSoup就是这一类问题的克星,它专注于HTML文档操作,名字来源于LewisCarroll的一首同名诗歌。
BeautifulSoup是一个用于解析HTML文档的Python库,通过BeautifulSoup,你只需要用很少的代码就可以提取出HTML中任何感兴趣的内容,此外,它还有一定的HTML容错能力,对于一个格式不完整的HTML文档,它也可以正确处理。
安装BeautifulSoup
pipinstallbeautifulsoup4
BeautifulSoup3被官方放弃维护,你要下载最新的版本BeautifulSoup4。
HTML标签
学习BeautifulSoup4前有必要先对HTML文档有一个基本认识,如下代码,HTML是一个树形组织结构。
hello,world BeautifulSoup 如何使用BeautifulSoup
- 它由很多标签(Tag)组成,比如html、head、title等等都是标签
- 一个标签对构成一个节点,比如...是一个根节点
- 节点之间存在某种关系,比如h1和p互为邻居,他们是相邻的兄弟(sibling)节点
- h1是body的直接子(children)节点,还是html的子孙(descendants)节点
- body是p的父(parent)节点,html是p的祖辈(parents)节点
- 嵌套在标签之间的字符串是该节点下的一个特殊子节点,比如“hello,world”也是一个节点,只不过没名字。
使用BeautifulSoup
构建一个BeautifulSoup对象需要两个参数,第一个参数是将要解析的HTML文本字符串,第二个参数告诉BeautifulSoup使用哪个解析器来解析HTML。
解析器负责把HTML解析成相关的对象,而BeautifulSoup负责操作数据(增删改查)。”html.parser”是Python内置的解析器,”lxml”则是一个基于c语言开发的解析器,它的执行速度更快,不过它需要额外安装
通过BeautifulSoup对象就可以定位到HTML中的任何一个标签节点。
frombs4importBeautifulSoup text="""hello,world BeautifulSoup
如何使用BeautifulSoup
第二个p标签
python """ soup=BeautifulSoup(text,"html.parser") #title标签 >>>soup.title hello,world #p标签 >>>soup.p\u5982\u4f55\u4f7f\u7528BeautifulSoup #p标签的内容 >>>soup.p.string u'\u5982\u4f55\u4f7f\u7528BeautifulSoup'
BeatifulSoup将HTML抽象成为4类主要的数据类型,分别是Tag,NavigableString,BeautifulSoup,Comment。每个标签节点就是一个Tag对象,NavigableString对象一般是包裹在Tag对象中的字符串,BeautifulSoup对象代表整个HTML文档。例如:
>>>type(soup)>>>type(soup.h1) >>>type(soup.p.string)
Tag
每个Tag都有一个名字,它对应HTML的标签名称。
>>>soup.h1.name u'h1' >>>soup.p.name u'p'
标签还可以有属性,属性的访问方式和字典是类似的,它返回一个列表对象
>>>soup.p['class'] [u'bold']
NavigableString
获取标签中的内容,直接使用.stirng即可获取,它是一个NavigableString对象,你可以显式地将它转换为unicode字符串。
>>>soup.p.string u'\u5982\u4f55\u4f7f\u7528BeautifulSoup' >>>type(soup.p.string)>>>unicode_str=unicode(soup.p.string) >>>unicode_str u'\u5982\u4f55\u4f7f\u7528BeautifulSoup'
基本概念介绍完,现在可以正式进入主题了,如何从HTML中找到我们关心的数据?BeautifulSoup提供了两种方式,一种是遍历,另一种是搜索,通常两者结合来完成查找任务。
遍历文档树
遍历文档树,顾名思义,就是是从根节点html标签开始遍历,直到找到目标元素为止,遍历的一个缺陷是,如果你要找的内容在文档的末尾,那么它要遍历整个文档才能找到它,速度上就慢了。因此还需要配合第二种方法。
通过遍历文档树的方式获取标签节点可以直接通过.标签名的方式获取,例如:
获取body标签:
>>>soup.body\nBeautifulSoup
\n\u5982\u4f55\u4f7f\u7528BeautifulSoup \n
获取p标签
>>>soup.body.p\u5982\u4f55\u4f7f\u7528BeautifulSoup
获取p标签的内容
>>>soup.body.p.string \u5982\u4f55\u4f7f\u7528BeautifulSoup
前面说了,内容也是一个节点,这里就可以用.string的方式得到。遍历文档树的另一个缺点是只能获取到与之匹配的第一个子节点,例如,如果有两个相邻的p标签时,第二个标签就没法通过.p的方式获取,这是需要借用next_sibling属性获取相邻且在后面的节点。此外,还有很多不怎么常用的属性,比如:.contents获取所有子节点,.parent获取父节点,更多的参考请查看官方文档。
搜索文档树
搜索文档树是通过指定标签名来搜索元素,另外还可以通过指定标签的属性值来精确定位某个节点元素,最常用的两个方法就是find和find_all。这两个方法在BeatifulSoup和Tag对象上都可以被调用。
find_all()
find_all(name,attrs,recursive,text,**kwargs)
find_all的返回值是一个Tag组成的列表,方法调用非常灵活,所有的参数都是可选的。
第一个参数name是标签节点的名字。
#找到所有标签名为title的节点 >>>soup.find_all("title") [hello,world ] >>>soup.find_all("p") [\xc8\xe7\xba\xce\xca\xb9\xd3\xc3BeautifulSoup ,
\xb5\xda\xb6\xfe\xb8\xf6p\xb1\xea\xc7\xa9 ]
第二个参数是标签的class属性值
#找到所有class属性为big的p标签 >>>soup.find_all("p","big") [\xb5\xda\xb6\xfe\xb8\xf6p\xb1\xea\xc7\xa9 ]
等效于
>>>soup.find_all("p",class_="big") [\xb5\xda\xb6\xfe\xb8\xf6p\xb1\xea\xc7\xa9 ]
因为class是Python关键字,所以这里指定为class_。
kwargs是标签的属性名值对,例如:查找有href属性值为"http://foofish.net"的标签
>>>soup.find_all(href="http://foofish.net"rel="externalnofollow"rel="externalnofollow"rel="externalnofollow"rel="externalnofollow"rel="externalnofollow"rel="externalnofollow") [python]
当然,它还支持正则表达式
>>>importre >>>soup.find_all(href=re.compile(" data-ke-src="http:></pre> <p>当然,它还支持正则表达式</p> <pre>>>>importre >>>soup.find_all(href=re.compile("^http")) [python]
属性除了可以是具体的值、正则表达式之外,它还可以是一个布尔值(True/Flase),表示有属性或者没有该属性。
>>>soup.find_all(id=" data-ke-src="http:></pre> <p>属性除了可以是具体的值、正则表达式之外,它还可以是一个布尔值(True/Flase),表示有属性或者没有该属性。</p> <pre>>>>soup.find_all(id="key1") [\xb5\xda\xb6\xfe\xb8\xf6p\xb1\xea\xc7\xa9 ] >>>soup.find_all(id=True) [
\xb5\xda\xb6\xfe\xb8\xf6p\xb1\xea\xc7\xa9 ]
遍历和搜索相结合查找,先定位到body标签,缩小搜索范围,再从body中找a标签。
>>>body_tag=soup.body >>>body_tag.find_all("a") [python]
find()
find方法跟find_all类似,唯一不同的地方是,它返回的单个Tag对象而非列表,如果没找到匹配的节点则返回None。如果匹配多个Tag,只返回第0个。
>>>body_tag.find(" data-ke-src="http:></pre> <p><strong>find()</strong> </p><p>find方法跟find_all类似,唯一不同的地方是,它返回的单个Tag对象而非列表,如果没找到匹配的节点则返回None。如果匹配多个Tag,只返回第0个。</p> <pre>>>>body_tag.find("a")python >>>body_tag.find("p") \xc8\xe7\xba\xce\xca\xb9\xd3\xc3BeautifulSoup
get_text()
获取标签里面内容,除了可以使用.string之外,还可以使用get_text方法,不同的地方在于前者返回的一个NavigableString对象,后者返回的是unicode类型的字符串。
>>>p1=body_tag.find('p').get_text() >>>type(p1)>>>p1 u'\xc8\xe7\xba\xce\xca\xb9\xd3\xc3BeautifulSoup' >>>p2=body_tag.find(" data-ke-src="http:></pre> <p><strong>get_text()</strong> </p><p>获取标签里面内容,除了可以使用.string之外,还可以使用get_text方法,不同的地方在于前者返回的一个NavigableString对象,后者返回的是unicode类型的字符串。</p> <pre>>>>p1=body_tag.find('p').get_text() >>>type(p1) <type'unicode'> >>>p1 u'\xc8\xe7\xba\xce\xca\xb9\xd3\xc3BeautifulSoup' >>>p2=body_tag.find("p").string >>>type(p2) >>>p2 u'\xc8\xe7\xba\xce\xca\xb9\xd3\xc3BeautifulSoup' >>>
实际场景中我们一般使用get_text方法获取标签中的内容。
总结
BeatifulSoup是一个用于操作HTML文档的Python库,初始化BeatifulSoup时,需要指定HTML文档字符串和具体的解析器。BeatifulSoup有3类常用的数据类型,分别是Tag、NavigableString、和BeautifulSoup。查找HTML元素有两种方式,分别是遍历文档树和搜索文档树,通常快速获取数据需要二者结合。
好了,以上就是关于这篇文章的全部内容,希望本文的内容对大家学习或者使用python能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。