python3爬虫学习笔记之解析库的使用----BeautifulSoup篇(六)

Beautiful Soup是python的另一个HTML或XML解析库,可以很方便的提取网页中的数据,利用它可以省去很多繁琐的提取工作,提高了解析效率。

首先从一个实例出发

html = """
<html><head><title>The Dormoues's story</title></head>
<body>
<p class="title" name="dromouse"><b>The Dormouse'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>
"""
from bs4 import BeautifulSoup
soup =BeautifulSoup(html,'lxml')
print(soup.prettify())
print(soup.title.string)

运行结果:

代码分析:这里首先声明了html,并不是一个完整的HTML字符串,然后调用BeautifulSoup并初始化对象,调用prettify()方法把要解析的字符串以标准的缩进格式输出。然后调用soup.title.string输出HTML中title节点的文本内容。

节点选择器

直接调用节点的名称就可以选择节点元素,在调用string属性就可以得到节点内的文本了。

  1. 选择元素
    print(soup.title)
    print(type(soup.title))
    print(soup.title.string)
    print(soup.head)
    print(soup.p)

    运行结果如下:当有多个节点时,打印第一个节点。

2. 提取信息

# 提取信息\

#节点名称
print(soup.title.name)
#节点属性
print(soup.p.attrs)
print(soup.p["name"])
print(soup.p["class"])
# 节点内容
print(soup.p.string)

运行结果如下:

3. 嵌套选择

上面的例子中,每一个返回结果都是bs4.element.Tag类型,它同样可以继续调用节点进行下一步的选择。

# 嵌套选择
print(soup.head.title)
print(soup.head.title.string)

4. 关联选择

在做选择的时候不能一步就选到想要的节点,需要选择一个节点,然后以他为基准再选择它的子节点、父节点、兄弟节点等。

(1) 子节点和子孙节点

选择节点元素之后,调用contents属性获取它的直接子节点。

html = """
<html><head><title>The Dormoues'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"><!--- 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>
"""
from bs4 import BeautifulSoup
soup =BeautifulSoup(html,'lxml')
#直接子节点
print(soup.p.contents)

运行结果如下:

可以看到,返回结果是列表形式,p节点直接字典带你既包含文本,又包含节点。可以调用children属性得到响应的结果:

for i,child in enumerate(soup.p.children):
    print(i,child)

运行结果如下:

 

调用descendants属性获取所有子孙节点:

for i,child in enumerate(soup.p.descendants):
    print(i,child)

运行结果如下:

(2) 父节点和祖先节点

parent属性可以获取节点的父节点。

print(soup.a.parent)

运行结果如下:

获取第一个a节点的父节点p。

 

parents属性可以获取节点的祖先节点。

print(type(soup.a.parents))
print(list(enumerate(soup.a.parents)))

运行结果如下:

(3) 兄弟节点

next_sibling和previous_sibling属性获取节点的下一个和上一个兄弟元素,next_siblings和previous_siblings属性返回节点所有前面的和后面的兄弟节点的生成器。

5. 提取信息

文本string,属性attrs。

html = """
<html><head><title>The Dormoues'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/lacie" class="sister" id="link2">Lacie</a><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>
"""
from bs4 import BeautifulSoup
soup =BeautifulSoup(html,'lxml')
print('-'*15,'获取信息','-'*15)
# 获取信息
print(type(soup.a.next_sibling))
print(soup.a.next_sibling)
print(soup.a.next_sibling.string)
print(type(soup.a.parents))
print(list(soup.a.parents)[0])
print(list(soup.a.parents)[0].attrs['class'])

运行结果如下:

如果返回的是单个节点,可以直接调用string、attrs等属性获取文本和属性值;如果返回结果是多个节点的生成器,则可以转为列表取出某个元素,再调用string、attrs等属性。

方法选择器

前面所讲的选择方法都是通过属性来选择的,这种方法非常快,但是如果进行比较复杂的选择就比较繁琐,find_all()、find()方法可以灵活查询。

1. find_all( )

查询所有符合条件的元素,传入一些属性或文本,就可以的东岸符合条件的元素。

API:find_all(name,attrs,recursive,text,**kwargs)

html = """
<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>
"""
soup = BeautifulSoup(html,'lxml')
print(soup.find_all(name="ul"))
print(type(soup.find_all(name="ul")[0]))

运行结果如下:

# 同样可以嵌套选择

for ul in soup.find_all(name="ul"):
    print(ul.find_all(name="li"))
    for li in ul.find_all(name="li"):
        print(li.string)
        print(li.attrs)

运行结果如下:

也可以通过属性来选择:

print(soup.find_all(attrs={'id':'list-1'}))
print(soup.find_all(attrs={'name':'elements'}))

对于一些常用属性,如id和class等,我们可以不用attrs来传递。

print(soup.find_all(id="list-1"))
print(soup.find_all(class_="element"))

Text参数可用来匹配节点的文本,传入的形式可以是字符串,也可以是正则表达式,

html = """
<div class="panel">
<div class="panel-body">
<a>Hello, this is a link</a>
<a>Hello, this is a link too</a>
"""
import re
soup = BeautifulSoup(html,'lxml')
print(soup.find_all(text=re.compile('link')))

2. find( )

返回第一个元素。

 

CSS选择器

BeautifulSoup提供了CSS选择器,只需要调用select()方法传入相应的CSS选择器即可。

html = """
<div class="panel">
    <div class="panel-heading">
        <h4>Hello</h4>
    </div>
    <div class="panel-body">
        <ul class="list" id="list-1" name="elements">
            <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>
"""
print('-'*15,'CSS选择器','-'*15)
soup = BeautifulSoup(html,'lxml')
print(soup.select('.panel .panel-heading'))
print(soup.select('ul li'))
print(soup.select("#list-2 .element"))
print(soup.select('ul')[0])

运行结果如下:

这里调用了3次CSS选择器,返回的结果是符合CSS选择器节点组成的列表。#表示id选择器,.表示class选择器。

1. 嵌套选择

for ul in soup.select('ul'):
    print(ul.select('li'))

2. 获取属性

for ul in soup.select('ul'):
    print(ul['id'])
    print(ul.attrs['id'])

3. 获取文本

for li in ul.select('li'):
print(li.string)
print(li.get_text())

以上就是BeautifulSoup的学习,接下来可以通过一个作业来实践一下:

利用requests和BeautifulSoup爬取某个静态网页的内容,这里以上面那个例子为例子(上面是XPath解析库解析)。(全部代码见news.py)

网页地址为:https://3w.huanqiu.com/a/b1c82f/9CaKrnKmLPE?agt=8

第一步和第二步查看网页和网页源码见上篇博客。

第三步,完整代码

import requests
from lxml import etree

def get_html(url):
    headers={"User-Agent": 
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0"}
    response = requests.get(url,headers=headers)
    if response.status_code==200:
        return response.text
    return None

from bs4 import BeautifulSoup    

def main1():
    url = 'https://3w.huanqiu.com/a/b1c82f/9CaKrnKmLPE?agt=8'
    html = get_html(url)
    soup = BeautifulSoup(html,'lxml')
    #标题
    print(soup.select('h1.a-title strong')[0].string)
    #时间
    print(soup.select('.a-info span.time')[0].string)
    #责编
    print(soup.select('.a-edit')[0].string)
    #内容
    #html
    print(soup.select('.content-a')[0].select('.a-con')[0])
    # text
    for p in soup.select('.content-a')[0].select('.a-con')[0].select('p'):
        print(p.string)
    
if __name__=='__main__':
    main1()

如果对你有用,点个赞  手动笑脸(*_*)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值