前のチュートリアルでは、Requests モジュールを使用して Python 経由で Web ページにアクセスする方法を説明しました。このチュートリアルでは、GET/POST リクエストの作成や、画像や PDF などのコンテンツをプログラムでダウンロードするなどのトピックについて説明します。このチュートリアルに欠けているものの 1 つは、必要な情報を抽出するリクエストを含む、アクセスした Web ページをスクレイピングする方法に関するガイドです。
このチュートリアルでは、HTML ファイルからデータを抽出するための Python ライブラリである Beautiful Soup について学習します。このチュートリアルではライブラリの基本を学習することに重点を置き、次のチュートリアルではより高度なトピックについて説明します。このチュートリアルのすべての例では Beautiful Soup 4 が使用されていることに注意してください。
###インストール### を使用してインストールできます。パッケージ名は beautysoup4
です。 Python 2 と Python 3 で動作するはずです。
リーリー
pip がシステムにインストールされていない場合は、Beautiful Soup 4 のソース コード tarball を直接ダウンロードし、
を使用してインストールできます。
リーリー
Beautiful Soup はもともと Python 2 コードとしてパッケージ化されていました。 Python 3 で使用するためにインストールすると、Python 3 コードに自動的に更新されます。パッケージをインストールしない限り、コードは変換されません。以下に、気付く可能性のある一般的なエラーをいくつか示します:
Python 3 で Python 2 バージョンのコードを実行すると、「HTMLParser という名前のモジュールがありません」
Python 2 で Python 3 バージョンのコードを実行すると、「html.parser という名前のモジュールがありません」
パーサーのインストール
オブジェクトは 2 つのパラメータを受け入れることができます。最初のパラメータは実際のトークンで、2 番目のパラメータは使用するパーサーです。さまざまなパーサーは、html.parser
、lxml、および html5lib です。 lxml
パーサーには、HTML パーサーと XML パーサーの 2 つのバージョンがあります。
は、古いバージョンの Python ではうまく動作しない組み込みパーサーです。次のコマンドを使用して追加のパーサーをインストールできます:
リーリー
パーサーは非常に高速で、指定された HTML をすばやく解析するために使用できます。一方、html5lib
パーサーは非常に遅いですが、非常に寛容でもあります。各パーサーの使用例を次に示します:
リーリー
上記の例で説明した違いは、無効な HTML を解析する場合にのみ意味を持ちます。ただし、Web 上のほとんどの HTML は不正な形式であるため、これらの違いを理解すると、一部の解析エラーをデバッグしたり、プロジェクトでどのパーサーを使用するかを決定したりするのに役立ちます。一般に、
パーサーは非常に良い選択です。
美しいスープの中の物体
、NavigableString
、BeautifulSoup
、および Comment
の 4 つです。
オブジェクトは、ドキュメント内の実際の XML タグまたは HTML タグを参照します。 tag.name
を使用してタグの名前にアクセスできます。ラベルの名前を別の名前に設定することもできます。名前の変更は、Beautiful Soup によって生成されたマークアップに表示されます。
と tag['id']
をそれぞれ使用して、タグのクラスや ID などのさまざまなプロパティにアクセスできます。 tag.attrs
を使用して属性ディクショナリ全体にアクセスすることもできます。ラベルのプロパティを追加、削除、または変更することもできます。要素の class
のような属性は複数の値を取ることができ、リストとして保存されます。
タグ内のテキストは、Beautiful Soup に
として保存されます。 replace_with("string")
など、タグ内のテキストを置換する便利なメソッドがいくつかあります。 unicode()
を使用して、NavigableString
を Unicode 文字列に変換することもできます。
Beautiful Soup を使用すると、Web ページのコメントにアクセスすることもできます。これらのコメントは
オブジェクトとして保存されますが、これも基本的に NavigableString
です。
オブジェクトについては、前のセクションですでに学習しました。文書全体を表すために使用されます。これは実際のオブジェクトではないため、名前やプロパティはありません。
タイトル、タイトル、リンクを取得
スープを作成したので、次のコードを使用して Web ページのタイトルを取得できます:
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 树中导航。链接这些标签名称可以帮助您更深入地导航树。例如,您可以使用 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 での Web スクレイピングに Beautiful Soup を使用する: 基本的な知識の探索の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。