0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

BeautifulSoup徹底解説:HTML解析からデータ抽出まで(Python)

Posted at

Group2265.png

Leapcell: The Best of Serverless Web Hosting

包括的なHTML処理チュートリアル:解析からデータ抽出まで

I. はじめに

Webページの基盤となる言語であるHTML(Hypertext Markup Language)は、Webデータ処理やWeb開発などの分野で幅広く利用されています。開発者がWeb構造を最適化する場合でも、データ分析者がWebページから情報を抽出する場合でも、HTML処理は欠かせません。本チュートリアルでは、HTMLの解析、修正、データ抽出などの核心的な操作に焦点を当て、読者がHTMLを扱う包括的な方法と技術を習得できるよう支援します。

II. HTML基礎の復習

2.1 HTMLの基本構造

標準的なHTML文書は<!DOCTYPE html>宣言で始まり、<html>ルート要素を含み、この要素の中に<head><body>の2つの主要なセクションがネストされています。<head>セクションには通常、ページのメタ情報(タイトル、文字コード、CSSスタイルシートへのリンクなど)が含まれます。<body>セクションには、テキスト、画像、リンク、フォームなどのページの表示されるコンテンツが含まれます。

<!DOCTYPE html>  
<html lang="en">  
<head>  
    <meta charset="UTF-8">  
    <title>My Page</title>  
</head>  
<body>  
    <h1>Hello, World!</h1>  
    <p>This is a simple HTML page.</p>  
</body>  
</html>  

2.2 HTML要素と属性

HTMLはさまざまな要素で構成され、これらの要素はタグで表されます(例:段落の<p>、リンクの<a>)。要素には追加情報を定義する属性を含めることができます。たとえば、<a href="https://example.com">href属性はリンクの目標アドレスを指定します。属性は通常「名前-値」のペアで記述し、属性値はクォートで囲む必要があります。

III. HTMLの解析

3.1 解析ツールとライブラリ

異なる開発環境では、複数のツールとライブラリを使用してHTMLを解析できます:

  • ブラウザー:ブラウザーには組み込みの強力なHTML解析エンジンが搭載されており、HTMLコードを視覚的なページにレンダリングします。ブラウザーの開発者ツール(例:Chrome DevTools)を使用すると、解析されたDOM(Document Object Model)構造を表示し、要素のスタイルや属性を分析できます。
  • Pythonのライブラリ
    • BeautifulSoup:Pythonで最もよく使われるHTML解析ライブラリの1つで、HTMLとXML文書を簡単に解析し、解析木をナビゲート、検索、修正するためのシンプルなAPIを提供します。
    • lxml:libxml2とlibxsltライブラリをベースに構築されたPythonライブラリで、高速に解析でき、HTMLとXMLの両方の解析に対応しており、XPath式と組み合わせて効率的にデータ抽出が行えます。
    • html5lib:このライブラリは現代のブラウザーと非常に類似した方法でHTMLを解析するため、規則正しくないHTMLコードの処理に適しています。
  • JavaScript:ブラウザー環境では、JavaScriptを使用してdocumentオブジェクトが提供するgetElementByIdgetElementsByTagNameなどのメソッドを直接使用してDOMを操作し、HTMLの解析と操作を行うことができます。Node.js環境では、jsdomなどのライブラリを使用してブラウザー環境をシミュレートしてHTMLを解析できます。

3.2 PythonによるHTMLの解析

3.2.1 BeautifulSoupによる解析の例

まず、BeautifulSoupライブラリをインストールします:

pip install beautifulsoup4  

以下はBeautifulSoupを使用してHTMLを解析する基本的なコードです:

from bs4 import BeautifulSoup  

html_doc = """  
<html>  
  <head><title>Sample Page</title></head>  
  <body>  
    <p class="intro">This is an introductory paragraph.</p>  
    <p class="content">Here is some content.</p>  
  </body>  
</html>  
"""  
soup = BeautifulSoup(html_doc, 'html.parser')  # Pythonの組み込みパーサーを使用  
# 他のパーサー(例:lxml)を使用する場合:soup = BeautifulSoup(html_doc, 'lxml')  
print(soup.title.string)  # 出力:Sample Page  

3.2.2 lxmlによる解析の例

lxmlライブラリをインストールします:

pip install lxml  

lxmlを使用してHTMLを解析し、XPathによるデータ抽出を行います:

from lxml import etree  

html = """  
<html>  
  <body>  
    <div class="box">  
      <p>First paragraph</p>  
      <p>Second paragraph</p>  
    </div>  
  </body>  
</html>  
"""  
tree = etree.HTML(html)  
paragraphs = tree.xpath('//div[@class="box"]/p/text()')  
print(paragraphs)  # 出力: ['First paragraph', 'Second paragraph']  

IV. HTML文書木のナビゲーションと検索

4.1 HTML文書木のナビゲーション

BeautifulSoupを例にとります:解析後、HTML文書は文書木を形成し、複数の方法でナビゲーションすることができます:

  • 子要素へのアクセス:タグ名を直接使用して子要素にアクセスできます(例:soup.body.p<body>要素の下にある最初の<p>要素にアクセスします)。また、contents属性を使用して子要素のリストを取得したり、children属性を使用して子要素をジェネレーターとして反復処理することもできます。
  • 親要素へのアクセスparent属性を使用して現在の要素の直接の親要素を取得し、parents属性を使用してすべての祖先要素を再帰的に辿ることができます。
  • 兄弟要素へのアクセスnext_siblingprevious_sibling属性を使用して、次の兄弟要素と前の兄弟要素をそれぞれ取得します。next_siblingsprevious_siblings属性を使用すると、すべての後続の兄弟要素と先行する兄弟要素を反復処理できます。

4.2 HTML文書木の検索

  • find_all()メソッド:BeautifulSoupのfind_all()メソッドを使用すると、指定された条件に一致するすべての要素を検索できます。これは、タグ名や属性などでフィルタリングすることができます。例:すべての<p>タグを検索するにはsoup.find_all('p)、クラスcontentを持つすべての要素を検索するにはsoup.find_all(class_='content')とします。
  • find()メソッドfind()メソッドは、条件に一致する最初の要素を返します(例:soup.find('a')は文書内の最初の<a>要素を返します)。
  • CSSセレクターselect()メソッドを使用してCSSセレクターの構文を用いて、より柔軟に要素を検索することができます。例:クラスboxを持つすべての<div>要素を選択するにはsoup.select('div.box)、idmainを持つ要素の下にあるすべての<li>要素を選択するにはsoup.select('#main li)とします。

V. HTMLの修正

5.1 要素属性の修正

PythonのライブラリとJavaScriptの両方で、HTMLの要素属性を簡単に修正できます。

  • Python(BeautifulSoup)

    from bs4 import BeautifulSoup  
    
    html = """  
    <html>  
      <body>  
        <a href="https://old-url.com">Old Link</a>  
      </body>  
    </html>  
    """  
    soup = BeautifulSoup(html, 'html.parser')  
    link = soup.find('a')  
    link['href'] = 'https://new-url.com'  # href属性を修正  
    print(soup.prettify())  
    
  • JavaScript

    <!DOCTYPE html>  
    <html lang="en">  
    <head>  
        <meta charset="UTF-8">  
    </head>  
    <body>  
        <img id="myImage" src="old-image.jpg" alt="Old Image">  
        <script>  
            const image = document.getElementById('myImage');  
            image.src = 'new-image.jpg';  // src属性を修正  
        </script>  
    </body>  
    </html>  
    

5.2 要素の追加と削除

  • Python(BeautifulSoup)

    • 要素の追加

      from bs4 import BeautifulSoup  
      
      html = """  
      <html>  
        <body>  
          <ul id="myList"></ul>  
        </body>  
      </html>  
      """  
      soup = BeautifulSoup(html, 'html.parser')  
      ul = soup.find('ul')  
      new_li = soup.new_tag('li')  
      new_li.string = 'New Item'  
      ul.append(new_li)  # 新しい要素を追加  
      
    • 要素の削除

      from bs4 import BeautifulSoup  
      
      html = """  
      <html>  
        <body>  
          <p id="removeMe">This paragraph will be removed.</p>  
        </body>  
      </html>  
      """  
      soup = BeautifulSoup(html, 'html.parser')  
      p = soup.find('p', id='removeMe')  
      p.decompose()  # 要素を削除  
      
  • JavaScript

    • 要素の追加

      <!DOCTYPE html>  
      <html lang="en">  
      <head>  
          <meta charset="UTF-8">  
      </head>  
      <body>  
          <div id="parentDiv"></div>  
          <script>  
              const parentDiv = document.getElementById('parentDiv');  
              const newParagraph = document.createElement('p');  
              newParagraph.textContent = 'This is a new paragraph.';  
              parentDiv.appendChild(newParagraph);  // 新しい要素を追加  
          </script>  
      </body>  
      </html>  
      
    • 要素の削除

      <!DOCTYPE html>  
      <html lang="en">  
      <head>  
          <meta charset="UTF-8">  
      </head>  
      <body>  
          <p id="removeParagraph">This paragraph will be removed.</p>  
          <script>  
              const paragraph = document.getElementById('removeParagraph');  
              paragraph.remove();  // 要素を削除  
          </script>  
      </body>  
      </html>  
      

VI. HTMLのデータ抽出

6.1 テキストコンテンツの抽出

  • Python(BeautifulSoup)string属性またはget_text()メソッドを使用して、要素内のテキストコンテンツを取得します。例:

    from bs4 import BeautifulSoup  
    
    html = """  
    <html>  
      <body>  
        <p class="text">Extract this text.</p>  
      </body>  
    </html>  
    """  
    soup = BeautifulSoup(html, 'html.parser')  
    text = soup.find('p', class_='text').string  
    print(text)  # 出力: Extract this text.  
    
  • JavaScripttextContentまたはinnerText属性を使用してテキストコンテンツを取得します(例:const element = document.getElementById('myElement'); const text = element.textContent;)。

6.2 属性値の抽出

PythonとJavaScriptの両方で、HTMLの要素属性値を簡単に抽出できます。例:<a>タグのhref属性値を抽出する場合:

  • Python(BeautifulSoup)href = soup.find('a')['href']
  • JavaScriptconst link = document.querySelector('a'); const href = link.getAttribute('href');

6.3 複雑なデータ抽出

実際のアプリケーションでは、複雑なHTML構造からデータを抽出する必要がよくあります(例:商品リストのWebページから商品名、価格、リンクを抽出する場合)。このような場合、ループと条件文を上記のナビゲーションと検索メソッドと組み合わせて、必要なデータを巡回して抽出します:

from bs4 import BeautifulSoup  
import requests  

url = "https://example.com/products"  
response = requests.get(url)  
soup = BeautifulSoup(response.text, 'html.parser')  

products = []  
for product_div in soup.find_all('div', class_='product'):  
    name = product_div.find('h2', class_='product-name').string  
    price = product_div.find('span', class_='product-price').string  
    link = product_div.find('a')['href']  
    products.append({'name': name, 'price': price, 'link': link})  

print(products)  

VII. 規則正しくないHTMLの処理

実際には、HTMLコードには規則正しくない形式(閉じタグのないタグや属性のクォートが欠落しているなど)がよく見られます。異なるパーサーは規則正しくないHTMLの処理方法が異なります:

  • html5lib:このパーサーはブラウザーと同様の動作をし、誤った構造を修正しようとするため、規則正しくないHTMLの処理に優れています。
  • lxml:lxmlパーサーは比較的に厳格ですが、ある程度の容錯能力を備えています。非常に規則正しくないHTMLを処理する場合には、事前処理を
    続けます。

必要がある場合は、lxml.etree.HTMLParserrecover=True パラメータとともに使用して回復モードを有効にすることもできます。

  • BeautifulSoup:選択したパーサーの特性に基づいて規則正しくないHTMLを処理します。複雑な規則正しくない文書の場合、html5libパーサーを優先的に使用することをおすすめします。

VIII. パフォーマンス最適化とベストプラクティス

8.1 適切なパーサーの選択

特定のニーズに基づいてパーサーを選択します:

  • lxml:HTMLが比較的標準化されている場合、速度重視の場合は最適です。
  • html5lib:規則正しくないHTMLの処理により適しています。
  • html.parser(Python組み込み):シンプルでパフォーマンス要件が中等程度の基本的なニーズに対応します。

8.2 冗長な解析の削減

複数のHTML文書を処理する場合や、同じ文書で複数回操作を行う場合は、冗長な解析を避けます。解析結果をキャッシュするか、1回の解析で全ての関連操作を完了させます。

8.3 検索メソッドの適切な使用

要素を検索する際には、不必要なトラバーサルを減らすために、より正確なフィルタ条件を使用します。例えば、CSSセレクターやXPath式を使用すると、ターゲット要素をより効率的に特定できます。

IX. まとめ

本チュートリアルを通じて、HTML処理の全般的な内容(基本構造、解析方法、文書木のナビゲーション、修正操作、データ抽出、規則正しくないHTMLの処理技術など)を学ぶことができました。実践においては、特定のシナリオに基づいて適切なツールと方法を選択し、パフォーマンス最適化とベストプラクティスに注意することで、より効率的にHTML処理タスクを完了することができます。Web開発やデータ収集のいずれの分野においても、HTML処理スキルを習得することで作業が大きく円滑化されるでしょう。

本チュートリアルではHTML処理の主要な側面を網羅しています。学習中に特定のユースケースがある場合や、特定のセクションをさらに深掘りしたい場合は、いつでもお問い合わせください。

Leapcell: The Best of Serverless Web Hosting

最後に、Pythonサービスのデプロイに最適なプラットフォーム Leapcell をご紹介します。

brandpic7.png

🚀 お好きな言語で構築

JavaScript、Python、Go、Rustで気軽に開発ができます。

🌍 無料で無制限のプロジェクトをデプロイ

使用分のみ課金 ― リクエストがなければ料金が発生しません。

⚡ 使った分だけ課金、隠れた費用はありません

アイドル料金は一切なし、シームレスなスケーラビリティが実現されています。

Frame3-withpadding2x.png

📖 ドキュメントを確認する

🔹 Twitterでフォローして最新情報を入手:@LeapcellHQ

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?