网页解析-提取结构化数据
BeautifulSoup
简介
BeautifulSoup 是一个可以从HTML或XML文件中提取数据的Python库,它的使用方式相对于正则来说更加的简单方便,常常能够节省我们大量的时间。
官方中文文档的:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html
BeautifulSoup的安装也是非常方便的,pip安装即可。
pip install beautifulsoup4
简单例子

1560427418742.png
指定解析器
BeautifulSoup解析网页需要指定一个可用的解析器,以下是主要几种解析器:
解析器 |
使用方法 |
优势 |
劣势 |
Python标准库 |
BeautifulSoup(markup, "html.parser") |
Python的内置标准库执行速度适中文档容错能力强 |
Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差 |
lxml HTML 解析器 |
BeautifulSoup(markup, "lxml") |
速度快文档容错能力强 |
需要安装C语言库 |
lxml XML 解析器 |
BeautifulSoup(markup, ["lxml", "xml"])``BeautifulSoup(markup, "xml") |
速度快唯一支持XML的解析器 |
需要安装C语言库 |
html5lib |
BeautifulSoup(markup, "html5lib") |
最好的容错性以浏览器的方式解析文档生成HTML5格式的文档 |
速度慢不依赖外部扩展 |
由于这个解析的过程在大规模的爬取中是会影响到整个爬虫系统的速度的,所以推荐使用的是lxml,速度会快很多,而lxml需要单独安装:
pip install lxml soup = BeautifulSoup(html_doc, 'lxml')
指定提示:如果一段HTML或XML文档格式不正确的话,那么在不同的解析器中返回的结果可能是不一样的,所以要指定某一个解析器。
节点对象
Tag
tag对象可以说是BeautifulSoup中最为重要的对象,通过BeautifulSoup来提取数据基本都围绕着这个对象来进行操作。
>>tag就是标签的意思,tag还有许多的方法和属性。
>>name: 每一个tag对象都有name属性,为标签的名字。
>>Attributes: 在HTML中,tag可能有多个属性,所以tag属性的取值跟字典相同。
>>get_text(): 通过get_text()方法我们可以获取某个tag下所有的文本内容。
NavigableString
NavigableString的意思是可以遍历的字符串,一般被标签包裹在其中的的文本就是NavigableString格式。
soup = BeautifulSoup('<p>do someing </p>')
soup.p.string
>>>'do someing '
BeautifulSoup
BeautifulSoup对象就是解析网页获得的对象。
Comment
Comment指的是在网页中的注释以及特殊字符串。
Tag与遍历文档树
tag对象可以说是BeautifulSoup中最为重要的对象,通过BeautifulSoup来提取数据基本都围绕着这个对象来进行操作。
首先,一个节点中是可以包含多个子节点和多个字符串的。例如html节点中包含着head和body节点。所以BeautifulSoup就可以将一个HTML的网页用这样一层层嵌套的节点来进行表示。
descendants
contents和children获取的是某个节点的直接子节点,而无法获得子孙节点。通过descendants可以获得所有子孙节点,返回的结果跟children一样,需要迭代或者转类型使用。。
父节点parent和parents
有时我们也需要去获取某个节点的父节点,也就是包裹着当前节点的节点而使用parents则可以获得当前节点递归到顶层的所有父辈元素。
contents和children
通过contents可以获取某个节点所有的子节点,包括里面的NavigableString对象。获取的子节点是列表格式。而通过children同样的是获取某个节点的所有子节点,但是返回的是一个迭代器,这种方式会比列表格式更加的节省内存。
string和strings
我们常常会遇到需要获取某个节点中的文本值的情况,如果这个节点中只有一个字符串,那么使用string可以正常将其取出。
而如果这个节点中有多个字符串的时候,BeautifulSoup就无法确定要取出哪个字符串了,这时候需要使用strings。使用stripped_strings可以将全是空白的行去掉。
兄弟节点
兄弟节点指的就是父节点相同的节点。
next_sibling 和 previous_sibling 下一个兄弟和上一个兄弟节点
next_siblings 和 previous_siblings 下面所有兄弟和上面所有兄弟节点
***find_all()
上方这种直接通过属性来进行访问属性的方法,很多时候只能适用于比较简单的一些场景,所以BeautifulSoup还提供了搜索整个文档树的方法find_all()。
1.通过name搜索,find_all('b')可以直接查找出整个文档树中所有的b标签,并返回列表
2.通过属性搜索,我们在搜索的时候一般只有标签名是不够的,因为可能同名的标签很多,那么这时候我们就要通过标签的属性来进行搜索。这时候我们可以通过传递给attrs一个字典参数来搜索属性。
soup.find_all(attrs={'class': 'sister'})
3.通过文本搜索,在find_all()方法中,还可以根据文本内容来进行搜索。soup.find_all(text="Elsie")
4.限制查找范围为子节点
find_all()方法会默认的去所有的子孙节点中搜索,而如果将recursive参数设置为False,则可以将搜索范围限制在直接子节点中。 soup.html.find_all("title", recursive=False)
5.通过正则表达式来筛选查找结果在BeautifulSoup中,也是可以与re模块进行相互配合的,将re.compile编译的对象传入find_all()方法,即可通过正则来进行搜索。
tags = soup.find_all(re.compile("^b"))
CSS选择器
在BeautifulSoup中,同样也支持使用CSS选择器来进行搜索。使用select(),在其中传入字符串参数,就可以使用CSS选择器的语法来找到tag。
>>soup.select('title')
>>soup.select('p > a')
XPath
简介
XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。
相比于BeautifulSoup,Xpath在提取数据时会更有效率。
安装:
在python中很多库都提供XPath的功能,但是最流行的还是lxml这个库,效率最高。在之前BeautifulSoup中我们也介绍了lxml是如何安装的。
pip install lxml
语法
XPath 使用路径表达式在 XML/HTML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。
下面列出了最有用的路径表达式:
表达式 |
描述 |
nodename |
选取当前节点的所有nodename子节点 |
/ |
从根节点选取 |
// |
从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
. |
选取当前节点 |
.. |
选取当前节点的父节点 |
@ |
选取属性 |
谓语
谓语用来查找某个或某些特定的节点或者包含某个指定值的节点
谓语被嵌在方括号中。实例:
在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果。
路径表达式 |
结果 |
//bookstore/book[1] |
选取属于 bookstore 子元素的第一个 book 元素。 |
//bookstore/book[last()] |
选取属于 bookstore 子元素的最后一个 book 元素。 |
//bookstore/book[last()-1] |
选取属于 bookstore 子元素的倒数第二个 book 元素。 |
//bookstore/book[position()<3] |
选取最前面的两个属于 bookstore 元素的子元素的 book 元素。 |
//title[@lang] |
选取所有拥有名为 lang 的属性的 title 元素。 |
//title[@lang='eng'] |
选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。 |
//bookstore/book[price>35.00] |
选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。 |
//bookstore/book[price>35.00]/title |
选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。 |
选取未知节点XPath通配符可用来选取未知节点
通配符 |
描述 |
例子 |
结果 |
* |
匹配任何元素节点 |
//bookstore/* |
选取bookstore元素的所有子元素。 |
@* |
匹配任何属性节点 |
//* |
选取文档中国的所有元素 |
node() |
匹配任何类型的节点 |
//title[@*] |
选取所有带有属性的title元素 |
选取多个路径通过在路径表达式中使用"|"运算符,您可以选取若干个路径。在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
路径表达式 |
结果 |
//book/title | //book/price |
选取book元素的所有title和price元素 |
//title | //price |
选取文档中所有的title和price元素 |
//bookstore/book/title | //price |
选取bookstore元素的book元素的所有title元素,以及文档中所有的price元素 |
获取文本
用text()获取某个节点下的文本
print(page.xpath('//book[1]/author/text()'))
用string()获取某个节点下所有的文本
print(page.xpath('string(//book[1]/author)'))
作业
1.全书网小说爬, 爬取一部小说的简介信息,如作者, 类型, 名称, 当前连载状态等, 存入txt文件中.
(代码和数据结果截图, 不能使用课上所演示的数据)
网友评论