整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

深入解析网页结构解析模块beautifulsoup

深入解析网页结构解析模块beautifulsoup

家好,我是编程末白,今天给大家分享一个网页结构解析模块beautifulsoup。

前言

beautifulsoup(以下简称bs),是一款网页结构解析模块,它支持传统的Xpath,css selector 语法,可以说很强大了,下面我们就来着重介绍下它的用法。

安装

bs 可以使用pip 或者easy_install安装,方便快捷。

pip install Beautifulsoup4 


基本用法

一般就是先由requests 获取到网页源码后然后对页面进行解析,如图:

这样就基本上拿到了页面的源码了。

1.根据标签直接获取元素,如下图:


2.根据find,find_all方法查找

前者返回一个结果,后者返回所有结果

find( name , attrs , recursive , text , **kwargs )


name :要查找的标签名(字符串、正则、方法、True)


attrs: 标签的属性


recursive: 递归


text: 查找文本


**kwargs :其它 键值参数

因为class是关键字,所以要写成class_="value", 等同于attrs={"class":"value"}

这里的参数适用于find find_all两种方法。

只不过find_all 还有其他参数,比如限制查找返回数量 的limit方法,标签内容string方法。


3.根据select方法查找

soup.select('div')

所有名为<div>的元素

soup.select('#aa')

所有 id 属性名为aa的元素

soup.select('.oo')

所有class 属性名为oo的元素

soup.select('div p')

所有在<div>元素之内的<p>元素

soup.select('div >p')

所有直接在<div>元素之内的<p>元素,中间没有其他元素

soup.select('input[name]')

所有名为<input>,并有一个 name 属性,其值无所谓的元素

soup.select('input[type="button"]')

所有名为<input>,并有一个 type 属性,其值为 button 的元素

soup.select('a')[0].get_text() # 获取首个a元素的文本

soup.select('a')[0].attrs['href'] # 获取首个a元素的链接地址


4.关系节点名

find_parents()返回所有祖先节点的列表,find_parent()返回直接父节点


print(soup.title.find_parent())


print(soup.title.find_parent().find_all('link')[1])


print(soup.title.find_parents())


find_next_siblings()返回后面所有兄弟节点的列表,find_next_sibling()返回后面第一个兄弟节点


print(soup.title.find_next_sibling())


print(soup.title.find_next_siblings())


find_previous_siblings()返回前面所有兄弟节点的列表,find_previous_sibling()返回前面第一个兄弟节点


print(soup.title.find_previous_sibling())


print(soup.title.find_previous_siblings())


find_all_next()返回节点后所有符合条件的节点的列表, find_next()返回节点后第一个符合条件的节点


print(soup.title.find_next('link'))


print(soup.title.find_all_next('link'))


find_all_previous()返回节点前所有符合条件的节点, find_previous()返回节点前第一个符合条件的节点


print(soup.title.find_previous('link'))


print(soup.title.find_all_previous('link'))


5.对象种类

tag(标签)  navigablestring(标签内字符串)  beautifulsoup(对象)  comment(备注)


rep=requests.get('https://book.qidian.com/info/1014243481#Catalog',timeout=3)
soup=BeautifulSoup(rep.text,'html.parser')


print(soup.name)  #beautifulsoup 对象


tr=soup.div


print(type(tr),tr) #tag对象 标签


print(tr.get_attribute_list('class')) #获取属性对应列表


print(tr.a.string) #navigablestring 对象,获取标签内文字,可使用str()方法将她转换为unicode字符串
print(soup.a.string.replace_with('fdf')) #替换navigablestring

comment 即为提取的注释内容,一般为!--xxxxxxx--! 包裹的内容就是了


三、使用案例

爬取起点小说主页第一页所有小说名字和链接,如图:

import requests
from bs4 import BeautifulSoup
rep=requests.get('https://www.qidian.com/all',timeout=3)
soup=BeautifulSoup(rep.text,'html.parser')
#按照步骤一步一步来爬取
ul=soup.find_all('ul','all-img-list cf')
for y in ul: 
    for z in y.find_all('div','book-mid-info'):
        for x in z.find_all('h4'):
            for v in x.find_all('a'):
                print(v.get_text(),'https:'+v.attrs['href']) #获取a标签的内容和href属性值

最后就可以得出正确结果,如图:

关于bs大致就这么多,大家学会了吗??


总结

今天就讲这么多,关于BS的强大之处,远不止于此,本文只是介绍了它的安装和基本用法,并通过一个案例来帮助大家加深理解,希望大家好好利用,在爬虫路上可以事倍功半!

------------------- End -------------------

最后多说一句,小编是一名python开发工程师,这里有我自己整理了一套最新的python系统学习教程,包括从基础的python脚本到web开发、爬虫、数据分析、数据可视化、机器学习等。想要这些资料的可以关注小编,并在后台私信小编:“01”即可领取。

上一节中,认识了Python中的lxml库,可以通过XPath来寻找页面中的位置,这也是仅仅对于结构完整的页面,但是对于有针对性的获取内容的时候并不很友好,比如说链接中以XXX开头或者结尾,而且中间符合某些特定规则,所以这时候需要认识一个新朋友,那就是另外一个很强大的解析库——Beautiful Soup。

与 lxml 一样,Beautiful Soup 也是一个HTML/XML的解析器,通过解析文档为用户提供需要抓取的数据的功能。

安装BeautifulSoup

Beautiful Soup也有很多版本,不过Beautiful Soup3已经停止更新了,目前最新的都是Beautiful Soup4,而且也已经移植到bs4库中,我们安装bs4库后就可以直接使用。安装库使用pip安装,安装命令:

pip install beautifulsoup4

安装解析器

Beautiful Soup中支持的解析器有很多种,不仅仅支持Python标准库中的HTML解析器,还可以使用一些第三方的解析器,比如说lxml等,如表所示,是几种常见的解析器的优缺点。

解析器

使用方式

优点

缺点

Python标准库

BeautifulSoup(html, "html.parser")

Python的内置标准库、文档容错性较强

执行速度适中

lxml解析器

BeautifulSoup(html, "lxml")

速度快、文档容错性较强

依赖C语言库

html5lib

BeautifulSoup(html, "html5lib")

以浏览器的方式解析文档、容错性最好

执行速度慢

一般情况下可以使用Python标准库或者lxml作为常用的解析器,对于爬虫来说,比起速度来说,准确性的要求并不是很高。如果在解析文档上花费的时间太多,必然会导致爬虫的效率低。

Python标准库解析器并不需要安装,因为本身自带的,lxml解析器在上一节使用它作为解析器时候已经安装过了,也不需要额外安装,直接使用即可。html5lib的安装跟BeautifulSoup一样,使用pip安装:

pip install html5lib

生成解析对象

from bs4 import BeautifulSoup
from lxml import etree
text='''
<html>
<head>
<title>实例HTML</title>
</head>
<body>
<div>
<h1>这是标题</h1>
</div>
<div>
<ul>
<li class="c1"><a href="link1.html" title="链接1">第一个链接</a></li>
<li class="c2"><a href="link2.html" title="链接2">第二个链接</a></li>
<li class="c3"><a href="link3.html" title="链接3">第三个链接</a></li>
</ul>
</div>
</body>
</html>
'''
# 生成一个BeautifulSoup对象
soup=BeautifulSoup(text, 'html.parser')
# 对象类型
print(type(soup))
#代码结果:
<class 'bs4.BeautifulSoup'>

现在就获得了一个BeautifulSoup的对象,Beautiful Soup其实是将HTML文档转换成一个复杂的树形结构,每个节点都是Python中的对象,所有对象可以归纳为 4 种:Tag、NavigableString、BeautifulSoup、Comment,后两种根本上讲也是前面两种的特殊情况。下面我们简要讲解这几个对象。

Tag

Tag是最容易理解的,跟字面意思一样,就是HTML中的标签。比如:一个a标签就是一个对象:

<a href="link1.html" title="链接1">第一个链接</a>

在tag对象中比较重要的两个属性name和attrs。通过这两个属性可以获取到标签中的信息:

print(soup.a.name)
print(soup.a.attrs)
#代码结果:
a
{'href': 'link1.html', 'title': '链接1'}

name其实就是获取标签的名称,这个是使用的不多,毕竟在日常使用的时候都会知道需要找哪些标签中的内容。attrs获取是标签中的属性,结果是一个字典类型的集合。

NavigableString

在上面两个属性中,并没法获取标签中的内容,那么NavigableString就是用来获取标签中文本内容的,用法也比较简单,直接使用string即可。

print(soup.a.string)
print(type(soup.a.string))
#代码结果:
第一个链接
<class 'bs4.element.NavigableString'>

BeautifulSoup

这个对象在前面提到过,表示一个页面(文档)的内容,可以作为一个特殊的Tag。

print(type(soup))
#代码结果:
<class 'bs4.BeautifulSoup'>

Comment

Comment对象也是一个特殊的NavigableString,读取的内容是注释里面的内容。把上面示例中的第一个a标签的内容更改成如下:

<a href="link1.html" title="链接1"><!--Hello--></a>
print(soup.a.string)
print(type(soup.a.string))
#代码结果:
Hello
<class 'bs4.element.Comment'>

注意:如果在标签内的文本既有正常文字也有注释,这时候string属性就无法获取到内容:

<a href="link1.html" title="链接1">第一个链接<!--Hello--></a>
print(soup.a.string)
#代码结果:
None

获取文本内容可以使用text方法,虽然text和string结果都是字符串,但是两个对象其实并不相同。

<a href="link1.html" title="链接1">第一个链接<!--Hello--></a>
print(soup.a.text)
print(type(soup.a.text))
#代码结果:
第一个链接
<class 'str'>

搜索文档树

把HTML内容解析成为一个BeautifulSoup对象后,对这个对象的操作才是BeautifulSoup这个模块所能体验的强大之处。本身BeautifulSoup本身有着丰富的节点遍历功能,包括父节点、子节点、子孙节点的获取和逐个元素的遍历。

不过在实际应用上,我们使用遍历的还是少数,使用搜索的还是多数,现在很多网页中的元素很丰富,我们很少会把一个页面中的所有内容都获取下来,基本是需要的重点内容,这对于遍历来说,搜索更加显得便捷实用。

find_all()

说到搜索,最常使用的肯定是BeautifulSoup的find_all()方法,它会搜索当前 tag 的所有 tag 子孙节点,并判断每个节点是否符合过滤器的条件。

find_all()方法的完整参数为find_all(name, attrs, recursive, text,limit, **kwargs):

name:标签名称的过滤,支持正则

attrs:标签的属性条件的过滤,支持正则;

recursive:bool选项,如果为True,find_all()将遍历所有节点,否则只有子节点,默认为True;

text:标签中的文本过滤,;

limit:搜索限制过滤,如果不为空,表示找到指定数量的元素后将停止搜索,默认为空,将搜索全部;

kwargs:表示可以添加多个属性值参数过滤。

1.name参数

搜索所有a标签

links=soup.find_all('a')
print(links)

代码结果:

[<a href="link1.html" title="链接1">第一个链接</a>, <a href="link2.html" title="链接2">第二个链接</a>, <a href="link3.html" title="链接3">第三个链接</a>]

搜索所有名字带“a”标签

links=soup.find_all(re.compile(".*a.*"))
print(links)

代码结果(head和a标签都符合)

[<head>
<title>实例HTML</title>
</head>, <a href="link1.html" title="链接1">第一个链接</a>, <a href="link2.html" title="链接2">第二个链接</a>, <a href="link3.html" title="链接3">第三个链接</a>]

2. arrts参数

搜索所有a标签中title值为“链接1”

links=soup.find_all('a', attrs={"title": "链接1"})
print(links)

代码结果:

[<a href="link1.html" title="链接1">第一个链接</a>]

3. kwargs参数:

搜索所有a标签中herf中带“1”的标签

links=soup.find_all('a', href=re.compile(".*1.*"))
print(links)

代码结果:

[<a href="link1.html" title="链接1">第一个链接</a>]

4. text参数:

#搜索所有a标签中,文本带“二”的标签

links=soup.find_all('a', text=re.compile(".*二.*"))
print(links)

代码结果:

[<a href="link2.html" title="链接2">第二个链接</a>]

如果不加a标签,搜索的内容则仅仅是文本。

#搜索所有a标签中,文本带“二”的标签

links=soup.find_all('text=re.compile(".*二.*"))
print(links)

代码结果:

['第二个链接']

5. limit参数

#搜索所有a标签中,超链接以link开头,最多2个

links=soup.find_all('a', href=re.compile("link.*"), limit=2)
print(links)

代码结果:

[<a href="link1.html" title="链接1">第一个链接</a>, <a href="link2.html" title="链接2">第二个链接</a>]

find()

find()方法相当于给find_all()方法默认添加limit=1,仅仅发挥符合条件的第一个Tag。方便有时候我们仅仅需要一个值的时候,直接可以调用。参数跟find_all()一样,用法也是相同。

CSS选择器

Beautiful Soup中用select()方法来CSS样式的进行筛选,当然也可以筛选标签。在标签的属性中,class的属性就是当前标签的CSS样式,返回的结果同样也是list。

1.通过标签名查找

查找所有a标签

links=soup.select('a')
print(links)

代码结果:

[<a href="link1.html" title="链接1">第一个链接</a>, <a href="link2.html" title="链接2">第二个链接</a>]

2.通过CSS样式类名查找

查找样式类名为c1的标签

links=soup.select('.c1')
print(links)

代码结果:

[<li class="c1"><a href="link1.html" title="链接1">第一个链接</a></li>]

3.通过标签属性查找

查找属性中href="link1.html"的a标签

links=soup.select('a[href="link1.html"]')
print(links)

代码结果:

[<a href="link1.html" title="链接1">第一个链接</a>]

在标签+属性组合中,属性不支持正则表达式。

4.获取查找到的内容

除了以上集中还可以使用标签的id等元素来进行查找,但是不管使用哪种方式,最终的是回去标签的内容或者属性中的值,那么找到相应的标签后,怎么取值呢?如果是去标签属性值,跟使用字典取值方式一样。如果是获取标签的文本,直接使用get_text()方法,可以获取到标签的文本内容。

查找属性中href="link1.html"的a标签

links=soup.select('a[href="link1.html"]')
#打印标签中的超链接值
print(links[0][‘href])
#打印标签文本内容
print(links[0].get_text())

代码结果:

第一个链接
link1.html

不管是使用lxml还是Beautiful Soup,多数结果都是获取文本内容或者是标签的属性值。文本内容多数是需要获取的内容,整理下来放到list中,最后可能保存本地文件或者数据库,而标签的中属性值多数可以找到子链接(详情链接),知道了怎么定位和获取页面的元素,下面我们就可以动手爬取页面的内容了。

eautifulsoup介绍:

  1. 是一个高效的网页解析库,可以从HTML或XML文件中提取数据
  2. 支持不同的解析器,比如,对HTML解析,对XML解析,对HTML5解析
  3. 就是一个非常强大的工具,爬虫利器
  4. 一个灵活又方便的网页解析库,处理高效,支持多种解析器
  5. 利用它就不用编写正则表达式也能方便的实现网页信息的抓取


第一步:安装BeautifulSoup4,lxml

 pip install BeautifulSoup4
    BeautifulSoup 是一个可以从HTML或XML文件中提取数据的Python库
pip install lxml
    lxml 是一种使用 Python 编写的解析库,可以迅速、灵活地处理 XML 和 HTML


第二步:导包,from bs4 import BeautifulSoup


第三步:实例化对象

html="""
<html>
    <head>
        <title>The Dormouse's story</title>
    </head>
    <body>
        <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">
                <span>Elsie</span>
            </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>
"""
soup=BeautifulSoup(html, 'lxml')  # h:要解析的内容  lxml:解析器
知识补充:print(soup.prettify())  # 代码补全


第四步:打印

一、通过标签选取,会返回包含标签本身及其里面的所有内容

# print(soup.head) # 包含head标签在内的所有内容
# print(soup.p) # 返回匹配的第一个结果

1.print(soup.head)打印结果:

<head>

<title>The Dormouse's story</title>

</head>

2.print(soup.p)打印结果:

<p class="title" name="dromouse"><b><span>The Dormouse's story</span></b></p>


二、打印标签中间的文本内容,不包含<>

# .string是属性,作用是获取字符串文本
print(soup.html.head.title.string)
print(soup.title.string)

打印结果都为:The Dormouse's story


三、打印标签名

 .name --获取标签本身名称  
 print(soup.title.name)

打印结果为:title


四、打印属性的值

.attrs[]  --通过属性拿属性的值 
print(soup.p.attrs['name'])# 获取p标签name属性的属性值
print(soup.a.attrs['id']) # 获取p标签id属性的属性值

print(soup.a['id']) #第二种写法
print(soup.p['class']) # 以列表得形式保存
print(soup.a['href'])  # 也是只返回第一个值

1.print(soup.p.attrs['name'])打印结果:

dromouse

2.print(soup.p.attrs['id'])和print(soup.a['id'])打印结果:

link1

3.print(soup.p['class'])打印结果:

['title', 'asdas']

4.print(soup.a['href'])打印结果:

http://example.com/elsie


五、打印父标签下的所有子标签

.contents 获取标签子节点,以列表形式返回
.children 获取子节点,返回的是一个list类型的迭代器

print(soup.body.contents)  # a是p的子节点,获取P标签所有子节点内容 返回一个list
print(soup.body.children) #返回的是一个list类型的迭代器

1.print(soup.body.contents)的打印结果:

['\n', <p class="title asdas" name="dromouse"><b><span>The Dormouse's story</span></b></p>, '\n', <p class="story">Once upon a time there were three little sisters; and their names were

<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>,

<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and

<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;

and they lived at the bottom of a well.</p>, '\n', <p class="story">...</p>, '\n']

2.print(soup.body.children)的打印结果:

<list_iterator object at 0x000002035ECC7088>


.children 获取子节点讲解

1.和for循环一起使用

for i in soup.p.children:
print(i)

打印结果: