LoginSignup
18

More than 3 years have passed since last update.

BeautifulSoupを用いたHTMLデータの検索方法

Posted at

1.概要

データ解析用にいろいろなタグ情報をHTMLに埋め込み、「その埋め込んだデータが正しく表示されているか」を自動テストで検出できないか、いろいろ方法を調べてみました。

その中で、PythonのBeautifulSoupを用いて対象のHTMLデータを検索出来たので、その方法をまとめます。
※本件は検索方法のみで解析については記載しておりません。

2.検索方法の考え方

BeautifulSoupで対象のHTMLデータを取得するには、まず起点となる<>で囲まれたデータを見つけます。そして、起点となるタグに含まれている情報を1つ1つ記載していくことで、HTMLデータを検索します。

image.png

起点とすべきデータはユニークな値を持つものを指定すると、その項目のみを指定すればいいので、検索プログラムの記載がシンプルになります。

また、3章以降の例文を動作するには、以下のプログラムが記載されていることを前提としております。


import requests
import re
from bs4 import BeautifulSoup

res = requests.get('ここに解析対象のURLを記載')
c=res.content
soup = BeautifulSoup(c,'html.parser')

#ここに例文を記載

print(elems)

3.基本的なデータの取得方法

取得したいデータが1つの場合はfindを、複数の場合はfind_allを利用します(その他にselectという方法もありますが、今回除外します)。以下の例文ではfind_allを用いています。

・直接タグを指定するパターン

#検索したいタグの構造
<script></script>
elems = soup.find_all("script")

単純なタグで囲まれた部分を検索する場合、利用します。

・複数のタグを指定するパターン(リストを利用)

#検索したいタグの構造
<h1></h1>
<div></div>
elems = soup.find_all(["h1","div"])

タグで囲まれているデータを複数検索したい場合、利用します。

・キーワードを指定するパターン(完全一致)

#検索したいタグの構造
<a class = "test"></a>
elems = soup.find_all(class_="test")

各タグの中で「=」を用いて値が代入されている項目がある場合、利用します。
また、classを指定する場合は「class_」とする必要があります。(Pythonの予約語にclassが使われているので)
検索項目が2つある場合は、以下のように[]を使います。

elems = soup.find_all(id=["test1", "test2"])

・キーワードを指定するパターン(部分一致)

#検索したいタグの構造
<a href="http://○○/△△.html"><a>
elems = soup.find_all(href=re.compile("http://"))

「=」で代入されている値を部分的に検索する場合などに利用します。

・キーワードを指定するパターン(attrs属性を利用した完全一致)

#検索したいタグの構造
<a href="http://○○/△△.html"><a>
elems = soup.find_all(attrs={"href":"http://○○/△△.html"})

HTML5のdataタグなど、キーワードとして使えないものがあるときは「attrs」を利用します

#例)
× elems = soup.find_all("meta",name="test")
TypeError: find_all() got multiple values for argument 'name'

○ elems = soup.find_all("meta",attrs={"name":"test"})

・項目のありなしを確認するパターン(値が入っていればTrue、入っていなければFalse)

#検索したいタグの構造
<a href="http://○○/△△.html"><a>
elems = soup.find_all(href=True)

hrefなどのタグに何でもいいので値が入っているものを調べる場合、利用します。
値が入っていない場合は、以下のようにFalseを指定します

elems = soup.find_all(id=False)

・タグで囲まれているテキストを検索するパターン(完全一致)

#検索したいタグの構造
<a href="http://○○/△△.html">ご利用案内<a> #ここのご利用案内のみ検索したい
elems = soup.find_all(text='ご利用案内')

タグで囲まれた中のテキストのみ抽出したい場合、利用します。

・タグで囲まれているテキストを検索するパターン(部分一致)

#検索したいタグの構造
<a href="http://○○/△△.html">ご利用案内<a> #ここのご利用案内のみ検索したい
elems = soup.find_all(text=re.compile("ご"))

タグで囲まれた中のテキストのみ抽出したい場合、利用します。こちらは完全一致ではなく、部分一致を用いています。

・収集するタグの数を指定するパターン(find_allのみ利用できる)

#検索したいタグの構造
<p>test1</p> #ここだけ取得したい
<p>test2</p>
elems = soup.find_all('p', limit=1)

複数のタグから指定した数だけ取得したい場合、利用します。

4.応用編

指定した構造データを見つけるには、上記の基本パターンを組み合わせて使うことが多いです。

・タグとキーワードを指定

#検索したいタグの構造
<meta name="test">
elems = soup.find_all("meta",attrs={"name":"test"})

metaというタグにname=testをしているタグを検索する場合、利用します。

・タグとテキストを指定

#検索したいタグの構造
<a href="http://○○/△△.html">テストです<a>
elems = soup.find_all("a",text="テストです")

aタグで「テストです」とテキスト文が記載されているタグを検索する場合

・attrsで項目を複数指定

#検索したいタグの構造
<a href="http://○○/△△.html" title="test">テストです</a>
elems = soup.find_all(attrs={"title":"test","href":"http://○○/△△.html"})

・起点の前後のタグを指定

また、同じようなタグが複数あるため指定の構造データを検索できない場合は、起点となる構造データを決めてそのデータの前後を検索するようにします。前後の検索には、「next_element」と「previous_element」を利用します。
(next_elementは後の要素を検索する場合、previous_elementは前の要素を検索する場合に利用します)

#検索したいタグの構造
<ui>
 <li>
  <a href="http://○○/△△.html">test</a>
 </li>
</ui>

#取得したいのはここ
<ui>
 <li>
  <a href="http://□□/☆☆.html">test2</a> #ここを起点にデータを取得する
 </li>
</ui>
elems = soup.find_all("a",href="http://□□/☆☆.html")
elems2 = elems[0].previous_element.previous_element #.previous_elementを2回使い、<ui><li>までを含むようにする

・関数を作成して指定

関数を作成し、複雑なタグ構造からデータを取得することもできます。

#検索したいタグの構造
<a class="test"></a> #ここだけ取得したい
<a id="test"></a>
def has_class_but_no_id(tag):
    return tag.has_attr('class') and not tag.has_attr('id')

elems = soup.find_all(has_class_but_no_id)

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
18