Rumah > pembangunan bahagian belakang > Tutorial Python > Menggunakan Beautiful Soup untuk mengikis web dalam Python: penerokaan pengetahuan asas

Menggunakan Beautiful Soup untuk mengikis web dalam Python: penerokaan pengetahuan asas

PHPz
Lepaskan: 2023-09-02 10:49:02
asal
1302 orang telah melayarinya

Python中使用Beautiful Soup进行网页抓取:基础知识探究

Dalam tutorial sebelumnya, saya menunjukkan kepada anda cara mengakses halaman web melalui Python menggunakan modul Permintaan. Tutorial ini merangkumi topik seperti membuat permintaan GET/POST dan memuat turun kandungan secara program seperti imej atau PDF. Satu perkara yang hilang dalam tutorial ialah panduan tentang cara mengikis halaman web yang anda lawati dengan permintaan untuk mengekstrak maklumat yang anda perlukan.

Dalam tutorial ini, anda akan belajar tentang Beautiful Soup, perpustakaan Python untuk mengekstrak data daripada fail HTML. Tutorial ini memberi tumpuan kepada pembelajaran asas perpustakaan, dengan tutorial seterusnya meliputi topik yang lebih lanjut. Sila ambil perhatian bahawa semua contoh dalam tutorial ini menggunakan Sup Cantik 4.

Pemasangan

Anda boleh memasang Beautiful Soup 4 menggunakan pip. Nama pakej ialah beautifulsoup4. Ia sepatutnya berfungsi pada Python 2 dan Python 3. pip 安装 Beautiful Soup 4。包名称为 beautifulsoup4。它应该适用于 Python 2 和 Python 3。

$ pip install beautifulsoup4
Salin selepas log masuk

如果您的系统上没有安装 pip,您可以直接下载 Beautiful Soup 4 源代码 tarball 并使用 setup.py 进行安装。

$ python setup.py install
Salin selepas log masuk

Beautiful Soup 最初打包为 Python 2 代码。当您安装它以与 Python 3 一起使用时,它会自动更新为 Python 3 代码。除非您安装该软件包,否则代码不会被转换。以下是您可能会注意到的一些常见错误:

  • 当您在 Python 3 下运行 Python 2 版本的代码时,会出现“没有名为 HTMLParser 的模块”ImportError
  • 当您在 Python 2 下运行 Python 3 版本的代码时,会出现“没有名为 html.parser 的模块”ImportError

上述两个错误都可以通过卸载并重新安装 Beautiful Soup 来纠正。

安装解析器

在讨论 Beautiful Soup 可以使用的不同解析器之间的差异之前,让我们编写代码来创建一个 soup。

from bs4 import BeautifulSoup

soup = BeautifulSoup("<html><p>This is <b>invalid HTML</p></html>", "html.parser")
Salin selepas log masuk

BeautifulSoup 对象可以接受两个参数。第一个参数是实际标记,第二个参数是您要使用的解析器。不同的解析器是 html.parser、lxml 和 html5lib。 lxml 解析器有两个版本:HTML 解析器和 XML 解析器。

html.parser 是一个内置解析器,它在旧版本的 Python 中工作得不太好。您可以使用以下命令安装其他解析器:

$ pip install lxml
$ pip install html5lib
Salin selepas log masuk

lxml 解析器非常快,可用于快速解析给定的 HTML。另一方面,html5lib 解析器非常慢,但也非常宽松。以下是使用每个解析器的示例:

soup = BeautifulSoup("<html><p>This is <b>invalid HTML</p></html>", "html.parser")
print(soup)
# <html><p>This is <b>invalid HTML</b></p></html>

soup = BeautifulSoup("<html><p>This is <b>invalid HTML</p></html>", "lxml")
print(soup)
# <html><body><p>This is <b>invalid HTML</b></p></body></html>

soup = BeautifulSoup("<html><p>This is <b>invalid HTML</p></html>", "xml")
print(soup)
# <?xml version="1.0" encoding="utf-8"?>
# <html><p>This is <b>invalid HTML</b></p></html>

soup = BeautifulSoup("<html><p>This is <b>invalid HTML</p></html>", "html5lib")
print(soup)
# <html><head></head><body><p>This is <b>invalid HTML</b></p></body></html>
Salin selepas log masuk

只有当您解析无效的 HTML 时,上面示例中概述的差异才有意义。然而,网络上的大多数 HTML 都是格式错误的,了解这些差异将帮助您调试一些解析错误并决定要在项目中使用哪个解析器。一般来说,lxml 解析器是一个非常好的选择。

美丽汤中的物体

Beautiful Soup 将给定的 HTML 文档解析为 Python 对象树。您需要了解四个主要的 Python 对象:TagNavigableStringBeautifulSoupComment

Tag 对象指的是文档中的实际 XML 或 HTML 标记。您可以使用 tag.name 访问标签的名称。您还可以将标签的名称设置为其他名称。名称更改将在 Beautiful Soup 生成的标记中可见。

您可以分别使用 tag['class']tag['id'] 访问不同的属性,例如标签的类和 id。您还可以使用 tag.attrs 访问整个属性字典。您还可以添加、删除或修改标签的属性。像元素的 class 这样的属性可以采用多个值,存储为列表。

标签内的文本在 Beautiful Soup 中存储为 NavigableString。它有一些有用的方法,例如 replace_with("string") 来替换标签内的文本。您还可以使用 unicode()NavigableString 转换为 unicode 字符串。

美丽汤还允许您访问网页中的评论。这些注释存储为 Comment 对象,该对象基本上也是一个 NavigableString

您已经在上一节中了解了 BeautifulSoup

import requests
from bs4 import BeautifulSoup

req = requests.get('https://en.wikipedia.org/wiki/Python_(programming_language)')
soup = BeautifulSoup(req.text, "lxml")
Salin selepas log masuk

Jika pip tidak dipasang pada sistem anda, anda boleh memuat turun terus tarball kod sumber Beautiful Soup 4 dan memasangnya menggunakan setup.py.

soup.title
# <title>Python (programming language) - Wikipedia</title>

soup.title.name
# 'title'

soup.title.string
# 'Python (programming language) - Wikipedia'
Salin selepas log masuk
Salin selepas log masuk

Sup Cantik pada asalnya dibungkus sebagai kod Python 2. Apabila anda memasangnya untuk digunakan dengan Python 3, ia mengemas kini secara automatik kepada kod Python 3. Kod tidak akan ditukar melainkan anda memasang pakej. Berikut adalah beberapa ralat biasa yang mungkin anda perhatikan:

  • Apabila anda menjalankan kod versi Python 2 di bawah Python 3, "Tiada modul bernama HTMLParser" ImportError berlaku.
  • Apabila anda menjalankan versi kod Python 3 di bawah Python 2, "Tiada modul bernama html.parser" ImportError berlaku.

Kedua-dua ralat di atas boleh dibetulkan dengan menyahpasang dan memasang semula Beautiful Soup.

Pasang parser🎜 🎜Sebelum membincangkan perbezaan antara parser berbeza yang boleh digunakan oleh Beautiful Soup, mari tulis kod untuk membuat sup. 🎜
soup.h1
# <h1 class="firstHeading" id="firstHeading" lang="en">Python (programming language)</h1>

soup.h1.string
# 'Python (programming language)'

soup.h1['class']
# ['firstHeading']

soup.h1['id']
# 'firstHeading'

soup.h1.attrs
# {'class': ['firstHeading'], 'id': 'firstHeading', 'lang': 'en'}

soup.h1['class'] = 'firstHeading, mainHeading'
soup.h1.string.replace_with("Python - Programming Language")
del soup.h1['lang']
del soup.h1['id']

soup.h1
# <h1 class="firstHeading, mainHeading">Python - Programming Language</h1>
Salin selepas log masuk
Salin selepas log masuk
🎜 Objek BeautifulSoup boleh menerima dua parameter. Parameter pertama ialah token sebenar dan parameter kedua ialah parser yang anda mahu gunakan. Penghurai yang berbeza ialah html.parser, lxml dan html5lib. Terdapat dua versi penghurai lxml: penghurai HTML dan penghurai XML. 🎜 🎜html.parser ialah penghurai terbina dalam yang tidak berfungsi dengan baik dalam versi Python yang lebih lama. Anda boleh memasang parser tambahan menggunakan arahan berikut: 🎜
for sub_heading in soup.find_all('h2'):
    print(sub_heading.text)
    
# all the sub-headings like Contents, History[edit]...
Salin selepas log masuk
Salin selepas log masuk
🎜lxml parser sangat pantas dan boleh digunakan untuk menghuraikan HTML yang diberikan dengan cepat. Sebaliknya, penghurai html5lib sangat perlahan, tetapi juga sangat lembut. Berikut adalah contoh menggunakan setiap penghurai: 🎜
from bs4 import BeautifulSoup

markup = '''
<a class="notice light" id="recent-posts" data-links="1 5 20" href="/recent-posts/">Recent Posts</a>
'''

soup = BeautifulSoup(markup, 'html.parser')
print(soup.a['class'])
print(soup.a['id'])
print(soup.a['data-links'] + "\n")
''' 
Output:
['notice', 'light']
recent-posts
1 5 20
'''


soup = BeautifulSoup(markup, 'html.parser', multi_valued_attributes=None)

print(soup.a['class'])
print(soup.a['id'])
print(soup.a['data-links'] + "\n")
'''
Output:
notice light
recent-posts
1 5 20
'''
Salin selepas log masuk
Salin selepas log masuk
🎜Perbezaan yang digariskan dalam contoh di atas hanya masuk akal jika anda menghuraikan HTML yang tidak sah. Walau bagaimanapun, kebanyakan HTML di web adalah salah bentuk, dan memahami perbezaan ini akan membantu anda menyahpepijat beberapa ralat penghuraian dan memutuskan penghurai yang hendak digunakan dalam projek anda. Secara umum, penghurai lxml ialah pilihan yang sangat baik. 🎜 🎜Benda dalam sup yang cantik🎜 🎜Beautiful Soup menghuraikan dokumen HTML yang diberikan ke dalam pokok objek Python. Terdapat empat objek Python utama yang perlu anda ketahui: Tag, NavigableString, BeautifulSoup dan Comment. 🎜 🎜Tag objek merujuk kepada teg XML atau HTML sebenar dalam dokumen. Anda boleh mengakses nama tag menggunakan tag.name. Anda juga boleh menetapkan nama label kepada sesuatu yang lain. Perubahan nama akan kelihatan dalam markup yang dijana oleh Beautiful Soup. 🎜 🎜Anda boleh menggunakan tag['class'] dan tag['id'] masing-masing untuk mengakses sifat yang berbeza, seperti kelas dan id teg. Anda juga boleh mengakses keseluruhan kamus atribut menggunakan tag.attrs. Anda juga boleh menambah, memadam atau mengubah suai sifat label. Atribut seperti class elemen boleh mengambil berbilang nilai, disimpan sebagai senarai. 🎜 Teks dalam teg 🎜 disimpan sebagai NavigableString dalam Beautiful Soup. Ia mempunyai beberapa kaedah berguna seperti replace_with("string") untuk menggantikan teks dalam teg. Anda juga boleh menggunakan unicode() untuk menukar NavigableString kepada rentetan unicode. 🎜 🎜Sup Cantik juga membolehkan anda mengakses ulasan dalam halaman web. Komen ini disimpan sebagai objek Comment, yang pada asasnya ialah NavigableString. 🎜 🎜Anda sudah mengetahui tentang objek BeautifulSoup dalam bahagian sebelumnya. Ia digunakan untuk mewakili keseluruhan dokumen. Oleh kerana ia bukan objek sebenar, ia tidak mempunyai sebarang nama atau sifat. 🎜 🎜Dapatkan tajuk, kapsyen dan pautan🎜 🎜Anda boleh mengekstrak tajuk halaman dan data lain dengan mudah menggunakan Sup Cantik. Mari kita mengikis halaman Wikipedia tentang Python. Pertama, anda perlu mendapatkan teg halaman menggunakan kod berikut mengikut tutorial modul permintaan untuk mengakses halaman web. 🎜
from bs4 import BeautifulSoup

markup = '''
<a class="notice light" href="/recent-posts/" class="important dark">Recent Posts</a>
'''

soup = BeautifulSoup(markup, 'lxml')
print(soup.a['class'])
# ['notice', 'light']

soup = BeautifulSoup(markup, 'html.parser', on_duplicate_attribute='ignore')
print(soup.a['class'])
# ['notice', 'light']

soup = BeautifulSoup(markup, 'html.parser', on_duplicate_attribute='replace')
print(soup.a['class'])
# ['important', 'dark']
Salin selepas log masuk
Salin selepas log masuk
🎜Sekarang anda telah mencipta sup anda, anda boleh mendapatkan tajuk halaman web menggunakan kod berikut: 🎜
soup.title
# <title>Python (programming language) - Wikipedia</title>

soup.title.name
# 'title'

soup.title.string
# 'Python (programming language) - Wikipedia'
Salin selepas log masuk
Salin selepas log masuk

您还可以抓取网页以获取其他信息,例如主标题或第一段、它们的类或 id 属性。

soup.h1
# <h1 class="firstHeading" id="firstHeading" lang="en">Python (programming language)</h1>

soup.h1.string
# 'Python (programming language)'

soup.h1['class']
# ['firstHeading']

soup.h1['id']
# 'firstHeading'

soup.h1.attrs
# {'class': ['firstHeading'], 'id': 'firstHeading', 'lang': 'en'}

soup.h1['class'] = 'firstHeading, mainHeading'
soup.h1.string.replace_with("Python - Programming Language")
del soup.h1['lang']
del soup.h1['id']

soup.h1
# <h1 class="firstHeading, mainHeading">Python - Programming Language</h1>
Salin selepas log masuk
Salin selepas log masuk

同样,您可以使用以下代码遍历文档中的所有链接或副标题:

for sub_heading in soup.find_all('h2'):
    print(sub_heading.text)
    
# all the sub-headings like Contents, History[edit]...
Salin selepas log masuk
Salin selepas log masuk

处理多值和重复属性

HTML 文档中的不同元素使用各种属性来实现不同的目的。例如,您可以将 class 或 id 属性添加到样式、组或标识元素。同样,您可以使用数据属性来存储任何附加信息。并非所有属性都可以接受多个值,但有一些可以。 HTML 规范对这些情况有一套明确的规则,Beautiful Soup 试图遵循所有这些规则。但是,它还允许您指定如何处理多值属性返回的数据。该功能是在4.8版本中添加的,因此在使用之前请确保您已经安装了正确的版本。

默认情况下,像 class 这样可以有多个值的属性将返回一个列表,但像 id 这样的属性将返回单个字符串值。您可以在 BeautifulSoup 构造函数中传递名为 multi_valued_attributes 的参数,并将其值设置为 None。这将确保所有属性返回的值都是字符串。

这是一个例子:

from bs4 import BeautifulSoup

markup = '''
<a class="notice light" id="recent-posts" data-links="1 5 20" href="/recent-posts/">Recent Posts</a>
'''

soup = BeautifulSoup(markup, 'html.parser')
print(soup.a['class'])
print(soup.a['id'])
print(soup.a['data-links'] + "\n")
''' 
Output:
['notice', 'light']
recent-posts
1 5 20
'''


soup = BeautifulSoup(markup, 'html.parser', multi_valued_attributes=None)

print(soup.a['class'])
print(soup.a['id'])
print(soup.a['data-links'] + "\n")
'''
Output:
notice light
recent-posts
1 5 20
'''
Salin selepas log masuk
Salin selepas log masuk

无法保证您从不同网站获得的 HTML 始终完全有效。它可能存在许多不同的问题,例如重复的属性。从版本 4.9.1 开始,Beautiful Soup 允许您通过为 on_duplicate_attribute 参数设置值来指定在这种情况下应该执行的操作。不同的解析器以不同的方式处理此问题,您将需要使用内置的 html.parser 来强制执行特定行为。

from bs4 import BeautifulSoup

markup = '''
<a class="notice light" href="/recent-posts/" class="important dark">Recent Posts</a>
'''

soup = BeautifulSoup(markup, 'lxml')
print(soup.a['class'])
# ['notice', 'light']

soup = BeautifulSoup(markup, 'html.parser', on_duplicate_attribute='ignore')
print(soup.a['class'])
# ['notice', 'light']

soup = BeautifulSoup(markup, 'html.parser', on_duplicate_attribute='replace')
print(soup.a['class'])
# ['important', 'dark']
Salin selepas log masuk
Salin selepas log masuk

浏览 DOM

您可以使用常规标签名称在 DOM 树中导航。链接这些标签名称可以帮助您更深入地导航树。例如,您可以使用 soup.p.a 获取给定维基百科页面第一段中的第一个链接。第一段中的所有链接都可以使用 soup.p.find_all('a') 访问。

您还可以使用 tag.contents 以列表形式访问标记的所有子级。要获取特定索引处的子项,您可以使用 tag.contents[index]。您还可以使用 .children 属性来迭代标记的子级。

仅当您想要访问标记的直接或第一级后代时,.children.contents 才有用。要获取所有后代,您可以使用 .descendants 属性。

print(soup.p.contents)
# [<b>Python</b>, ' is a widely used ',.....the full list]

print(soup.p.contents[10])
# <a href="/wiki/Readability" title="Readability">readability</a>

for child in soup.p.children:
    print(child.name)
# b
# None
# a
# None
# a
# None
# ... and so on.
Salin selepas log masuk

您还可以使用 .parent 属性访问元素的父元素。同样,您可以使用 .parents 属性访问元素的所有祖先。顶级 <html> 标签的父级是 BeautifulSoup 对象本身,其父级为 None。

print(soup.p.parent.name)
# div

for parent in soup.p.parents:
    print(parent.name)
# div
# div
# div
# body
# html
# [document]
Salin selepas log masuk

您可以使用 .previous_sibling.next_sibling 属性访问元素的上一个和下一个同级元素。

要使两个元素成为兄弟元素,它们应该具有相同的父元素。这意味着元素的第一个子元素不会有前一个同级元素。类似地,元素的最后一个子元素不会有下一个同级元素。在实际的网页中,元素的上一个和下一个同级元素很可能是换行符。

您还可以使用 .previous_siblings.next_siblings 迭代元素的所有同级元素。

soup.head.next_sibling
# '\n'

soup.p.a.next_sibling
# ' for '

soup.p.a.previous_sibling
# ' is a widely used '

print(soup.p.b.previous_sibling)
# None
Salin selepas log masuk

您可以使用 .next_element 属性转到紧随当前元素之后的元素。要访问紧邻当前元素之前的元素,请使用 .previous_element 属性。

同样,您可以分别使用 .previous_elements.next_elements 迭代当前元素之前和之后的所有元素。

仅解析文档的一部分

假设您在查找特定内容时需要处理大量数据,并且节省一些处理时间或内存对您来说很重要。在这种情况下,您可以利用 Beautiful Soup 中的 SoupStrainer 类。此类允许您仅关注特定元素,而忽略文档的其余部分。例如,您可以通过在 SoupStrainer 构造函数中传递适当的选择器,使用它来忽略网页上除图像之外的所有其他内容。

请记住,汤过滤器不能与 html5lib 解析器一起使用。但是,您可以将其与 lxml 和内置解析器一起使用。下面是一个示例,我们解析美国的维基百科页面并获取类为 thumbimage 的所有图像。

import requests
from bs4 import BeautifulSoup, SoupStrainer

req = requests.get('https://en.wikipedia.org/wiki/United_States')

thumb_images = SoupStrainer(class_="thumbimage")

soup = BeautifulSoup(req.text, "lxml", parse_only=thumb_images)

for image in soup.find_all("img"):
    print(image['src'])
'''
Output:
//upload.wikimedia.org/wikipedia/commons/thumb/7/7b/Mesa_Verde_National_Park_-_Cliff_Palace.jpg/220px-Mesa_Verde_National_Park_-_Cliff_Palace.jpg
//upload.wikimedia.org/wikipedia/commons/thumb/3/38/Map_of_territorial_growth_1775.svg/260px-Map_of_territorial_growth_1775.svg.png
//upload.wikimedia.org/wikipedia/commons/thumb/f/f9/Declaration_of_Independence_%281819%29%2C_by_John_Trumbull.jpg/220px-Declaration_of_Independence_%281819%29%2C_by_John_Trumbull.jpg
//upload.wikimedia.org/wikipedia/commons/thumb/9/94/U.S._Territorial_Acquisitions.png/310px-U.S._Territorial_Acquisitions.png
...and many more images
'''
Salin selepas log masuk

您应该注意,我使用 class_ 而不是 class 来获取这些元素,因为 class 是 Python 中的保留关键字。

最终想法

完成本教程后,您现在应该能够很好地理解不同 HTML 解析器之间的主要差异。您现在还应该能够浏览网页并提取重要数据。当您想要分析给定网站上的所有标题或链接时,这会很有帮助。

在本系列的下一部分中,您将学习如何使用 Beautiful Soup 库来搜索和修改 DOM。

Atas ialah kandungan terperinci Menggunakan Beautiful Soup untuk mengikis web dalam Python: penerokaan pengetahuan asas. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan