python爬虫之解析库Beautiful Soup
为何要用Beautiful Soup
Beautiful Soup是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式,
是一个标签的形式,来进行查找的,有点像jquery的形式。提升效率,我们在进行爬虫开发的时候,进程会用到正则来进行查找过滤的操作,纯手动会及其浪费时间。
Beautiful Soup示例摘自官网
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p> <p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p> <p class="story">...</p>
"""
这里先简单说明Beautiful Soup的查找方式,是一个标签树的形式。
在使用的时候实例化一个对象,这个对象就相当于整个html文件,将标签封装成对象的属性,查找的时候使用“.”
简单操作
from bs4 import BeautifulSoup
soup = BeautifulSoup(open("html_doc.html"),"lxml")
#简单的操作
#打印html文件的title属性
#print(soup.title)
#<title>The Dormouse's story</title> #打印标签的名字
# print(soup.title.name)
#title # 打印标签的内容
# print(soup.title.string)
#The Dormouse's story #打印soup中的p标签,但是这里是能找到的第一个
# print(soup.p)
# <p class="title"><b>The Dormouse's story</b></p> #打印soup中的p标签class名字,但是这里是能找到的第一个
# print(soup.p['class'],type(soup.p['class']))
# ['title'] <class 'list'> #类型是个列表 # 打印soup中的a标签,但是这里是能找到的第一个
# print(soup.a)
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a> #打印所有的a标签
# print(soup.find_all('a'))
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] #打印id=link3的标签
# print(soup.find(id="link3"))
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a> #从文档中找到所有<a>标签的链接:
# for link in soup.find_all('a'):
# print(link.get('href'))
# http://example.com/elsie
# http://example.com/lacie
# http://example.com/tillie # 从文档中获取所有文字内容:
# print(soup.get_text())
# The Dormouse's story
#
# The Dormouse's story
#
# Once upon a time there were three little sisters; and their names were
# Elsie,
# Lacie and
# Tillie;
# and they lived at the bottom of a well.
#
# ...
Tag
soup1 = BeautifulSoup('<b class="boldest">Extremely bold</b>',"lxml")
tag = soup1.b
# print(type(tag))
# <class 'bs4.element.Tag'>
Tag的Name属性
# print(tag.name)
# b
# 如果改变了tag的name,那将影响所有通过当前Beautiful Soup对象生成的HTML文档: # tag.name = "blockquote"
# print(tag)
# <blockquote class="boldest">Extremely bold</blockquote>
Tag的Attributes属性
一个tag可能有很多个属性. tag <b class="boldest"> 有一个 “class” 的属性,值为 “boldest” . tag的属性的操作方法与字典相同:
# print(tag['class'])
# ['boldest'] # 也可以直接”点”取属性, 比如: .attrs :
# print(tag.attrs)
# {'class': ['boldest']}
# print(soup.a.attrs['class'])
# ['sister']
# tag的属性可以被添加,删除或修改. 再说一次, tag的属性操作方法与字典一样 # tag['class'] = 'verybold'
# tag['id'] = 1
# print(tag)
# <blockquote class="verybold" id="1">Extremely bold</blockquote> # del tag['class']
# del tag['id']
# print(tag)
# <blockquote>Extremely bold</blockquote> # tag['class']
# KeyError: 'class'
# print(tag.get('class'))
# None
子节点操作:
.contents属性
#.contents
# tag的 .contents 属性可以将tag的子节点以列表的方式输出:
# print(soup)
#print(soup.contents) #这里打印的是整个html标签
#print("________")
#print(soup.head.contents) #打印出来的是head下的列表,可以借助元组去重
##['\n', <meta charset="utf-8"/>, '\n', <title>The Dormouse's story</title>, '\n']
#print(len(soup.head.contents))
##5
#print(soup.head.contents[1].name)
##meta
descendants属性
#descendants属性
# .contents 和 .children 属性仅包含tag的直接子节点.例如,<head>标签只有一个直接子节点<title>
#但如果我们需要递归循环的话, .descendants 属性可以对所有tag的子孙节点进行递归循环 [5] :
# des_tag = soup.head
# print(des_tag)
# for child in des_tag.descendants:
# print(child,end="") # 输出的字符串中可能包含了很多空格或空行,使用 .stripped_strings 可以去除多余空白内容:(代替.string)
父节点:
parent
#parent
# title_tag = soup.title
# print(title_tag)
## <title>The Dormouse's story</title>
# print(title_tag.parent)
## <head>
## <meta charset="utf-8"/>
## <title>The Dormouse's story</title>
##</head>
parents
#通过元素的 .parents 属性可以递归得到元素的所有父辈节点,下面的例子使用了 .parents 方法遍历了<a>标签到根节点的所有节点.
#link = soup.a
# link
## <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
# for parent in link.parents:
# if parent is None:
# print(parent)
# else:
# print(parent.name)
##p
## body
##html
## [document]
## None
兄弟节点:
.next_sibling 和 .previous_sibling 属性
# link2 = soup.find(id='link2')
# print(link2)
# # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
# #实际文档中的tag的 .next_sibling 和 .previous_sibling 属性通常是字符串或空白. 看看“爱丽丝”文档:
# print(link2.next_sibling) #由于本文是以爱丽丝为版本,所以这里下一个是“and”
# print(link2.previous_sibling) #上一个是一个",".
.next_siblings 和 .previous_siblings属性
# 通过 .next_siblings 和 .previous_siblings 属性可以对当前节点的兄弟节点迭代输出:
# link2 = soup.find(id='link2')
# for sibling in link2.next_siblings:
# print(sibling)
#
# # and
#
# # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
# # ;
# # and they lived at the bottom of a well.
# link2 = soup.find(id='link2')
# for sibling in link2.previous_siblings:
# print(sibling)
#
# # ,
# #
# # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
# # Once upon a time there were three little sisters; and their names were
搜索文档树:
# #find 和 findall() 唯一的区别是 find_all() 方法的返回结果是值包含一个元素的列表,而 find() 方法直接返回结果.
# find = soup.find('a')
# print(find)
# # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
# print("----------------")
# findall = soup.find_all('a')
# print(findall) #这个是个列表,可以索引取值
# #[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
# findall2 = soup.find_all(attrs={'id':'link2'}) #后面可以加属性来进行过滤
# print("---------")
# print(findall2)
# # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
正则表达式
#如果传入正则表达式作为参数,Beautiful Soup会通过正则表达式的 match()
# 来匹配内容.下面例子中找出所有以b开头的标签,这表示<body>和<b>标签都应该被找到: # import re
# for tag in soup.find_all(re.compile("^b")):
# print(tag.name)
# #b
# #b
判断是否有那个属性
# findall可以传入函数作为过滤的参数
# 下面方法校验了当前元素,如果包含 class 属性却不包含 id 属性,那么将返回 True:
#
# def has_class_but_no_id(tag):
# return tag.has_attr('class') and not tag.has_attr('id')
# 将这个方法作为参数传入 find_all() 方法,将得到所有<p>标签:
#
# soup.find_all(has_class_but_no_id)
# [<p class="title"><b>The Dormouse's story</b></p>,
# <p class="story">Once upon a time there were...</p>,
# <p class="story">...</p>]
findall的属性(find和findall差不多)
# find_all( name , attrs , recursive , string , **kwargs )
#
# soup.find_all("title")
# # [<title>The Dormouse's story</title>]
#
# soup.find_all("p", "title")
# # [<p class="title"><b>The Dormouse's story</b></p>]
#
# soup.find_all("a")
# # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
#
# soup.find_all(id="link2")
# # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
#
# import re
# soup.find(string=re.compile("sisters"))
# # u'Once upon a time there were three little sisters; and their names were\n'
findall中 name参数
简单的用法如下:
soup.find_all("title")
# [<title>The Dormouse's story</title>]
重申: 搜索 name 参数的值可以使任一类型的 过滤器 ,字符窜,正则表达式,列表,方法或是 True .
keyword 参数
如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索,如果包含一个名字为 id 的参数,Beautiful Soup会搜索每个tag的”id”属性.
soup.find_all(id='link2')
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
如果传入 href 参数,Beautiful Soup会搜索每个tag的”href”属性:
soup.find_all(href=re.compile("elsie"))
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
搜索指定名字的属性时可以使用的参数值包括 字符串 , 正则表达式 , 列表, True .
下面的例子在文档树中查找所有包含 id 属性的tag,无论 id 的值是什么:
soup.find_all(id=True)
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
使用多个指定名字的参数可以同时过滤tag的多个属性:
soup.find_all(href=re.compile("elsie"), id='link1')
# [<a class="sister" href="http://example.com/elsie" id="link1">three</a>]
有些tag属性在搜索不能使用,比如HTML5中的 data-* 属性:
data_soup = BeautifulSoup('<div data-foo="value">foo!</div>')
data_soup.find_all(data-foo="value")
# SyntaxError: keyword can't be an expression
但是可以通过 find_all() 方法的 attrs 参数定义一个字典参数来搜索包含特殊属性的tag:
data_soup.find_all(attrs={"data-foo": "value"})
# [<div data-foo="value">foo!</div>]
其他
find_parents()返回所有祖先节点,find_parent()返回直接父节点。
find_next_siblings()返回后面所有兄弟节点,find_next_sibling()返回后面第一个兄弟节点。
find_previous_siblings()返回前面所有兄弟节点,find_previous_sibling()返回前面第一个兄弟节点。
find_all_next()返回节点后所有符合条件的节点, find_next()返回第一个符合条件的节点
find_all_previous()返回节点后所有符合条件的节点, find_previous()返回第一个符合条件的节点
CSS选择器
#Beautiful Soup支持大部分的CSS选择器 http://www.w3.org/TR/CSS2/selector.html [6] , 在 Tag 或 BeautifulSoup 对象的 .select() 方法中传入字符串参数, 即可使用CSS选择器的语法找到tag:
soup.select("title")
# [<title>The Dormouse's story</title>]
soup.select("p nth-of-type(3)")
# [<p class="story">...</p>]
通过tag标签逐层查找:
soup.select("body a")
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
soup.select("html head title")
# [<title>The Dormouse's story</title>]
找到某个tag标签下的直接子标签 [6] :
soup.select("head > title")
# [<title>The Dormouse's story</title>]
soup.select("p > a")
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
soup.select("p > a:nth-of-type(2)")
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
soup.select("p > #link1")
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
soup.select("body > a")
# []
找到兄弟节点标签:
soup.select("#link1 ~ .sister")
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
soup.select("#link1 + .sister")
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
通过CSS的类名查找:
soup.select(".sister")
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
soup.select("[class~=sister]")
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
通过tag的id查找:
soup.select("#link1")
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
soup.select("a#link2")
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
同时用多种CSS选择器查询元素:
soup.select("#link1,#link2")
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
通过是否存在某个属性来查找:
soup.select('a[href]')
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
通过属性的值来查找:
soup.select('a[href="http://example.com/elsie"]')
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
soup.select('a[href^="http://example.com/"]')
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
soup.select('a[href$="tillie"]')
# [<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
soup.select('a[href*=".com/el"]')
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
通过语言设置来查找:
multilingual_markup = """
<p lang="en">Hello</p>
<p lang="en-us">Howdy, y'all</p>
<p lang="en-gb">Pip-pip, old fruit</p>
<p lang="fr">Bonjour mes amis</p>
"""
multilingual_soup = BeautifulSoup(multilingual_markup)
multilingual_soup.select('p[lang|=en]')
# [<p lang="en">Hello</p>,
# <p lang="en-us">Howdy, y'all</p>,
# <p lang="en-gb">Pip-pip, old fruit</p>]
返回查找到的元素的第一个
soup.select_one(".sister")
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
对于熟悉CSS选择器语法的人来说这是个非常方便的方法.Beautiful Soup也支持CSS选择器API,
如果你仅仅需要CSS选择器的功能,那么直接使用 lxml 也可以, 而且速度更快,支持更多的CSS选择器语法,
但Beautiful Soup整合了CSS选择器的语法和自身方便使用API.
解释器种类:
| 解析器 | 使用方法 | 优势 | 劣势 |
|---|---|---|---|
| Python标准库 | BeautifulSoup(markup, "html.parser") |
|
|
| lxml HTML 解析器 | BeautifulSoup(markup, "lxml") |
|
|
| lxml XML 解析器 |
|
|
|
| html5lib | BeautifulSoup(markup, "html5lib") |
|
|
python爬虫之解析库Beautiful Soup的更多相关文章
- 小白学 Python 爬虫(21):解析库 Beautiful Soup(上)
小白学 Python 爬虫(21):解析库 Beautiful Soup(上) 人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前 ...
- 小白学 Python 爬虫(22):解析库 Beautiful Soup(下)
人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...
- Python爬虫利器二之Beautiful Soup的用法
上一节我们介绍了正则表达式,它的内容其实还是蛮多的,如果一个正则匹配稍有差池,那可能程序就处在永久的循环之中,而且有的小伙伴们也对写正则表达式的写法用得不熟练,没关系,我们还有一个更强大的工具,叫Be ...
- Python3编写网络爬虫06-基本解析库Beautiful Soup的使用
二.Beautiful Soup 简介 就是python的一个HTML或XML的解析库 可以用它来很方便的从网页中提取数据 0.1 提供一些简单的 python式的函数来处理导航,搜索,修改分析树等功 ...
- python爬虫(7)--Beautiful Soup的用法
1.Beautiful Soup简介 简单来说,Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据. Beautiful Soup提供一些简单的.python式的函数用来 ...
- Python爬虫【解析库之beautifulsoup】
解析库的安装 pip3 install beautifulsoup4 初始化 BeautifulSoup(str,"解析库") from bs4 import BeautifulS ...
- python爬虫三大解析库之XPath解析库通俗易懂详讲
目录 使用XPath解析库 @(这里写自定义目录标题) 使用XPath解析库 1.简介 XPath(全称XML Path Languang),即XML路径语言,是一种在XML文档中查找信息的语言. ...
- Python爬虫【解析库之pyquery】
该库跟jQuery的使用方法基本一样 http://pyquery.readthedocs.io/ 官方文档 解析库的安装 pip3 install pyquery 初始化 1.字符串初始化 htm ...
- Python的html和xml解析库Beautiful Soup
网站:http://www.crummy.com/software/BeautifulSoup/ 版权声明:本文博主原创文章,博客,未经同意不得转载.
随机推荐
- 还是畅通工程,最小生成树kruskal
题目描述: 某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离.省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可 ...
- ulimit系统资源的设定
使用ulimit -a 可以查看系统使用的资源 core file size 设定core文件的最大值,单位为区块,如果指定为0,不会产生core文件 data seg size 设定数据段的最大值, ...
- 关于maven环境变量的配置问题
开始使用“MAVEN_HOME”配置完环境变量后,在cmd中输入mvn -v提示不是内部命令,后直接在PATH 路径里面添加maven所在的位置+\bin,比如,maven的路径为E:\maven\a ...
- Windows10 VS2017 C++ xml解析(tinyxml2库)
首先下载tinyxml2 7.0.1库: https://github.com/leethomason/tinyxml2/releases 打开tinyxml2,然后升级sdk,解决方案->重定 ...
- 自动化测试-4.selenium的xpath定位
前言 在上一篇简单的介绍了用工具查看目标元素的xpath地址,工具查看比较死板,不够灵活,有时候直接复制粘贴会定位不到.这个时候就需要自己手动的去写xpath了,这一篇详细讲解xpath的一些语法. ...
- linux c 获取console 结果
getLine(char *line, const char *cmd) { FILE *pf = popen(cmd, "r"); if (pf == NULL) { ; } f ...
- Zookeeper之入门(原理、基础知识)
Zookeeper介绍 Zookeeper是分布式应用程序的协调服务框架,是Hadoop的重要组件.ZK要解决的问题: 1.分布式环境下的数据一致性. 2.分布式环境下的统一命名服务 3.分布式环境下 ...
- c++简单实现对mysql数据库操作
1.连接数据库 #include <mysql.h> #include <iostream> #include<string> #include<vector ...
- 洛谷P1219 :八皇后(DFS+回溯)
题目描述 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序列2 4 6 1 3 ...
- 学习笔记GAN002:DCGAN
Ian J. Goodfellow 论文:https://arxiv.org/abs/1406.2661 两个网络:G(Generator),生成网络,接收随机噪声Z,通过噪声生成样本,G(z).D( ...