前書き
多くのデータ分析、ビッグデータ、機械学習プロジェクトでは、使用するデータを収集するためにWebサイトをスクレイピングする必要があります。 Pythonプログラミング言語はデータサイエンスコミュニティで広く使用されているため、独自のプロジェクトで使用できるモジュールとツールのエコシステムを備えています。 このチュートリアルでは、Beautiful Soupモジュールに焦点を当てます。
ルイスキャロルのAlice’s Adventures in Wonderlandの第10章にあるMock Turtle’sの曲のほのめかしであるBeautiful Soupは、Webスクレイピングプロジェクトの迅速なターンアラウンドを可能にするPythonライブラリです。 現在BeautifulSoup 4として利用可能で、Python2.7とPython3の両方と互換性があり、Beautiful Soupは、解析されたHTMLおよびXMLドキュメント(閉じられていないタグまたはtag soupおよびその他の不正な形式のマークアップを含むドキュメントを含む)から解析ツリーを作成します。
このチュートリアルでは、テキストデータを取得し、収集した情報をCSVファイルに書き込むために、Webページを収集して解析します。
前提条件
このチュートリアルに取り組む前に、localまたはserver-basedのPythonプログラミング環境をマシンにセットアップしておく必要があります。
RequestsモジュールとBeautifulSoupモジュールinstalledが必要です。これは、チュートリアル「https://www.digitalocean.com/community/tutorials/how-to-work-with-web-data-」に従って実行できます。 using-requests-and-beautiful-soup-with-python-3 [リクエストを使用してWebデータを操作する方法とPython3で美しいスープを使用する方法]。これらのモジュールについて実用的な知識があると便利です。
さらに、Webからスクレイピングされたデータを扱うため、HTMLの構造とタグ付けに慣れている必要があります。
データを理解する
このチュートリアルでは、米国のNational Gallery of Artの公式ウェブサイトのデータを使用します。 ナショナルギャラリーは、ワシントンD.C.のナショナルモールにある美術館です。 ルネサンスから現在まで、13,000人以上のアーティストが制作した120,000を超える作品を所蔵しています。
アーティストのインデックスを検索したいと思います。このチュートリアルの更新時に、次のURLのInternet ArchiveのWayback Machineから入手できます。
[。注意]##
Note:上記の長いURLは、このWebサイトがインターネットアーカイブによってアーカイブされているためです。
インターネットアーカイブは、インターネットサイトやその他のデジタルメディアへの無料アクセスを提供する非営利のデジタルライブラリです。 この組織は、ウェブサイトのスナップショットを取り、サイトの履歴を保存します。現在、このチュートリアルが最初に作成されたときに利用できたナショナルギャラリーのサイトの古いバージョンにアクセスできます。 インターネットアーカイブは、同じサイトと利用可能なデータの反復間での比較を含む、あらゆる種類の履歴データスクレイピングを行う際に留意すべき優れたツールです。
インターネットアーカイブのヘッダーの下に、次のようなページが表示されます。
Beautiful Soupを使用してWebスクレイピングについて学習するためにこのプロジェクトを行うため、サイトから大量のデータを取得する必要はありません。したがって、スクレイピングするアーティストデータの範囲を制限しましょう。 したがって、1つの文字を選択しましょう(この例では、文字Zを選択します)。次のようなページが表示されます。
上のページでは、執筆時点で最初にリストされているアーティストがZabaglia, Niccolaであることがわかります。これは、データのプルを開始するときに注意することをお勧めします。 この最初のページで、文字Zの次のURLを使用して作業を開始します。
リストすることを選択しているレターの合計ページ数を後で確認することが重要です。これは、アーティストの最後のページまでクリックして見つけることができます。 この場合、合計4ページあり、執筆時点でリストされている最後のアーティストはZykmund, Václavです。 Zアーティストの最後のページには、次のURLがあります。
Howeverの場合、最初のページと同じインターネットアーカイブの数値文字列を使用して上記のページにアクセスすることもできます。
このチュートリアルの後半でこれらのページを反復処理するため、これは重要です。
このWebページがどのように設定されているかを理解するために、そのDOMを確認すると、HTMLがどのように構造化されているかを理解するのに役立ちます。 DOMを検査するために、ブラウザのDeveloper Toolsを開くことができます。
ライブラリのインポート
コーディングプロジェクトを開始するために、Python 3プログラミング環境をアクティブにしましょう。 環境が存在するディレクトリにいることを確認し、次のコマンドを実行します。
. my_env/bin/activate
プログラミング環境をアクティブにして、たとえばnanoなどの新しいファイルを作成します。 ファイルには任意の名前を付けることができます。このチュートリアルでは、ファイルをnga_z_artists.py
と呼びます。
nano nga_z_artists.py
このファイル内で、使用するライブラリ(RequestsとBeautiful Soup)のインポートを開始できます。
Requestsライブラリを使用すると、Pythonプログラム内で人間が読める方法でHTTPを使用できます。BeautifulSoupモジュールは、Webスクレイピングをすばやく実行できるように設計されています。
リクエストと美しいスープの両方をimport
statementでインポートします。 Beautiful Soupの場合、Beautiful Soup 4が含まれているパッケージであるbs4
からインポートします。
nga_z_artists.py
# Import libraries
import requests
from bs4 import BeautifulSoup
RequestsモジュールとBeautiful Soupモジュールの両方をインポートしたら、最初にページを収集してから解析する作業に進むことができます。
Webページの収集と解析
次のステップは、リクエストを含む最初のWebページのURLを収集することです。 method requests.get()
を使用して、最初のページのURLをvariablepage
に割り当てます。
nga_z_artists.py
import requests
from bs4 import BeautifulSoup
# Collect first page of artists’ list
page = requests.get('https://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ1.htm')
Note:URLが長いため、このチュートリアルの上記および全体のコードは、79文字より長い行にフラグを立てるPEP 8 E501を渡しません。 最終バージョンでコードを読みやすくするために、URLを変数に割り当てることができます。 このチュートリアルのコードはデモンストレーション用であり、独自のプロジェクトの一部として短いURLを交換することができます。
次に、BeautifulSoup
オブジェクトまたは解析ツリーを作成します。 このオブジェクトは、その引数としてRequestsからのpage.text
ドキュメント(サーバーの応答のコンテンツ)を取り、Pythonの組み込みhtml.parser
からそれを解析します。
nga_z_artists.py
import requests
from bs4 import BeautifulSoup
page = requests.get('https://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ1.htm')
# Create a BeautifulSoup object
soup = BeautifulSoup(page.text, 'html.parser')
ページが収集され、解析され、BeautifulSoup
オブジェクトとして設定されたら、必要なデータの収集に進むことができます。
Webページからテキストを取得する
このプロジェクトでは、アーティストの名前とウェブサイトで利用可能な関連リンクを収集します。 アーティストの国籍や日付など、さまざまなデータを収集できます。 収集するデータが何であれ、それがWebページのDOMによってどのように記述されているかを調べる必要があります。
これを行うには、Webブラウザーで、最初のアーティストの名前Zabaglia, Niccolaを右クリック(またはCTRL
+ macOSをクリック)します。 ポップアップ表示されるコンテキストメニュー内に、Inspect Element(Firefox)またはInspect(Chrome)のようなメニュー項目が表示されます。
関連するInspectメニュー項目をクリックすると、Web開発者向けのツールがブラウザ内に表示されます。 このリストでアーティストの名前に関連付けられているクラスとタグを探します。
最初に、名前のテーブルが<div>
タグ内にあり、class="BodyText"
であることがわかります。 これは、Webページのこのセクション内のテキストのみを検索するように注意することが重要です。 また、名前がアーティストを説明するWebページを参照しているため、名前Zabaglia, Niccolaがリンクタグに含まれていることにも注意してください。 したがって、リンクの<a>
タグを参照する必要があります。 各アーティストの名前はリンクへの参照です。
これを行うには、Beautiful Soupのfind()
メソッドとfind_all()
メソッドを使用して、BodyText
<div>
からアーティストの名前のテキストを取得します。
nga_z_artists.py
import requests
from bs4 import BeautifulSoup
# Collect and parse first page
page = requests.get('https://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ1.htm')
soup = BeautifulSoup(page.text, 'html.parser')
# Pull all text from the BodyText div
artist_name_list = soup.find(class_='BodyText')
# Pull text from all instances of tag within BodyText div
artist_name_list_items = artist_name_list.find_all('a')
次に、プログラムファイルの下部に、artist_name_list_items
変数に入力したすべてのアーティスト名を反復処理するためにfor
loopを作成します。
Beautiful Soup解析ツリーを適切にフォーマットされたUnicode文字列に変換するために、これらの名前をprettify()
メソッドで出力します。
nga_z_artists.py
...
artist_name_list = soup.find(class_='BodyText')
artist_name_list_items = artist_name_list.find_all('a')
# Create for loop to print out all artists' names
for artist_name in artist_name_list_items:
print(artist_name.prettify())
これまでのプログラムを実行してみましょう。
python nga_z_artists.py
そうすると、次の出力が表示されます。
Output
Zabaglia, Niccola
...
Zao Wou-Ki
Zas-Zie
Zie-Zor
next
page
この時点で出力に表示されるのは、最初のページの<div class="BodyText">
タグにある<a>
タグ内のすべてのアーティストの名前に関連する全文とタグ、およびいくつかの追加のタグです。下部のリンクテキスト。 この追加情報は必要ないので、次のセクションでこれを削除してみましょう。
余分なデータを削除する
これまでのところ、Webページの1つの<div>
セクション内のすべてのリンクテキストデータを収集することができました。 ただし、アーティストの名前を参照しない下部のリンクは必要ないので、その部分を削除してみましょう。
ページの下部のリンクを削除するには、もう一度右クリックしてDOMをInspectします。 <div class="BodyText">
セクションの下部にあるリンクがHTMLテーブルに含まれていることがわかります。<table class="AlphaNav">
:
したがって、Beautiful Soupを使用してAlphaNav
クラスを検索し、decompose()
メソッドを使用して解析ツリーからタグを削除し、その内容とともにタグを破棄できます。
変数last_links
を使用して、これらの下部リンクを参照し、プログラムファイルに追加します。
nga_z_artists.py
import requests
from bs4 import BeautifulSoup
page = requests.get('https://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ1.htm')
soup = BeautifulSoup(page.text, 'html.parser')
# Remove bottom links
last_links = soup.find(class_='AlphaNav')
last_links.decompose()
artist_name_list = soup.find(class_='BodyText')
artist_name_list_items = artist_name_list.find_all('a')
for artist_name in artist_name_list_items:
print(artist_name.prettify())
ここで、python nga_z_artist.py
コマンドを使用してプログラムを実行すると、次の出力が表示されます。
この時点で、出力にはウェブページの下部にリンクが含まれなくなり、アーティスト名に関連付けられたリンクのみが表示されるようになりました。
これまで、アーティスト名のリンクを具体的にターゲットにしてきましたが、あまり望まない余分なタグデータがあります。 次のセクションでそれを削除しましょう。
タグからコンテンツを引き出す
実際のアーティストの名前のみにアクセスするには、リンクタグ全体を印刷するのではなく、<a>
タグのコンテンツをターゲットにする必要があります。
これは、Beautiful Soupの.contents
を使用して行うことができます。これにより、タグの子がPythonlist data typeとして返されます。
リンク全体とそのタグを印刷する代わりに、子のリストを印刷するように、for
ループを修正しましょう(つまり、 アーティストのフルネーム):
nga_z_artists.py
import requests
from bs4 import BeautifulSoup
page = requests.get('https://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ1.htm')
soup = BeautifulSoup(page.text, 'html.parser')
last_links = soup.find(class_='AlphaNav')
last_links.decompose()
artist_name_list = soup.find(class_='BodyText')
artist_name_list_items = artist_name_list.find_all('a')
# Use .contents to pull out the tag’s children
for artist_name in artist_name_list_items:
names = artist_name.contents[0]
print(names)
各アイテムのindex numberを呼び出すことにより、上記のリストを反復処理していることに注意してください。
python
コマンドを使用してプログラムを実行すると、次の出力が表示されます。
OutputZabaglia, Niccola
Zaccone, Fabian
Zadkine, Ossip
...
Zanini-Viola, Giuseppe
Zanotti, Giampietro
Zao Wou-Ki
手紙Zの最初のページにあるすべてのアーティストの名前のリストを受け取りました。
ただし、それらのアーティストに関連付けられているURLもキャプチャする場合はどうでしょうか。 Beautiful Soupのget('href')
メソッドを使用して、ページの<a>
タグ内で見つかったURLを抽出できます。
上記のリンクの出力から、URL全体がキャプチャされていないことがわかっているため、リンク文字列をURL文字列の前にconcatenateします(この場合はhttps://web.archive.org/
)。
これらの行もfor
ループに追加します。
nga_z_artists.py
...
for artist_name in artist_name_list_items:
names = artist_name.contents[0]
links = 'https://web.archive.org' + artist_name.get('href')
print(names)
print(links)
上記のプログラムを実行すると、bothのアーティストの名前と、アーティストについて詳しく説明しているリンクへのURLが表示されます。
OutputZabaglia, Niccola
https://web.archive.org/web/20121007172955/https://www.nga.gov/cgi-bin/tsearch?artistid=11630
Zaccone, Fabian
https://web.archive.org/web/20121007172955/https://www.nga.gov/cgi-bin/tsearch?artistid=34202
...
Zanotti, Giampietro
https://web.archive.org/web/20121007172955/https://www.nga.gov/cgi-bin/tsearch?artistid=11631
Zao Wou-Ki
https://web.archive.org/web/20121007172955/https://www.nga.gov/cgi-bin/tsearch?artistid=3427
現在、Webサイトから情報を取得していますが、現在はターミナルウィンドウに印刷しています。 代わりに、このデータをキャプチャして、ファイルに書き込むことで他の場所で使用できるようにします。
データをCSVファイルに書き込む
ターミナルウィンドウにのみ存在するデータを収集することは、あまり役に立ちません。 コンマ区切り値(CSV)ファイルを使用すると、表形式のデータをプレーンテキストで保存でき、スプレッドシートやデータベースの一般的な形式です。 このセクションを開始する前に、how to handle plain text files in Pythonについて理解しておく必要があります。
まず、Pythonの組み込みcsv
モジュールを、Pythonプログラミングファイルの先頭にある他のモジュールと一緒にインポートする必要があります。
import csv
次に、'w'
モードを使用して、z-artist-names.csv
というファイルを作成してwrite toに開きます(ここではファイルに変数f
を使用します)。 また、一番上の行の見出し:Name
とLink
を記述し、これらをリストとしてwriterow()
メソッドに渡します。
f = csv.writer(open('z-artist-names.csv', 'w'))
f.writerow(['Name', 'Link'])
最後に、for
ループ内で、アーティストのnames
とそれに関連するlinks
を使用して各行を記述します。
f.writerow([names, links])
以下のファイルでこれらの各タスクの行を確認できます。
nga_z_artists.py
import requests
import csv
from bs4 import BeautifulSoup
page = requests.get('https://web.archive.org/web/20121007172955/http://www.nga.gov/collection/anZ1.htm')
soup = BeautifulSoup(page.text, 'html.parser')
last_links = soup.find(class_='AlphaNav')
last_links.decompose()
# Create a file to write to, add headers row
f = csv.writer(open('z-artist-names.csv', 'w'))
f.writerow(['Name', 'Link'])
artist_name_list = soup.find(class_='BodyText')
artist_name_list_items = artist_name_list.find_all('a')
for artist_name in artist_name_list_items:
names = artist_name.contents[0]
links = 'https://web.archive.org' + artist_name.get('href')
# Add each artist’s name and associated link to a row
f.writerow([names, links])
python
コマンドを使用してプログラムを実行すると、ターミナルウィンドウに出力は返されません。 代わりに、作業しているディレクトリにz-artist-names.csv
というファイルが作成されます。
開くために使用するものに応じて、次のようになります。
z-artist-names.csv
Name,Link
"Zabaglia, Niccola",https://web.archive.org/web/20121007172955/http://www.nga.gov/cgi-bin/tsearch?artistid=11630
"Zaccone, Fabian",https://web.archive.org/web/20121007172955/http://www.nga.gov/cgi-bin/tsearch?artistid=34202
"Zadkine, Ossip",https://web.archive.org/web/20121007172955/http://www.nga.gov/cgi-bin/tsearch?artistid=3475w
...
または、スプレッドシートのように見える場合があります。
どちらの場合でも、収集した情報がコンピュータのメモリに保存されるようになったため、このファイルを使用して、より意味のある方法でデータを操作できます。
関連ページの取得
家系の名前が文字Zで始まるアーティストのリストの最初のページからデータを取得するプログラムを作成しました。 ただし、これらのアーティストの合計4ページがWebサイトで利用可能です。
これらすべてのページを収集するために、for
ループを使用してさらに反復を実行できます。 これにより、これまでに記述したコードのほとんどが修正されますが、同様の概念が採用されます。
まず、リストを初期化してページを保持します。
pages = []
この初期化されたリストに次のfor
ループを設定します。
for i in range(1, 5):
url = 'https://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ' + str(i) + '.htm'
pages.append(url)
Earlier in this tutorial、文字Z(または使用している文字)で始まるアーティストの名前を含むページの総数に注意する必要があることに注意しました。 文字Zには4ページあるため、上記のfor
ループを1
から5
の範囲で作成し、4ページのそれぞれを反復処理するようにしました。 。
この特定のWebサイトの場合、URLは文字列https://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ
で始まり、その後にページの番号が続きます(これは、for
ループからの整数i
になります。 t3)s)で終わり、.htm
で終わります。 これらの文字列を連結して、結果をpages
リストに追加します。
このループに加えて、上記の各ページを通過する2番目のループがあります。 このfor
ループのコードは、これまでに作成したコードと同じように見えます。これは、合計4ページのそれぞれについてZアーティストの手紙の最初のページで完了したタスクを実行しているためです。 。 元のプログラムを2番目のfor
ループに入れたので、元のループがnested for
loopとして含まれていることに注意してください。
2つのfor
ループは次のようになります。
pages = []
for i in range(1, 5):
url = 'https://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ' + str(i) + '.htm'
pages.append(url)
for item in pages:
page = requests.get(item)
soup = BeautifulSoup(page.text, 'html.parser')
last_links = soup.find(class_='AlphaNav')
last_links.decompose()
artist_name_list = soup.find(class_='BodyText')
artist_name_list_items = artist_name_list.find_all('a')
for artist_name in artist_name_list_items:
names = artist_name.contents[0]
links = 'https://web.archive.org' + artist_name.get('href')
f.writerow([names, links])
上記のコードでは、最初のfor
ループがページを反復処理し、2番目のfor
ループがそれらの各ページからデータを取得してから、アーティストの名前とリンク行を追加していることがわかります。各ページの各行を1行ずつ通過します。
これらの2つのfor
ループは、import
ステートメント、CSVファイルの作成とライター(ファイルのヘッダーを書き込むための行を含む)、およびpages
変数の初期化(割り当て済み)の下にあります。リストへ)。
プログラミングファイルのより大きなコンテキスト内では、完全なコードは次のようになります。
nga_z_artists.py
import requests
import csv
from bs4 import BeautifulSoup
f = csv.writer(open('z-artist-names.csv', 'w'))
f.writerow(['Name', 'Link'])
pages = []
for i in range(1, 5):
url = 'https://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ' + str(i) + '.htm'
pages.append(url)
for item in pages:
page = requests.get(item)
soup = BeautifulSoup(page.text, 'html.parser')
last_links = soup.find(class_='AlphaNav')
last_links.decompose()
artist_name_list = soup.find(class_='BodyText')
artist_name_list_items = artist_name_list.find_all('a')
for artist_name in artist_name_list_items:
names = artist_name.contents[0]
links = 'https://web.archive.org' + artist_name.get('href')
f.writerow([names, links])
このプログラムは少し作業をしているため、CSVファイルを作成するには少し時間がかかります。 完了すると、出力が完了し、アーティストの名前とそれに関連するZabaglia, NiccolaからZykmund, Václavへのリンクが表示されます。
思いやりがある
Webページをスクレイピングするときは、情報を取得するサーバーを慎重に検討することが重要です。
サイトにWebスクレイピングに関連する利用規約または利用規約があるかどうかを確認します。 また、サイトに自分でデータを取得する前にデータを取得できるAPIがあるかどうかを確認します。
サーバーに継続的にアクセスしてデータを収集しないでください。 サイトから必要なものを収集したら、他の人のサーバーに負担をかけるのではなく、データをローカルでスキャンするスクリプトを実行します。
さらに、ウェブサイトがあなたを特定し、質問がある場合はフォローアップできるように、あなたの名前とメールを含むヘッダーを削っておくことをお勧めします。 Python Requestsライブラリで使用できるヘッダーの例は次のとおりです。
import requests
headers = {
'User-Agent': 'Your Name, example.com',
'From': '[email protected]'
}
url = 'https://example.com'
page = requests.get(url, headers = headers)
識別可能な情報でヘッダーを使用すると、サーバーのログを調べた人があなたに連絡できるようになります。
結論
このチュートリアルでは、PythonとBeautiful Soupを使用してWebサイトからデータを取得しました。 収集したテキストをCSVファイルに保存しました。
より多くのデータを収集し、CSVファイルをより堅牢にすることで、このプロジェクトの作業を続けることができます。 たとえば、各アーティストの国籍と年を含めることができます。 学んだことを使用して、他のWebサイトからデータをスクレイピングすることもできます。
ウェブから情報を引き出すことについて学び続けるには、チュートリアル「https://www.digitalocean.com/community/tutorials/how-to-crawl-a-web-page-with-scrapy-and-python-3 [ ScrapyとPython 3を使用してWebページをクロールする方法]。