爬虫(七):BeatifulSoup模块
1. Beautiful Soup介绍
Beautiful Soup是一个可以从HTML或XML文件中提取数据的Python库。能将即将要进行解析的源码加载到bs对象,调用bs对象中相关的方法或属性进行源码中的相关标签的定位,并获取定位到的标签之间存在的文本或者属性值。
它能够通过你喜欢的转换器实现惯用的文档导航、查找、修改文档的方式。Beautiful Soup会帮你节省数小时甚至数天的工作时间。
1.1 安装bs4
pip install 包名 -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
1.2 初始化
from bs4 import BeautifulSoup soup = BeautifulSoup("<html>A Html Text</html>", "html.parser")
两个参数:第一个参数是要解析的html文本,第二个参数是使用那种解析器,对于HTML来讲就是html.parser,这个是bs4自带的解析器。
如果一段HTML或XML文档格式不正确的话,那么在不同的解析器中返回的结果可能是不一样的。
格式化输出:
soup.prettify()
1.3 对象
Beautfiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:tag,NavigableString,BeautifulSoup,Comment。
1.3.1 tag
Tag对象与xml或html原生文档中的tag相同。
from bs4 import BeautifulSoup soup = BeautifulSoup('<b class="boldest">Extremely bold</b>','xml')
tag = soup.b
print(type(tag))# <class 'bs4.element.Tag'>
如果不存在,则返回 None,如果存在多个,则返回第一个。
每个tag都有自己的名字。
tag = soup.b
print(tag.name)# b
tag的属性是一个字典。
tag = soup.b
print(tag['class'])# boldest
print(tag.attrs)# {'class': 'boldest'}
print(type(tag.attrs))# <class 'dict'>
多值属性,最常见的多值属性是class,多值属性的返回list。
soup = BeautifulSoup('<p class="body strikeout"></p>','xml') print(soup.p['class']) # ['body', 'strikeout'] print(soup.p.attrs) # {'class': ['body', 'strikeout']}
如果某个属性看起来好像有多个值,但在任何版本的HTML定义中都没有被定义为多值属性,那么Beautiful Soup会将这个属性作为字符串返回。
soup = BeautifulSoup('<p id="my id"></p>', 'html.parser')
print(soup.p['id']) # 'my id'
text属性返回tag的所有字符串连成的字符串。
1.3.2 NavigableString
字符串常被包含在tag内,BeautifulSoup用NavigableString类来包装tag中的字符串。但是字符串中不能包含其他tag。
soup = BeautifulSoup('<b class="boldest">Extremely bold</b>','xml') s = soup.b.string print(s) # Extremely bold print(type(s)) # <class 'bs4.element.NavigableString'>
1.3.3 BeautifulSoup
BeautifulSoup 对象表示的是一个文档的全部内容。大部分时候,可以把它当作Tag对象。但是BeautifulSoup对象并不是真正的HTML或XML的 tag,它没有attribute属性,name属性是一个值为“[document]”的特殊属性。
1.3.4 Comment
Comment一般表示文档的注释部分。
oup = BeautifulSoup("<b><!--This is a comment--></b>",'xml') comment = soup.b.string print(comment) # This is a comment print(type(comment)) # <class 'bs4.element.Comment'>
1.4 遍历
1.4.1 子节点
contents属性返回所有子节点的列表,包括NavigableString类型节点。如果节点当中有换行符,会被当做是NavigableString类型节点而作为一个子节点。
NavigableString 类型节点没有contents属性,因为没有子节点。
soup = BeautifulSoup("""<div>
<span>test</span>
</div>
""",'xml') element = soup.div.contents print(element) # ['\n', <span>test</span>, '\n']
children属性跟contents属性基本一样,只不过返回的不是子节点列表,而是子节点的可迭代对象。
descendants属性返回tag的所有子孙节点。
如果tag只有一个NavigableString类型子节点,那么这个tag可以使用.string得到子节点。
如果一个tag仅有一个子节点,那么这个tag也可以使用.string方法,输出结果与当前唯一子节点的.string结果相同。
如果tag包含了多个子节点,tag就无法确定.string方法应该调用哪个子节点的内容,.string 的输出结果是None。
soup = BeautifulSoup("""<div>
<p><span><b>test</b></span></p>
</div>
""",'xml') element = soup.p.string print(element) # test print(type(element)) # <class 'bs4.element.NavigableString'>
特别注意,为了清楚显示,一般我们会将html节点换行缩进显示,而在BeautifulSoup中会被认为是一个NavigableString类型子节点,导致出错。上例中,如果改成element = soup.div.string就会出错。
如果tag中包含多个字符串,可以用strings属性来获取。如果返回结果中要去除空行,则可以用stripped_strings属性。
soup = BeautifulSoup("""<div>
<p> </p>
<p>test 1</p>
<p>test 2</p>
</div>
""", 'html.parser') element = soup.div.stripped_strings print(list(element)) # ['test 1', 'test 2']
1.4.2 父节点
parent属性返回某个元素(tag、NavigableString)的父节点,文档的顶层节点的父节点是BeautifulSoup对象,BeautifulSoup对象的父节点是None。
parents属性递归得到元素的所有父辈节点,包括BeautifulSoup对象。
1.4.3 兄弟节点
next_sibling返回后一个兄弟节点,previous_sibling返回前一个兄弟节点。直接看个例子,注意别被换行缩进搅了局。
soup = BeautifulSoup("""<div>
<p>test 1</p><b>test 2</b><h>test 3</h></div>
""", 'html.parser') print(soup.b.next_sibling) # <h>test 3</h> print(soup.b.previous_sibling) # <p>test 1</p> print(soup.h.next_sibling) # None
next_siblings返回后面的兄弟节点
previous_siblings返回前面的兄弟节点
1.4.4 回退和前进
把html解析看成依次解析标签的一连串事件,BeautifulSoup提供了重现解析器初始化过程的方法。
next_element属性指向解析过程中下一个被解析的对象(tag或NavigableString)。
previous_element属性指向解析过程中前一个被解析的对象。
另外还有next_elements和previous_elements属性,不赘述了。
1.5 搜索
1.5.1 过滤器
介绍find_all()方法前,先介绍一下过滤器的类型,这些过滤器贯穿整个搜索的API。过滤器可以被用在tag的name中,节点的属性中,字符串中或他们的混合中。
html = """
<div>
<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></p>
</div>
""" soup = BeautifulSoup(html, 'html.parser')
查找所有的<b>标签
print(soup.find_all('b')) # [<b>The Dormouse's story</b>]
传入正则表达式作为参数,返回满足正则表达式的标签。下面例子中找出所有以b开头的标签。
print(soup.find_all(re.compile("^b"))) # [<b>The Dormouse's story</b>]
传入列表参数,将返回与列表中任一元素匹配的内容。下面例子中找出所有<a>标签和<b>标签。
print(soup.find_all(["a", "b"])) # [<b>The Dormouse's story</b>, <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>]
True可以匹配任何值,下面的代码查找到所有的tag,但是不会返回字符串节点。
print(soup.find_all(True))
如果没有合适的过滤器,还可以自定义一个方法,方法只接收一个元素参数,如果这个方法返回True表示当前元素匹配被找到。
例子,返回所有包含class属性但不包含id属性的标签:
def has_class_but_no_id(tag):
return tag.has_attr('class') and not tag.has_attr('id') print(soup.find_all(has_class_but_no_id))
结果:
结果怎么不对呢,<a>标签含有id属性。其实返回的list中只有2个元素,都是<p>标签,<a>标签是<p>标签的子节点。
1.5.2 find和find_all
搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件。
语法:
find(name=None, attrs={}, recursive=True, text=None, **kwargs)
find_all(name=None, attrs={}, recursive=True, text=None, limit=None, **kwargs)
参数:
name:查找所有名字为name的tag,字符串对象会被自动忽略掉。上面过滤器示例中的参数都是name参数。当然,其他参数中也可以使用过滤器。
attrs:按属性名和值查找。传入字典,key为属性名,value为属性值。
recursive:是否递归遍历所有子孙节点,默认True。
text:用于搜索字符串,会找到 .string方法与text参数值相符的tag,通常配合正则表达式使用。也就是说,虽然参数名是 text,但实际上搜索的是string属性。
limit:限定返回列表的最大个数。
kwargs:如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作tag的属性来搜索。这里注意,如果要按class属性搜索,因为class是python的保留字,需要写作class_。
Tag的有些属性在搜索中不能作为kwargs参数使用,比如H5中的data-*属性。
data_soup = BeautifulSoup('<div data-foo="value">foo!</div>') print(data_soup.find_all(data-foo="value")) # SyntaxError: keyword can't be an expression
但是可以通过attrs参数传递
data_soup = BeautifulSoup('<div data-foo="value">foo!</div>','xml') print(data_soup.find_all(attrs={"data-foo": "value"})) # [<div data-foo="value">foo!</div>]
1.6 CSS选择器
BeautifulSoup支持大部分的CSS选择器,这里直接用代码来演示。
from bs4 import BeautifulSoup html = """
<html>
<head><title>标题</title></head>
<body>
<p class="title" name="dromouse"><b>标题</b></p>
<div name="divlink">
<p>
<a href="http://example.com/1" class="sister" id="link1">链接1</a>
<a href="http://example.com/2" class="sister" id="link2">链接2</a>
<a href="http://example.com/3" class="sister" id="link3">链接3</a>
</p>
</div>
<p></p>
<div name='dv2'></div>
</body>
</html>
""" soup = BeautifulSoup(html, 'lxml') # 通过tag查找
print(soup.select('title')) # [<title>标题</title>] # 通过tag逐层查找
print(soup.select("html head title")) # [<title>标题</title>] # 通过class查找
print(soup.select('.sister'))
# [<a class="sister" href="http://example.com/1" id="link1">链接1</a>,
# <a class="sister" href="http://example.com/2" id="link2">链接2</a>,
# <a class="sister" href="http://example.com/3" id="link3">链接3</a>] # 通过id查找
print(soup.select('#link1, #link2'))
# [<a class="sister" href="http://example.com/1" id="link1">链接1</a>,
# <a class="sister" href="http://example.com/2" id="link2">链接2</a>] # 组合查找
print(soup.select('p #link1'))# [<a class="sister" href="http://example.com/1" id="link1">链接1</a>] # 查找直接子标签
print(soup.select("head > title"))# [<title>标题</title>] print(soup.select("p > #link1"))# [<a class="sister" href="http://example.com/1" id="link1">链接1</a>] print(soup.select("p > a:nth-of-type(2)")) # [<a class="sister" href="http://example.com/2" id="link2">链接2</a>]
# nth-of-type 是CSS选择器 # 查找兄弟节点(向后查找)
print(soup.select("#link1 ~ .sister"))
# [<a class="sister" href="http://example.com/2" id="link2">链接2</a>,
# <a class="sister" href="http://example.com/3" id="link3">链接3</a>] print(soup.select("#link1 + .sister"))
# [<a class="sister" href="http://example.com/2" id="link2">链接2</a>] # 通过属性查找
print(soup.select('a[href="http://example.com/1"]')) # ^ 以XX开头
print(soup.select('a[href^="http://example.com/"]')) # * 包含
print(soup.select('a[href*=".com/"]')) # 查找包含指定属性的标签
print(soup.select('[name]')) # 查找第一个元素
print(soup.select_one(".sister"))
1.7 实例
我们来爬取三国演义的内容,我甚至有个想法,去那些小说网里爬小说去。
import requests
from bs4 import BeautifulSoup url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}
page_text = requests.get(url=url,headers=headers).text soup = BeautifulSoup(page_text,'lxml') a_list = soup.select('.book-mulu > ul > li > a') fp = open('sanguo.txt','w',encoding='utf-8')
for a in a_list:
title = a.string
detail_url = 'http://www.shicimingju.com'+a['href']
detail_page_text = requests.get(url=detail_url,headers=headers).text soup = BeautifulSoup(detail_page_text,'lxml')
content = soup.find('div',class_='chapter_content').text fp.write(title+'\n'+content)
print(title,'下载完毕')
print('over')
爬虫(七):BeatifulSoup模块的更多相关文章
- 爬虫 BeatifulSoup 模块
BeatifulSoup 模块 介绍 Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库 安装 pip install beautifulsoup4 解析器下载 ...
- python爬虫主要就是五个模块:爬虫启动入口模块,URL管理器存放已经爬虫的URL和待爬虫URL列表,html下载器,html解析器,html输出器 同时可以掌握到urllib2的使用、bs4(BeautifulSoup)页面解析器、re正则表达式、urlparse、python基础知识回顾(set集合操作)等相关内容。
本次python爬虫百步百科,里面详细分析了爬虫的步骤,对每一步代码都有详细的注释说明,可通过本案例掌握python爬虫的特点: 1.爬虫调度入口(crawler_main.py) # coding: ...
- Python爬虫之urllib模块2
Python爬虫之urllib模块2 本文来自网友投稿 作者:PG-55,一个待毕业待就业的二流大学生. 看了一下上一节的反馈,有些同学认为这个没什么意义,也有的同学觉得太简单,关于Beautiful ...
- Python爬虫之urllib模块1
Python爬虫之urllib模块1 本文来自网友投稿.作者PG,一个待毕业待就业二流大学生.玄魂工作室未对该文章内容做任何改变. 因为本人一直对推理悬疑比较感兴趣,所以这次爬取的网站也是平时看一些悬 ...
- asynicio模块以及爬虫应用asynicio模块(高性能爬虫)
一.背景知识 爬虫的本质就是一个socket客户端与服务端的通信过程,如果我们有多个url待爬取,只用一个线程且采用串行的方式执行,那只能等待爬取一个结束后才能继续下一个,效率会非常低. 需要强调的是 ...
- 第三百二十六节,web爬虫,scrapy模块,解决重复ur——自动递归url
第三百二十六节,web爬虫,scrapy模块,解决重复url——自动递归url 一般抓取过的url不重复抓取,那么就需要记录url,判断当前URL如果在记录里说明已经抓取过了,如果不存在说明没抓取过 ...
- 第三百二十五节,web爬虫,scrapy模块标签选择器下载图片,以及正则匹配标签
第三百二十五节,web爬虫,scrapy模块标签选择器下载图片,以及正则匹配标签 标签选择器对象 HtmlXPathSelector()创建标签选择器对象,参数接收response回调的html对象需 ...
- 第三百二十四节,web爬虫,scrapy模块介绍与使用
第三百二十四节,web爬虫,scrapy模块介绍与使用 Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 其可以应用在数据挖掘,信息处理或存储历史数据等一系列的程序中.其最初是为了 ...
- 第三百二十三节,web爬虫,scrapy模块以及相关依赖模块安装
第三百二十三节,web爬虫,scrapy模块以及相关依赖模块安装 当前环境python3.5 ,windows10系统 Linux系统安装 在线安装,会自动安装scrapy模块以及相关依赖模块 pip ...
- Python爬虫教程-09-error 模块
Python爬虫教程-09-error模块 今天的主角是error,爬取的时候,很容易出现错,所以我们要在代码里做一些,常见错误的处,关于urllib.error URLError URLError ...
随机推荐
- python--数字灯管
import turtle import time def drawLine(draw): #绘制单段数码管 turtle.pendown() if draw else turtle.penup() ...
- DNS资源记录的七类
在Microsoft产品系列中,ADDS是一个很出色的设计平台,说到AD,那么我们就不得不提起他的合作伙伴--DNS,相信大家都知道,DNS在AD中的重要地位,就如男人和女人一样,要想有所作为,他们2 ...
- day20191006假期作业收尾
国庆作业:(轻重缓急,重点代码看懂理解了.每天重心就是代码,理解代码,理解,understand the code.花时间花功夫.只要功夫深,铁杵磨成针.) 一.使用DAO设计模式操作数据库CRUD( ...
- 【Android - 控件】之MD - CardView的使用
CardView是Android 5.0新特性——Material Design中的一个布局控件,可以通过属性设置显示一个圆角的类似卡片的视图. 1.CardView的属性: app:cardCorn ...
- CentOS 7 Cobbler 配置 YUM仓库
通过Cobbler配置内网YUM仓库 在上一篇Cobbler 安装中,配置好了Cobbler 下面来通过Cobbler来配置内网的YUM仓库 这里可以同步所有版本的yum源,增加内网的yum安装下载速 ...
- Chapter 02—Creating a dataset(Part1)
一. 数据集 1. 在R语言中,进行数据分析的第一步是创建一个包含待研究数据并且符合要求的数据集. · 选择装数据的数据结构 · 把数据装入数据结构中 2. 理解数据集 (1)数据集通常是矩形的数据列 ...
- 网络OSI七层模型以及数据传输过程
网络OSI七层模型 模型图 国际标准化组织(ISO)制定了osi七层模型,iso规定了各种各样的协议,并且分了7层 每一层的详细信息 具体7层 数据格式 功能与连接方式 典型设备 应用层 Applic ...
- Nginx动静分离(Nginx+Tomcat)
第一步:nginx构建 第二步:Tomcat构建 1.Tomcat基础点 (1)Tomcat 是基于java开发的web容器,用来发布java代码和jsp网页. (2)开发人员开发java web网站 ...
- WebMagic 实现爬虫入门教程
本示例实现某电影网站最新片源名称列表及详情页下载地址的抓取. webmagic是一个开源的Java垂直爬虫框架,目标是简化爬虫的开发流程,让开发者专注于逻辑功能的开发. WebMagic 特点: 完全 ...
- 工作流Activity组件值数据传递获取问题
如图:先简单说一下大致过程 通过具体的菜单节点,加载具体的指令组件.本着低耦合的原件,需要将核查组件从指令组件重拆分出来,作为单独的组件根据业务需要拖拽到指令组件中.但是具体业务方面核查组件一方面需要 ...