草庐IT

Python爬虫 —— 使用BeautifulSoup4解析HTML文档

香蕉道突破手牛爷爷 2023-06-07 原文

Python爬虫 —— 使用BeautifulSoup4解析HTML文档

目录


1.BeautifulSoup4简介

1.1 BS4与lxml

开门见山!我们先来聊聊BS4是个啥,它能干啥,BS4是一个从HTML和XML文件中提取数据的python库,它可以将复杂HTML文件转换为一个复杂的树形结构,这棵树的每一个结点都是Python对象,所有对象都可以归纳为4类,我们在后面会说

BeautifulSoup会自动将输入文档转换为Unicode编码,将输入文档转换为utf-8编码

lxml与BS4一样是优秀的python解释器,它也是,但是这二者有什么样的区别,决定了我们为什么选择BeautifulSoup,lxml是从文档的局部入手,只能局部遍历,但BS4就不一样了,它会载入整个文档,解析整个DOM树,正是因为这个工程量巨大,所以BS4会有很大的时间和空间的开销,整体性能是低于lxml的

但是我们使用BeautifulSoup4必有其原因:BS4用来解析HTML比较简单,API设计也是非常的银性化(人性化)方便我们使用,它也支持CSS选择器,这对于解析整个DOM树的BS4可谓是如虎添翼,它还支持Python标准库中的HTML解析器和lxml的XML解析器

1.2 BeautifulSoup的4类对象

我们前面说:“将复杂HTML文件转换为一个复杂的树形结构,这棵树的每一个结点都是Python对象”,这些python可以大致分为4类:Tag、NavigableString、BeautifulSoup和Comment,我们通过几个例子来熟悉一下这四类对象的使用方法:

  • 1.Tap 标签及其内容,但默认只拿到第一个
  • 2.NavigableString 标签里的内容(字符串)
  • 3.BeautifulSoup 表示整个文档
  • 4.Comment 是一个特殊的NavigableString类型,但输出的内容不包含注释

首先第一步就是导包:from bs4 import BeautifulSoup;然后通过文件操作的语句来打开我们项目中的一个html文件,用一个file对象接收我们的html文件后想要让BeautifulSoup解析它,我们还需要传入一个解析器:html.parser

from bs4 import BeautifulSoup
import re
file = open("./Demo.html", "rb")
html = file.read().decode("utf-8")
# 通过html.parser解析器把我们的HTML解析成了一棵树
bs = BeautifulSoup(html, "html.parser")
# 1.Tap
print("1. Tap的例子:获取title")
print(bs.title)
# 2.NavigableString
print("2. NavigableString的例子:获取title的string内容和div的属性")
print(bs.title.string)
print(bs.div.attrs)     # 获取标签中的所有属性,并返回一个字典
# 3.BeautifulSoup
print("3. BeautifulSoup的例子:获取整个html文档的name")
print(bs.name)
# 4.Comment
print("4. Comment的例子:获取a的string")
print(bs.a.string)

按照以往管理咱来看看代码!从第7行开始我们对这四类对象做了实例解释,对应Tap类型,我们打印了bs.title,即这个HTML文档的标签的全部信息,第12、13行我们通过bs.title.string和bs.div.attrs打印了标签内的信息,title的string信息和div盒子的属性,后面的代码也是同样的道理

2.文档搜索方式

我们在通过网页的地址获取到其源码后不可能直接使用,所以我们在获取HTML源码后要先对其进行信息的定向搜索和筛选,然后再供我们使用,对应BeautifulSoup的文档搜索,它提供了这样几种搜索方式:使用find_all()方法直接搜索、使用kwargs指定参数进行搜索、指定字符串搜索(常与正则表达式匹配使用)和设置limit参数进行搜索,我们依旧通过一些实际操作来掌握这些搜索方法

2.1 使用find_all()搜索

  • 字符串过滤:会查找与字符串完全匹配的内容(注意一定是完全匹配)
  • 正则表达式搜索:使用search()方法匹配内容,它搜索的对象依旧是一个标签,一个整体而不是拆分开来
t_list = bs.find_all("a")
t_list02 = bs.find_all(re.compile("a"))

对应字符串搜索,我们往find_all()方法中传入了一个字符串"a",进行整个文档的字符串过滤,只有含有单个"a"的内容才会被筛选出来,我们使用正则表达式搜索时往find_all()方法中传入re.compile(“a”)这样的一个匹配规则,它会返回所有含有"a"的标签内容,比如等都不例外

2.2 使用kwargs指定参数搜索

同样是使用find_all()方法进行文档搜索,但是我们往其中传入的参数完全不同,举两个例子,我们要搜索id="update"的标签、有class字样的标签还有href="baidu.html"的标签

# 2.kwargs (参数):指定参数进行搜索
print("-------(1)显示id=“update“的")
t_list03 = bs.find_all(id="update")
for item in t_list03:
    print(item)
print("-------(2)只要有class就显示出来")
t_list04 = bs.find_all(class_=True)
for item in t_list04:
    print(item)
print("-------(3)指定查找href=”baidu.html“")
t_list05 = bs.find_all(href="baidu.html")
for item in t_list05:
    print(item)

2.3 text参数搜索

使用text参数进行搜索就稍显轻松了,使用text搜索我们一般会使用列表和正则表达式搜索,这样才能达到我们定向筛选数据的效果,话不多说上代码

2.4 设置limit参数搜索

如果我们通过代码bs.find_all(class_=True)来筛选出存在"class"的部分,结果是有很多很多的,但是我们如果只想要3个结果,需要设置参数limit=x来满足我们的需求

t_text10 = bs.find_all("a", limit=3)
for item in t_text10:
    print(item)

2.5 CSS选择器

相对来说通过CSS选择器来进行文档搜索就很丰富了,可以通过标签、类名、id名、标签属性和子标签等等方式来进行搜索,不一样的是我们会使用bs.select()方法来筛选

# css选择器
print("-------(1)通过标签访问")
t_css = bs.select('title')  # 通过标签访问
for item in t_css:
    print(item)
print("-------(2)通过类名访问")
t_css2 = bs.select(".col-sm-3")  # 通过类名访问
for item in t_css2:
    print(item)
print("-------(3)通过id访问")
t_css3 = bs.select("#btn_add")
for item in t_css3:
    print(item)
print("-------(4)通过标签的属性访问")
t_css4 = bs.select("button[type='submit']")
for item in t_css4:
    print(item)
# 注意不能有空格
print("-------(5)通过子标签访问")
t_css5 = bs.select("div > button")
for item in t_css5:
    print(item)


如果文章对您有所帮助,记得一键三连支持一下哦~

有关Python爬虫 —— 使用BeautifulSoup4解析HTML文档的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. Ruby 解析字符串 - 2

    我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?

  3. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  4. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  5. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  6. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  7. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  8. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  9. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  10. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

随机推荐