#1.概要
データ解析用にいろいろなタグ情報をHTMLに埋め込み、「その埋め込んだデータが正しく表示されているか」を自動テストで検出できないか、いろいろ方法を調べてみました。
その中で、PythonのBeautifulSoupを用いて対象のHTMLデータを検索出来たので、その方法をまとめます。
※本件は検索方法のみで解析については記載しておりません。
#2.検索方法の考え方
BeautifulSoupで対象のHTMLデータを取得するには、まず起点となる<>で囲まれたデータを見つけます。そして、起点となるタグに含まれている情報を1つ1つ記載していくことで、HTMLデータを検索します。
起点とすべきデータはユニークな値を持つものを指定すると、その項目のみを指定すればいいので、検索プログラムの記載がシンプルになります。
また、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)