Python で lxmlライブラリ を使って HTML を解析する方法 を解説します。
lxml は、XML と HTML を処理するためのライブラリです。標準ライブラリではないのでインストールする必要があります。
lxmlライブラリ を使って簡単なスクレイピングを行ってみましょう!
lxml とは、XML と HTML を処理するためのライブラリです。
Linklxml - Processing XML and HTML with Python
標準ライブラリではないので pip を使ってインストールする必要があります。
ターミナル、またはコマンドプロンプト
pip install lxml
lxml をインストールしたら次に使い方を見ていきましょう!
HTML文字列 を読み込むには、lxml.html の fromstring() を使います。
import lxml.html lxml.html.fromstring(html文字列)
今回はわかりやすいように複数行文字列を簡単な HTML として読み込んでみます。
import lxml.html # HTMLデータ html = '''<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>サイトタイトル</title> </head> <body> <h1>タイトル</h1> <h2>見出し1</h2> <p>コンテンツの内容</p> </body> </html>''' root = lxml.html.fromstring(html) print(root)
実行結果
<Element html at 0x10678ccc0>
root には、タグの情報がツリー構造で格納されています。
それでは、タグを取得する方法を見ていきましょう!
head属性からheadタグ、body属性からbodyタグを取得できる。
root = lxml.html.fromstring(html) print(root.head, root.body)
実行結果
<Element head at 0x10252a3b0> <Element body at 0x102536310>
headタグ以下、またはbodyタグ以下の情報が欲しいときに使います。
リストに変換することで子要素をリストとしてまとめて取得できる。
root = lxml.html.fromstring(html) print(list(root))
実行結果
[<Element head at 0x1012e95e0>, <Element body at 0x1012e97c0>]
インデックスを指定して取得することもできる。
root = lxml.html.fromstring(html) print(root[0], root[1])
実行結果
<Element head at 0x104a035e0> <Element body at 0x104a037c0>
親要素を取得するには、getparent() を使います。
root = lxml.html.fromstring(html) print(root.body.getparent())
実行結果
<Element html at 0x105705450>
前のタグを getprevious()、次のタグを getnext() で取得できます。
root = lxml.html.fromstring(html) # body の取得 body = root.body # body の子要素 print(f'bodyの子要素: {list(body)}') # body の中の h2 h2 = body[1] # h2 の前のタグ print(f'h2の前のタグ: {h2.getprevious()}') # h2 の次のタグ print(f'h2の次のタグ: {h2.getnext()}')
実行結果
bodyの子要素: [<Element h1 at 0x106a59680>, <Element h2 at 0x106a59860>, <Element p at 0x106a773b0>] h2の前のタグ: <Element h1 at 0x106a59860> h2の次のタグ: <Element p at 0x106a59860>
ルートは xpath('/*') で取得できる。
root = lxml.html.fromstring(html) # body の取得 body = root.body # body の中の h2 h2 = body[1] # h2 からルートの取得 print(h2.xpath('/*'))
実行結果
[<Element html at 0x105871f40>]
xpath() はリストでタグを取得するので注意。
find() を使うことでタグを探すことができる。
root = lxml.html.fromstring(html) # body の取得 body = root.find('body') print(body) # h1 の取得 h1 = root.find('body/h1') print(h1)
実行結果
<Element body at 0x100ba0400> <Element h1 at 0x100bac770>
findall() を使うことで複数の要素を取得できる。
root = lxml.html.fromstring(html) # body 内のタグの取得 in_body = root.findall('body/*') print(in_body)
実行結果
[<Element h1 at 0x1020bf3b0>, <Element h2 at 0x1020bf7c0>, <Element p at 0x1020bf9a0>]
xpath() を使っても同様のことができる。
root = lxml.html.fromstring(html) print(root.xpath('body/*'))
実行結果
[<Element h1 at 0x10c73a400>, <Element h2 at 0x10c7433b0>, <Element p at 0x10c7437c0>]
タグの指定方法は以下の記事を参考にしてください。
外部リンクロケーションパス(省略構文) - XPathのまとめ、要素の参照方法いろいろ │ Web備忘録
タグに指定した ID から検索できる。
# HTMLデータ html = '''<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>サイトタイトル</title> </head> <body> <h1 id="title">タイトル</h1> <h2>見出し1</h2> <p>コンテンツの内容</p> </body> </html>''' root = lxml.html.fromstring(html) # title という ID を持つタグの取得 title = root.get_element_by_id('title') print(title)
実行結果
<Element h1 at 0x10f7a6630>
タグから属性やテキストを取得する方法を見ていきましょう!
tag 属性からタグ名を取得することができます。
root = lxml.html.fromstring(html) # h1 の取得 h1 = root.find('body/h1') # タグ名の取得 print(h1.tag)
実行結果
h1
attrib 属性からタグの属性を辞書として取得できる。
root = lxml.html.fromstring(html) # h1 の取得 h1 = root.find('body/h1') # 属性の取得 print(h1.attrib)
実行結果
{'id': 'title'}
get() で指定した属性のみを取得することもできる。
root = lxml.html.fromstring(html) # h1 の取得 h1 = root.find('body/h1') # 属性の取得 print(h1.get('id'))
実行結果
title
text 属性からタグに囲まれているテキストを取得できる。
root = lxml.html.fromstring(html) # h1 の取得 h1 = root.find('body/h1') # 属性の取得 print(h1.text)
実行結果
タイトル
直下のテキストしか取得できないので <h1><a>タイトル</a></h1> のようになっている場合は注意。
インライン要素の後ろにあるテキストは tail 属性から取得する。
html = '<p>あいうえお<span>かきくけこ</span>さしすせそ</p>' p = lxml.html.fromstring(html) # span の取得 span = p.find('span') # span の後ろのテキスト print(span.tail)
実行結果
さしすせそ
試しに適当なサイトの記事内の見出しを抜き出してみます。
import lxml.html import requests # 適当なURL url = 'https://yumarublog.com/python/str' # # URLを開く r = requests.get(url) # HTML文字列の読み込み root = lxml.html.fromstring(r.text) body = root.body # 記事内の見出しのみを取得 elems = body.xpath('//div[@class="cps-post-main-box"]//h2') for elem in elems: print(elem.text)
実行結果
大文字小文字に変換して比較する casefold()メソッドを使う 正規表現を使う
この記事では、lxmlライブラリを使ってHTML文字列を解析する方法を解説しました。
lxml はとても高速で簡単にスクレイピングすることができます。解析するサイトの迷惑にならないように高速でアクセスするのは避けましょう!
それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ