爬虫 — Bs4 数据解析

2023-09-15 21:00:00

一、介绍

Bs4(beautifulsoup4):是一个可以从 HTML 或 XML 文件中提取数据的网页信息提取库

官方文档

Bs4 与 XPath 区别

XPath:根据路径找数据

Bs4:使用封装好的方法获取数据

二、使用

安装第三方库

pip install beautifulSoup4

pip install lxml

# 导入
from bs4 import BeautifulSoup
# 创建对象,网页源码,解析器
soup = BeautifulSoup(html_doc, 'lxml')

三、Bs4 对象种类

# 导入库
from bs4 import BeautifulSoup

# 模拟数据
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>
"""

# features 指定解析器
soup = BeautifulSoup(html_doc, features='lxml')

1、tag:标签

# soup.title:查找的是 title 标签
print(soup.title)  # <title>The Dormouse's story</title>
print(type(soup.title))  # <class 'bs4.element.Tag'>
print(soup.p)  # <p class="title"><b>The Dormouse's story</b></p>
print(soup.a)  # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>

2、NavigableString :可导航的字符串

# 标签里面的文本内容
title_tag = soup.title
print(title_tag.string)  # The Dormouse's story
print(type(title_tag.string))  # <class 'bs4.element.NavigableString'>

3、BeautifulSoup:bs对象

print(type(soup))  # <class 'bs4.BeautifulSoup'>

4、Comment:注释

html = '<b><!--好好坚持学习python--></b>'
soup2 = BeautifulSoup(html, "lxml")
print(soup2.b.string)  # 好好坚持学习python
print(type(soup2.b.string))  # <class 'bs4.element.Comment'>

四、遍历文档树

# 导入库
from bs4 import BeautifulSoup

# 模拟数据
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 the
ir 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>
"""

# features 指定解析器
soup = BeautifulSoup(html_doc, features='lxml')

1、遍历子节点

1)contents:返回的是一个所有子节点的列表

print(soup.head.contents)  # [<title>The Dormouse's story</title>]

2)children:返回的是一个子节点的迭代器

# 通过循环取出迭代器里面的内容
for i in soup.head.children:
    print(i)  # <title>The Dormouse's story</title>

3)descendants:返回的是一个生成器遍历子子孙孙

for i in soup.head.descendants:
    print(i)
# <title>The Dormouse's story</title>
# The Dormouse's story  

2、获取节点内容

1)string:获取标签里面的内容

# 只能获取单个
print(soup.title.string)  # The Dormouse's story
print(soup.head.string)  # The Dormouse's story
print(soup.html.string)  # None

2)strings:返回的是一个生成器对象用过来获取多个标签内容

# 返回生成器
print(soup.html.strings)  # <generator object _all_strings at 0x0000020F4F3EB5C8>
# 通过循环取出生成器里面的内容,使用 strings,会出现多个换行符
for i in soup.html.strings:
    print(i)
# The Dormouse's story
#
#
#
#
# The Dormouse's story
#
#
# Once upon a time there were three little sisters; and the
# ir names were
#
# Elsie
# ,
#
# Lacie
#  and
#
# Tillie
# ;
# and they lived at the bottom of a well.
#
#
# ...
#
#

3)stripped_strings:和 strings 基本一致,但是它可以把多余的空格去掉

print(soup.html.stripped_strings)  # <generator object stripped_strings at 0x000001FD0822B5C8>
# 通过循环取出生成器里面的内容
for i in soup.html.stripped_strings:
    print(i)
# The Dormouse's story
# The Dormouse's story
# Once upon a time there were three little sisters; and the
# ir names were
# Elsie
# ,
# Lacie
# and
# Tillie
# ;
# and they lived at the bottom of a well.
# ...

3、遍历父节点

1)parent:直接获得父节点

print(soup.title.parent)  # <head><title>The Dormouse's story</title></head>
# 在 Bs4 中,html的父节点是 BeautifulSoup 对象
print(soup.html.parent)
# <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 the
# ir 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>
# </body></html>
print(type(soup.html.parent))  # <class 'bs4.BeautifulSoup'>

2)parents:获取所有的父节点

# parents:获取所有的父节点
print(soup.a.parents)  # <generator object parents at 0x000001E7984EA5C8>
for i in soup.a.parents:
    print(i.name, soup.name)
# p [document]
# body [document]
# html [document]
# [document] [document]

4、遍历兄弟节点

# 导入库
from bs4 import BeautifulSoup

# 模拟数据
html_doc = '''<a>
<b>bbb</b><c>ccc</c><d>ddd</d>
</a>'''

# features 指定解析器
soup = BeautifulSoup(html_doc, features='lxml')

1)next_sibling:下一个兄弟节点

# 紧挨着的
print(soup.b.next_sibling)  # <c>ccc</c>

2)previous_sibling:上一个兄弟节点

print(soup.c.previous_sibling)  # <b>bbb</b>

3)next_siblings:下一个所有兄弟节点

for i in soup.b.next_siblings:
    print(i)
# <c>ccc</c>
# <d>ddd</d>

4)previous_siblings:上一个所有兄弟节点

for i in soup.d.previous_siblings:
    print(i)
# <c>ccc</c>
# <b>bbb</b>

五、常用方法

# 导入库
from bs4 import BeautifulSoup

# 模拟数据
html_doc = """
<table class="tablelist" cellpadding="0" cellspacing="0">
    <tbody>
        <tr class="h">
            <td class="l" width="374">职位名称</td>
            <td>职位类别</td>
            <td>人数</td>
            <td>地点</td>
            <td>发布时间</td>
        </tr>
        <tr class="even">
            <td class="l square"><a target="_blank" href="position_detail.php?id=33824&keywords=python&tid=87&lid=2218">22989-金融云区块链高级研发工程师(深圳)</a></td>
            <td>技术类</td>
            <td>1</td>
            <td>深圳</td>
            <td>2017-11-25</td>
        </tr>
        <tr class="odd">
            <td class="l square"><a target="_blank" href="position_detail.php?id=29938&keywords=python&tid=87&lid=2218">22989-金融云高级后台开发</a></td>
            <td>技术类</td>
            <td>2</td>
            <td>深圳</td>
            <td>2017-11-25</td>
        </tr>
        <tr class="even">
            <td class="l square"><a target="_blank" href="position_detail.php?id=31236&keywords=python&tid=87&lid=2218">SNG16-腾讯音乐运营开发工程师(深圳)</a></td>
            <td>技术类</td>
            <td>2</td>
            <td>深圳</td>
            <td>2017-11-25</td>
        </tr>
        <tr class="odd">
            <td class="l square"><a target="_blank" href="position_detail.php?id=31235&keywords=python&tid=87&lid=2218">SNG16-腾讯音乐业务运维工程师(深圳)</a></td>
            <td>技术类</td>
            <td>1</td>
            <td>深圳</td>
            <td>2017-11-25</td>
        </tr>
        <tr class="even">
            <td class="l square"><a target="_blank" href="position_detail.php?id=34531&keywords=python&tid=87&lid=2218">TEG03-高级研发工程师(深圳)</a></td>
            <td>技术类</td>
            <td>1</td>
            <td>深圳</td>
            <td>2017-11-24</td>
        </tr>
        <tr class="odd">
            <td class="l square"><a target="_blank" href="position_detail.php?id=34532&keywords=python&tid=87&lid=2218">TEG03-高级图像算法研发工程师(深圳)</a></td>
            <td>技术类</td>
            <td>1</td>
            <td>深圳</td>
            <td>2017-11-24</td>
        </tr>
        <tr class="even">
            <td class="l square"><a target="_blank" href="position_detail.php?id=31648&keywords=python&tid=87&lid=2218">TEG11-高级AI开发工程师(深圳)</a></td>
            <td>技术类</td>
            <td>4</td>
            <td>深圳</td>
            <td>2017-11-24</td>
        </tr>
        <tr class="odd">
            <td class="l square"><a target="_blank" href="position_detail.php?id=32218&keywords=python&tid=87&lid=2218">15851-后台开发工程师</a></td>
            <td>技术类</td>
            <td>1</td>
            <td>深圳</td>
            <td>2017-11-24</td>
        </tr>
        <tr class="even">
            <td class="l square"><a target="_blank" href="position_detail.php?id=32217&keywords=python&tid=87&lid=2218">15851-后台开发工程师</a></td>
            <td>技术类</td>
            <td>1</td>
            <td>深圳</td>
            <td>2017-11-24</td>
        </tr>
        <tr class="odd">
            <td class="l square"><a id="test" class="test" target='_blank' href="position_detail.php?id=34511&keywords=python&tid=87&lid=2218">SNG11-高级业务运维工程师(深圳)</a></td>
            <td>技术类</td>
            <td>1</td>
            <td>深圳</td>
            <td>2017-11-24</td>
        </tr>
    </tbody>
</table>
"""

# features 指定解析器
soup = BeautifulSoup(html_doc, features='lxml')

1、find_all()

以列表形式返回所有的搜索到的标签数据

2、find()

返回搜索到的第一条数据

# 1、获取第一个 tr 标签
tr = soup.find('tr')  # 默认查找一个
print(tr)

# 2、获取所有的 tr 标签
trs = soup.find_all('tr')  # 返回列表,每一组 tr 存放在列表
print(trs)

# 3、获取第二个 tr 标签
tr2 = soup.find_all('tr')[1]  # 返回列表,取下标即可
print(tr2)

# 4、获取 class="odd" 的标签
# 方法一
odd = soup.find_all('tr', class_='odd')
for tr in odd:
    print(tr)
# 方法二
odd2 = soup.find_all('tr', attrs={'class': 'odd'})
for tr in odd2:
    print(tr)

# 5、获取所有 a 标签里面的 href 属性值
lst = soup.find_all('a')
for a in lst:
    print(a['href'])

# 6、获取所有的岗位信息
lst_data = soup.find_all('a')
for a in lst_data:
    print(a.string)

六、CSS选择器

# 导入库
from bs4 import BeautifulSoup

# 模拟数据
html_doc = """ 
<html><head><title>睡鼠的故事</title></head> 
<body> 
<p class="title"><b>睡鼠的故事</b></p>

<p class="story">从前有三个小姐妹;他们的名字是
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>、
<a href="http://example.com/lacie " class="sister" id="link2">Lacie</a> 和
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
他们住在井底。</p>

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

# features 指定解析器
soup = BeautifulSoup(html_doc, features='lxml')

相关语法:http://www.w3cmap.com/cssref/css-selectors.html

# 获取 class 为 sister 的数据
print(soup.select('.sister'))

# 获取 id 为 link1 的数据
print(soup.select('#link1'))

# 获取 title 标签里面的文本内容
print(soup.select('title')[0].string)

# 获取 p 标签下的 a 标签
print(soup.select('p a'))

七、案例

目标网站:http://www.weather.com.cn/textFC/hb.shtml

需求:获取全国的天气,包括城市名称和最低温度,并将数据保存到 csv 文件当中

# 导入
import requests
from bs4 import BeautifulSoup
import csv

# 表格数据
lst = []

# 获取网页源码
def get_html(url):
    # 发请求
    html = requests.get(url)
    # 发现乱码,处理编码
    html.encoding = 'utf-8'
    # 得到网页源码
    html = html.text
    # 返回到函数调用处
    return html

# 解析网页数据
def parse_html(html):
    # 创建对象
    soup = BeautifulSoup(html,'html5lib')
    # 解析
    conMidtab = soup.find('div', class_='conMidtab')
    # print(conMidtab)
    tables = conMidtab.find_all('table')
    for table in tables:
        trs = table.find_all('tr')[2:]
        for index, tr in enumerate(trs):
            dic = {}
            # 拿到对应的标签
            if index == 0: # 判断是否是第一个城市
                # 第一个城市
                city_td = tr.find_all('td')[1]
            else:
                # 其他城市
                city_td = tr.find_all('td')[0]
            temp_td = tr.find_all('td')[-2]
            # print(city_td,temp_td)
            # 对应的标签里面拿文本内容
            dic['city'] = list(city_td.stripped_strings)[0]
            dic['temp'] = temp_td.string
            lst.append(dic)

# 保存数据
def save_data():
    # 规定表头
    head = ('city','temp')
    # csv 文件写入
    with open('weather.csv','w',encoding='utf-8-sig',newline='') as f:
        # 创建 csv 对象
        writer = csv.DictWriter(f, fieldnames=head)
        # 写入表头
        writer.writeheader()
        # 写入数据
        writer.writerows(lst)

# 获取不同地区 url
def area(link):
    # 获取网页源码
    link = get_html(link)
    # 创建对象
    soup = BeautifulSoup(link, 'html5lib')
    # 解析
    conMidtab = soup.find('ul', class_='lq_contentboxTab2')
    # 找到 a 链接
    tagas = conMidtab.find_all('a')
    # url 列表
    hrefs = []
    # 循环获取 url
    for i in tagas:
        hrefs.append('http://www.weather.com.cn' + i.get('href'))
    # 打印 url 列表
    # print(hrefs)
    # 返回函数值
    return hrefs

# 处理主逻辑
def main():
    # 确定 url
    link = 'http://www.weather.com.cn/textFC/hb.shtml'
    # 不同地区 url
    lst = area(link)
    # print(lst)
    for i in lst:
        url = i
        # 获取网页源码
        html = get_html(url)
        # 数据解析
        parse_html(html)
    # 保存内容
    save_data()

# 运行主程序
main()

记录学习过程,欢迎讨论交流,尊重原创,转载请注明出处~

更多推荐

服务器搭建(TCP套接字)-epoll版(服务端)

epoll是一种在Linux系统上用于高效事件驱动编程的I/O多路复用机制。它相比于传统的select和poll函数具有更好的性能和扩展性。epoll的主要特点和原理:1、事件驱动:epoll是基于事件驱动的模型,它通过监听事件来触发相应的回调函数,而不是像传统的阻塞模型那样持续轮询。这样可以避免无效的轮询操作,提高效

开源项目在面试中的作用:如何用你的贡献加分

🌷🍁博主猫头虎(🐅🐾)带您GotoNewWorld✨🍁🦄博客首页——🐅🐾猫头虎的博客🎐🐳《面试题大全专栏》🦕文章图文并茂🦖生动形象🐅简单易学!欢迎大家来踩踩~🌺🌊《IDEA开发秘籍专栏》🐾学会IDEA常用操作,工作效率翻倍~💐🌊《100天精通Golang(基础入门篇)》🐅学会Gol

STM32F4X UCOSIII 消息队列

STM32F4XUCOSIII消息队列消息队列消息队列的作用消息队列工作机制消息队列创建消息发送消息发送模式FIFO(先进先出)LIFO(后进先出)消息接收消息队列删除消息队列常用函数消息队列创建函数消息队列发送函数消息队列接收函数消息队列删除函数UCOSIII消息队列例程消息队列消息队列的作用消息队列是一种常用于任务

全渠道零售趋势——现代零售业成功的关键

在快节奏的零售时代,无论通过什么渠道购物,消费者越来越习惯无缝购物体验。因此,保持线上和线下购物体验的一致性有助于在品牌与购物者之间建立信任,这也是每个零售商的首要任务。在本文中,我们将介绍现代零售业成功的关键——全渠道零售趋势,帮助零售商实现现代零售业的成功。什么是全渠道零售体验?全渠道零售是一种使零售商能够在所有渠

孙宇晨:稳定币支付交易具百倍增长潜力 后FTX时代行业仍需修炼内功

9月14日,波场TRON创始人、火币HTX全球顾问委员会成员孙宇晨受邀出席于新加坡举办的TOKEN2049,并参加了“生态系统和行业增长:展望加密货币的未来十年”主题板块的讨论。孙宇晨在发言中表示,接下来的10年里,加密货币和区块链的最大日常应用场景仍然是稳定币支付交易,预计将有百倍规模增长。他同时指出,一系列风险事件

RISC-V架构学习——C语言内嵌汇编总结

1、C语言内嵌汇编的作用(1)优化:对于特别重要代码进行优化,出于性能的考虑;(2)C语言需要借助汇编指令来实现特殊功能。比如:C语言中访问系统寄存器就需要借助CSR指令;2、基础内嵌汇编2.1、基础内嵌汇编格式asmasm-qualifiers(AssemblerInstructions)关键字含义asm这是内嵌汇编

欧科云链研究院:锚定金融市场,香港从STO再出发

作者|HedyBi昨日,据大公报报道,太极资本宣布推出香港首个面向「专业投资者」的房地产基金证券型代币发行(STO)。集资目标为1亿元。“牌照,醉翁之意不在酒。BTC、ETH等加密资产只是第一步,而背后暗藏的玄机,则是整个金融市场。”“在合规之前,我们看到行业更多是冒出来的是例如NFT、DeFi这类原生的项目。合规之后

【C++】C++ 引用详解 ⑦ ( 指针的引用 )

文章目录一、二级指针可实现的效果二、指针的引用1、指针的引用等同于二级指针(重点概念)2、引用本质-函数间接赋值简化版本3、代码示例-指针的引用一、二级指针可实现的效果指针的引用效果等同于二级指针,因此这里先介绍二级指针;使用二级指针作为参数,可以实现如下功能:动态内存管理:借助二级指针,可以在函数中分配或释放内存;如

数据结构:平衡二叉树

文章目录平衡二叉树一,概述二,添加数据三,删除数据平衡二叉树一,概述平衡二叉树,也称为AVL树,是一种特殊的二叉排序树,它的每个节点的左子树和右子树的高度差不超过1。平衡二叉树的定义可以概括为以下两点:左子树和右子树的高度差绝对值不超过1。左子树和右子树都是平衡二叉树。平衡因子是平衡二叉树中的一个重要概念,它表示一个节

爬虫 — Xpath 数据解析

目录一、介绍二、使用三、语法1、//2、/3、@4、/text5、[]、[@]四、练习1、元组写入2、对象写入五、豆瓣电影信息爬取一、介绍XPath(XMLPathLanguage)是一种XML的查询语言,它能在XML树状结构中寻找节点。XPath用于在XML文档中通过元素和属性进行导航。XML是一种标记语法的文本格式

ASP.NET dotnet 3.5 实验室信息管理系统LIMS源码

技术架构:ASP.NETdotnet3.5LIMS作为一个信息管理系统,它有着和ERP、MIS之类管理软件的共性,如它是通过现代管理模式与计算机管理信息系统支持企业或单位合理、系统地管理经营与生产,最大限度地发挥现有设备、资源、人、技术的作用,最大限度地产生经济效益。但其也与企业管理软件存在着差异,首先,LIMS作为实

热文推荐