>  기사  >  백엔드 개발  >  Python에서 웹 스크래핑을 위해 Beautiful Soup 사용하기: 기본 지식 탐구

Python에서 웹 스크래핑을 위해 Beautiful Soup 사용하기: 기본 지식 탐구

PHPz
PHPz원래의
2023-09-02 10:49:021219검색

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

이전 튜토리얼에서는 요청 모듈을 사용하여 Python을 통해 웹 페이지에 액세스하는 방법을 보여주었습니다. 이 자습서에서는 GET/POST 요청 만들기, 이미지나 PDF와 같은 콘텐츠를 프로그래밍 방식으로 다운로드하는 것과 같은 주제를 다룹니다. 튜토리얼에서 누락된 것 중 하나는 필요한 정보를 추출하라는 요청과 함께 방문한 웹 페이지를 스크랩하는 방법에 대한 가이드입니다.

이 튜토리얼에서는 HTML 파일에서 데이터를 추출하기 위한 Python 라이브러리인 Beautiful Soup에 대해 알아봅니다. 이 튜토리얼은 라이브러리의 기본 사항을 학습하는 데 중점을 두고 있으며, 다음 튜토리얼에서는 보다 고급 주제를 다루고 있습니다. 이 튜토리얼의 모든 예제는 Beautiful Soup 4를 사용한다는 점에 유의하세요.

설치

pip 安装 Beautiful Soup 4。包名称为 beautifulsoup4를 사용할 수 있습니다. Python 2 및 Python 3에서 작동합니다.

으아악

시스템에 pip가 설치되어 있지 않으면 뷰티플수프 4 소스 코드 타르볼을 직접 다운로드하고 setup.py를 사용하여 설치할 수 있습니다.

으아악

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이 사용할 수 있는 다양한 파서 간의 차이점을 논의하기 전에 먼저 수프를 생성하는 코드를 작성해 보겠습니다.

으아악

BeautifulSoup 对象可以接受两个参数。第一个参数是实际标记,第二个参数是您要使用的解析器。不同的解析器是 html.parser、lxml 和 html5lib。 lxml 파서에는 HTML 파서와 XML 파서의 두 가지 버전이 있습니다.

html.parser은 이전 버전의 Python에서는 제대로 작동하지 않는 내장 파서입니다. 다음 명령을 사용하여 추가 파서를 설치할 수 있습니다.

으아악

lxml 解析器非常快,可用于快速解析给定的 HTML。另一方面,html5lib 파서는 매우 느리지만 매우 관대합니다. 다음은 각 파서를 사용하는 예입니다.

으아악

위 예에 설명된 차이점은 잘못된 HTML을 구문 분석하는 경우에만 의미가 있습니다. 그러나 웹상의 대부분의 HTML은 잘못된 형식이므로 이러한 차이점을 이해하면 일부 구문 분석 오류를 디버그하고 프로젝트에 사용할 구문 분석기를 결정하는 데 도움이 됩니다. 일반적으로 lxml 파서는 매우 좋은 선택입니다.

아름다운 수프 속의 물건들

Beautiful Soup은 주어진 HTML 문서를 Python 객체 트리로 구문 분석합니다. 알아야 할 네 가지 주요 Python 객체가 있습니다: TagNavigableStringBeautifulSoupComment.

Tag 对象指的是文档中的实际 XML 或 HTML 标记。您可以使用 tag.name 액세스 태그의 이름입니다. 라벨 이름을 다른 이름으로 설정할 수도 있습니다. 이름 변경은 Beautiful Soup이 생성한 마크업에 표시됩니다.

tag['class']tag['id'] 访问不同的属性,例如标签的类和 id。您还可以使用 tag.attrs 访问整个属性字典。您还可以添加、删除或修改标签的属性。像元素的 class를 별도로 사용할 수 있습니다. 이러한 속성은 목록으로 저장된 여러 값을 가질 수 있습니다.

태그 안의 텍스트는 NavigableString。它有一些有用的方法,例如 replace_with("string") 来替换标签内的文本。您还可以使用 unicode()NavigableString 유니코드 문자열로 변환되어 Beautiful Soup에 저장됩니다.

Beautiful Soup을 사용하면 웹페이지의 댓글에도 액세스할 수 있습니다. 이러한 주석은 Comment 对象,该对象基本上也是一个 NavigableString로 저장됩니다.

이전 섹션에서 BeautifulSoup 개체에 대해 이미 배웠습니다. 문서 전체를 표현하는데 사용됩니다. 실제 객체가 아니기 때문에 이름이나 속성이 없습니다.

제목, 캡션, 링크 받기

Beautiful Soup을 사용하면 페이지 제목 및 기타 데이터를 쉽게 추출할 수 있습니다. Python에 관한 Wikipedia 페이지를 스크랩해 보겠습니다. 먼저 웹 페이지에 액세스하려면 요청 모듈 튜토리얼에 따라 다음 코드를 사용하여 페이지 태그를 가져와야 합니다.

으아악

이제 수프를 만들었으므로 다음 코드를 사용하여 웹페이지 제목을 얻을 수 있습니다.

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

soup.title.name
# 'title'

soup.title.string
# 'Python (programming language) - Wikipedia'

您还可以抓取网页以获取其他信息,例如主标题或第一段、它们的类或 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>

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

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

处理多值和重复属性

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

无法保证您从不同网站获得的 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']

浏览 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.

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

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

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

您可以使用 .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

您可以使用 .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
'''

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

最终想法

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

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

위 내용은 Python에서 웹 스크래핑을 위해 Beautiful Soup 사용하기: 기본 지식 탐구의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.