Python爬虫:用Beautifulsoup爬取html文本数据

Beautifulsoup介绍:

  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)

打印结果:

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

<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>

<p class="story">...</p>


2.和enumerate()一起使用

enumerate() 
#用于将一个可遍历的数据对象,并在其前面添加一个索引序列,即同时列出数据下标值和数据,一般用在 for 循环当中
for i, child in enumerate(soup.body.children):  
    print(i, child)  #i用来接收索引,child用来接收数据

打印结果:



六、打印子孙节点

.descendants 获取子孙节点,返回的是一个生成器
用法:
from bs4 import BeautifulSoup
soup = BeautifulSoup(h, 'lxml')
print(soup.body.descendants)  # 获取子孙节点  生成器本身是一种特殊的迭代器
for i, child in enumerate(soup.body.descendants):
    print(i, child)


七、打印父节点

.parent 获取父节点,返回的结果是某一标签的上一层级节点以及某一标签里的内容,返回的不是列表
用法:
from bs4 import Beautifulsoup
soup = Beautifulsoup(h, 'lxml')
print(soup.body.parent)

.parents 获取祖先节点,返回的结果是,返回的是生成器
用法:
from bs4 import BeautifulSoup
soup = BeautifulSoup(h, 'lxml')
print(soup.a.parents)  # 获取祖先节点 返回的是生成器,生成器本身是一种特殊的迭代器
      
# print(list(soup.a.parents)) 
#list是内置的列表类,它有一个构造函数,可以接受一个Iterable(可迭代)的对象作为参数,返回一个列表对象

for i, child in enumerate(soup.a.parents):
    print(i, child)
返回的结果是按层级来返回,首先返回a标签的上一层级,再返回a标签的上上层级,再返回a标签的上上上层级,以此类推


八、打印兄弟节点

 .next_siblings 获取后面的兄弟节点,可以是多个兄弟节点
.previous_siblings 获取前面的兄弟节点
两者返回的都是一个生成器对象

用法:
from bs4 import BeautifulSoup
soup = BeautifulSoup(h, 'lxml')

print(list(enumerate(soup.a.next_siblings)))  # 默认为找第一个a标签后边的所有的兄弟节点
print(list(enumerate(soup.a.previous_siblings))) # 默认为找第一个a标签前边的所有的同一层级的兄弟节点


九、find_all(),根据标签名查找

from bs4 import BeautifulSoup

soup = BeautifulSoup(h, 'lxml')

# print(soup.find_all('a'))  # 拿到所有a标签及其里面内容
# print(soup.find_all('a')[0])  # 拿到第一个a标签及其里面内容
# print(soup.find_all('p')) # 拿到所有p标签及其里面内容,包括在p标签里其他标签的内容


.string 获取标签中间的文本值
用法
from bs4 import BeautifulSoup
soup = BeautifulSoup(h, 'lxml')
for i in soup.find_all('p'):
	print(i.string)

有时候用.string取不到,可以用get_text(),get_text()可以用来获取特殊符号
用法:print(i.get_text())


十、根据属性取值,.find_all(attrs={'属性':'属性值'})

from bs4 import BeautifulSoup
soup = BeautifulSoup(h, 'lxml')
for ul in soup.find_all(attrs={'name': 'elements'}):
#     print(ul)  # 从列表中遍历取出
#     print(ul.li.string)  #只返回第一个值
#     print('-----')
    for li in ul:
#         print(li) # 都是同级标签
        print(li.string)

第二种写法:.find_all(属性='属性值')

print(soup.find_all(id='list-1'))

这种方法打印不出class属性,因为class属于Python关键字,需做特殊处理,在class后面加_


第三种写法:指定标签和属性(常用)

print(soup.find_all('li',{'class':'element'}))  
print(soup.find_all('ul',{'id':'list-2'}))

可以通过父标签.子标签['属性']来获取对应的属性值


例如获取class='element'的属性值'element',可以这样写:

classes = soup.find_all('ul',{'class':'list'})

for i in classes:

new_class = i.li['class']

print(new_class)


打印结果为:

['element']

['element']


十一、查找标签中的指定文本,text=()

print(soup.find_all(text='Foo')) # 可以做内容统计用
print(len(soup.find_all(text='Foo'))) # 统计数量

打印结果:

['Foo', 'Foo']

2


十二、find和find_all用法一样,但是也有区别

find返回单个元素,find_all返回所有元素


十三、用CSS选择器提取

CSS选择器介绍:

1,类别选择器 -- class

2,标签选择器 -- <p></p>

3,ID选择器 -- id

用法:
通过select()直接传入CSS选择器即可完成选择
例如:print(soup.select('ul li'))  # 提取ul选择器下的li标签

注意:
    1,用CSS选择器时,标签名不加任何修饰,class类名前加. , id名前加# 
    2,用到的方法是soup.select(),返回类型是list
    3,多个过滤条件需要用空格隔开,严格遵守从前往后逐层筛选


html='''
<div class="pan">q321312321</div>
<div class="panel">
    <div class="panel-heading">
        <h4>Hello</h4>
    </div>
    <div class="panel-body">
        <ul class="list" id="list-1">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
            <li class="element">Jay</li>
        </ul>
        <ul class="list list-small" id="list-2">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
        </ul>
    </div>
</div>
'''

class类名前加.

print(soup.select('.panel'))
print("----"*10)
# 多个条件用空格隔开
print(soup.select('.panel .panel-heading')) 
print("----"*10)

打印结果:


id名前加#

print(soup.select('#list-1'))

打印结果:


可以混合使用!!

# 比如:根据id和class去找
print(soup.select('#list-1 .element'))  #从这个例子可以看出.select方法会获取满足条件的所有内容

打印结果:


十四、获取属性的值

两种写法:
ul['id']
ul.attrs['id']
具体用法:
for ul in soup.select('ul'):
#     print(ul)
#     print(ul['id'])
#     print(ul['class'])

    print(ul.attrs['id'])
    print(ul.attrs['class']) 

打印结果: