find()とfind_all()は、BeautifulSoup によるウェブスクレイピングにおいて必須のメソッドであり、HTML からデータを抽出するのに役立ちます。find()メソッドは、条件に一致する最初の要素を取得します(例:find("div")でページ上の最初のdivを取得)。一致する要素がない場合はNoneを返します。 一方、find_all() は一致する要素をすべて見つけ、リストとして返します。これにより、すべてのdivタグのような複数の要素を抽出するのに最適です。BeautifulSoup を使用したウェブスクレイピングを始める前に、Requests と BeautifulSoup の両方がインストールされていることを確認してください。
依存関係インストール
pip install requests
pip install beautifulsoup4
find()
find() の使い方を学びましょう。以下の例では、ページ上の要素を見つけるためにQuotes To Scrape とFake Store API を使用します。これらのサイトはスクレイピング用に構築されており、変更が少ないため学習に最適です。
クラスによる要素の検索
要素をクラス名で探すには、class_キーワードを使います。なぜclassではなくclass _なのか疑問に思うかもしれません。Pythonではclassはカスタムデータ型を作成するためのキーワードです。class_のアンダースコアはこのキーワードがコードと衝突するのを防ぎます。
以下の例は、class:quote を持つ最初のdiv を検索します。
import requests
from bs4 import BeautifulSoup
response = requests.get("https://quotes.toscrape.com")
soup = BeautifulSoup(response.text, "html.parser")
first_quote = soup.find("div", class_="quote")
print(first_quote.text)
出力結果は以下の通りです。
「私たちが創造した世界は、私たちの思考の産物である。思考を変えずに世界を変えることはできない。」
アルバート・アインシュタイン
(about)
Tags:
change
deep-thoughts
thinking
world
IDによる検索
スクレイピングでは、要素をIDで探すこともよく必要になります。以下の例では、id引数を使ってページ上のメニューを探します。ここでは、IDを使ってページ上のメニューを見つけます。
import requests
from bs4 import BeautifulSoup
response = requests.get("https://fakestoreapi.com")
soup = BeautifulSoup(response.text, "html.parser")
ul = soup.find("ul", id="menu")
print(ul.text)
メニューを抽出してターミナルに出力した結果は以下の通りです。
Home
Docs
GitHub
Buy me a coffee
テキストで検索
テキストを使用して項目を検索することもできます。これには文字列引数を使用します。以下の例ではページ上のログインボタンを検索します。
import requests
from bs4 import BeautifulSoup
response = requests.get("https://quotes.toscrape.com")
soup = BeautifulSoup(response.text, "html.parser")
login_button = soup.find("a", string="Login")
print(login_button.text)
ご覧の通り、コンソールに「Login」が出力されます。
ログイン
属性による検索
より正確な検索のために、異なる属性を使用することもできます。今回もページから最初の引用文を検索します。ただし、今回はitempropがtextであるspan要素を探します。これにより、著者やタグなどの余分な情報なしで、最初の引用文を再度見つけることができます。
import requests
from bs4 import BeautifulSoup
response = requests.get("https://quotes.toscrape.com")
soup = BeautifulSoup(response.text, "html.parser")
first_clean_quote = soup.find("span", attrs={"itemprop": "text"})
print(first_clean_quote.text)
最初の引用文のクリーン版はこちらです。
「私たちが創造した世界は、私たちの思考の産物である。思考を変えずに世界を変えることはできない。」
複数条件での検索
お気づきかもしれませんが、attr引数には単一の値ではなく辞書(dict)を渡せます。これにより複数の条件を指定し、より高度なフィルタリングが可能になります。ここではclass属性 とitemprop属性を使って、ページ内の最初の著者を検索します。
import requests
from bs4 import BeautifulSoup
response = requests.get("https://quotes.toscrape.com")
soup = BeautifulSoup(response.text, "html.parser")
first_author = soup.find("small", attrs={"class": "author", "itemprop": "author"})
print(first_author.text)
これを実行すると、Albert Einstein が出力されるはずです。
Albert Einstein
find_all()
では、find_all() を使用して同じ例を見ていきましょう。今回も Quotes to Scrape と Fake Store API を使用します。これらの例はほぼ同じですが、1つの大きな違いがあります。find() は単一の要素を返します。find_all() はページの要素のリストを返します。
クラスによる検索
クラスを使用して要素を検索するには、class_キーワード引数を使用します。以下のコードは、CSSクラスを使用して各引用を抽出するためにfind_all()を使用しています。
import requests
from bs4 import BeautifulSoup
response = requests.get("https://quotes.toscrape.com")
soup = BeautifulSoup(response.text, "html.parser")
quotes = soup.find_all("div", class_="quote")
for quote in quotes:
print("-------------")
print(quote.text)
最初のページの引用を抽出・表示すると、以下のようになります。
-------------
「我々が創造した世界は、我々の思考の産物である。思考を変えずに世界を変えることはできない。」
アルバート・アインシュタイン
(about)
Tags:
change
deep-thoughts
thinking
world
-------------
「ハリー、私たちの本質を示すのは能力よりも、選択そのものなのよ。」
J.K.ローリング
(about)
Tags:
abilities
choices
-------------
「人生を生きる方法は二つしかない。一つは、何も奇跡ではないかのように生きる方法。もう一つは、すべてが奇跡であるかのように生きる方法だ。」
アルバート・アインシュタイン
(について)
タグ:
インスピレーション
人生
生きる
奇跡
奇跡
-------------
「紳士であれ淑女であれ、良質な小説に喜びを見出せない者は、耐え難いほど愚かなに違いない。」
ジェーン・オースティン
(について)
タグ:
リテラシー
書籍
古典
ユーモア
-------------
「不完全さは美であり、狂気は天才である。そして、まったく退屈であるよりは、まったく滑稽であるほうがましだ。」
マリリン・モンロー
(について)
タグ:
自分らしく
インスピレーション
-------------
「成功者になろうとするな。むしろ価値ある人間になれ。」
アルバート・アインシュタイン
(について)
タグ:
大人
成功
価値
-------------
「あるがままの自分で憎まれる方が、偽りの自分で愛されるよりましだ」
アンドレ・ジッド
(について)
タグ:
人生
愛
-------------
「私は失敗したのではない。ただ1万通りの失敗の方法を見つけただけだ」
トーマス・A・エジソン
(について)
タグ:
エジソン
失敗
インスピレーション
言い換え
-------------
「女性はティーバッグのようなものです。お湯に浸けてみなければ、その強さはわからないのです。」
エレノア・ルーズベルト
(について)
タグ:
誤って帰属されたエレノア・ルーズベルトの言葉
-------------
「太陽の光のない日は、つまり、夜のようなものですね」
スティーブ・マーティン
(について)
タグ:
ユーモア
自明
直喩
ID による検索
find() の使用について述べたように、id はページからデータを抽出するために使用できる、もう 1 つの一般的なメソッドです。id を使用してデータを抽出するには、id 引数を使用します… 先ほどと同じ方法です。
次に、id がmenu のul アイテムをすべて検索します。メニューは 1 つしかないので、実際には 1 つだけが見つかります。
import requests
from bs4 import BeautifulSoup
response = requests.get("https://fakestoreapi.com")
soup = BeautifulSoup(response.text, "html.parser")
uls = soup.find_all("ul", id="menu")
for ul in uls:
print("-------------")
print(ul.text)
ページ上にメニューが1つしかないため、出力結果はfind()を使用した場合と全く同じになります。
-------------
ホーム
ドキュメント
GitHub
コーヒーをご馳走してください
テキストによる検索
次に、テキストを使用してページから項目を抽出します。文字列引数を使用します。以下の例では、文字列「Login」を含むすべてのa要素を検索します。ここでも、1つしか見つかりません。
import requests
from bs4 import BeautifulSoup
response = requests.get("https://quotes.toscrape.com")
soup = BeautifulSoup(response.text, "html.parser")
login_buttons = soup.find_all("a", string="Login")
for button in login_buttons:
print("-------------")
print(button)
出力は次のようになります。
-------------
<a href="/login">Login</a>
属性による検索
実際のスクレイピングでは、ページから項目を抽出するために他の属性を使用する必要がよくあります。最初の例の出力がいかに煩雑だったか覚えていますか?次のスニペットでは、itemprop属性を使用し、今回は引用符のみを抽出します。
import requests
from bs4 import BeautifulSoup
response = requests.get("https://quotes.toscrape.com")
soup = BeautifulSoup(response.text, "html.parser")
clean_quotes = soup.find_all("span", attrs={"itemprop": "text"})
for quote in clean_quotes:
print("-------------")
print(quote.text)
出力のきれいさを見てください!
-------------
「我々が創造した世界は、我々の思考の産物である。思考を変えずに世界を変えることはできない。」
-------------
「ハリー、我々の真の姿を示すのは能力よりも、選択なのだ。」
-------------
「人生を生きる方法は二つしかない。一つは、何も奇跡ではないかのように生きる方法。もう一つは、すべてが奇跡であるかのように生きる方法だ。」
-------------
「紳士であれ淑女であれ、良き小説に喜びを見出せない者は、耐え難いほど愚かなに違いない。」
-------------
「不完全さは美であり、狂気は天才である。まったく退屈であるよりは、まったく滑稽であるほうがましだ。」
-------------
「成功者になろうとするな。むしろ価値ある人間になれ。」
-------------
「偽りの自分への愛より、真実の自分への憎悪を選べ。」
-------------
「私は失敗したのではない。ただ1万通りの失敗の方法を見つけただけだ。」
-------------
「女性はティーバッグのようなものだ。熱湯に浸すまでは、その強さがわからない。」
-------------
「太陽の光のない日は、つまり、夜のようなものだ。」
複数条件での検索
今回はattrs引数をより複雑な方法で使用します。ここでは、class属性がauthorで itemprop属性がauthorである 小さな要素をすべて検索します。両方の属性をattrs辞書に渡すことでこれを実現します。
import requests
from bs4 import BeautifulSoup
response = requests.get("https://quotes.toscrape.com")
soup = BeautifulSoup(response.text, "html.parser")
authors = soup.find_all("small", attrs={"class": "author", "itemprop": "author"})
for author in authors:
print("-------------")
print(author.text)
コンソールに表示される著者リストは以下の通りです。
-------------
アルバート・アインシュタイン
-------------
J.K. ローリング
-------------
アルバート・アインシュタイン
-------------
ジェーン・オースティン
-------------
マリリン・モンロー
-------------
アルバート・アインシュタイン
-------------
アンドレ・ジッド
-------------
トーマス・A・エジソン
-------------
エレノア・ルーズベルト
-------------
スティーブ・マーティン
高度なテクニック
さらに高度なテクニックをいくつかご紹介します。以下の例ではfind_all() を使用していますが、これらのメソッドはfind() を使用する場合も同様に互換性があります。覚えておいてほしいのは、単一の要素が必要なのか、それともそれらのリストが必要なのか、ということです。
正規表現
正規表現は、文字列のマッチングに非常に強力なツールです。このコード例では、正規表現を文字列 article と組み合わせて、大文字小文字を問わず、einstein を含むすべての要素を検索しています。
import requests
import re
from bs4 import BeautifulSoup
response = requests.get("https://quotes.toscrape.com")
soup = BeautifulSoup(response.text, "html.parser")
pattern = re.compile(r"einstein", re.IGNORECASE)
tags = soup.find_all(string=pattern)
print(f"アインシュタインの引用文の総数: {len(tags)}")
ページ上で3件の引用が見つかりました。
アインシュタインの引用文の総数: 3
カスタム関数
次に、アインシュタインの実際の名言をすべて返すカスタム関数を作成しましょう。以下の例では、正規表現を拡張しています。親メソッドを使用して、名言を含むカードを探し出します。次に、すべてのspan要素を見つけます。カード上の最初のspan要素が実際の名言を含んでいます。その内容をコンソールに出力します。
import requests
import re
from bs4 import BeautifulSoup
def find_einstein_quotes(http_response):
soup = BeautifulSoup(http_response.text, "html.parser")
#アインシュタインタグを全て検索
pattern = re.compile(r"einstein", re.IGNORECASE)
tags = soup.find_all(string=pattern)
for tag in tags:
#引用文カードまで親要素を追跡
full_card = tag.parent.parent.parent
#span要素を検索
spans = full_card.find_all("span")
#最初のspanを出力(実際の引用文を含む)
print(spans[0].text)
if __name__ == "__main__":
response = requests.get("https://quotes.toscrape.com")
find_einstein_quotes(response)
出力結果は以下の通りです。
「私たちが創造した世界は、私たちの思考の産物である。思考を変えずに世界を変えることはできない。」
「人生を生きる方法は二つしかない。一つは、何も奇跡ではないかのように生きる方法。もう一つは、すべてが奇跡であるかのように生きる方法だ。」
「成功者になろうとするな。むしろ、価値ある人間になれ。」
ボーナス:CSSセレクタを使った検索
BeautifulSoupのselectメソッド はfind_all()とほぼ同じ動作ですが、より柔軟です。このメソッドはCSSセレクタを受け取ります。セレクタを書けるなら、それを見つけられます。このコードでは、複数の属性を使って再び著者全員を検索します。ただし、これらを単一のセレクタとして渡すことも可能です。
import requests
from bs4 import BeautifulSoup
response = requests.get("https://quotes.toscrape.com")
soup = BeautifulSoup(response.text, "html.parser")
authors = soup.select("small[class='author'][itemprop='author']")
for author in authors:
print("-------------")
print(author.text)
出力結果は以下の通りです。
-------------
アルバート・アインシュタイン
-------------
J.K. ローリング
-------------
アルバート・アインシュタイン
-------------
ジェーン・オースティン
-------------
マリリン・モンロー
-------------
アルバート・アインシュタイン
-------------
アンドレ・ジッド
-------------
トーマス・A・エジソン
-------------
エレノア・ルーズベルト
-------------
スティーブ・マーティン
まとめ
これで、BeautifulSoup のfind()およびfind_all()のあらゆる側面について理解できたと思います。これらのメソッドをすべて習得する必要はありません。さまざまな find メソッドが用意されているので、使いやすいものを選ぶことができます。 最も重要なことは、これらのメソッドを使用して、あらゆる Web ページからデータを抽出できることです。本番環境では、特に成功率の高い、高速で信頼性の高い結果を得るために、当社のレジデンシャルプロキシ、あるいはプロキシ管理システムとCAPTCHAの解決機能を内蔵したスクレイピングブラウザのご利用をご検討ください。
今すぐ無料トライアルに登録し、ご自身のニーズに最適な製品を見つけてください。