美しいスープとPython3でWebページをスクレイプする方法
序章
多くのデータ分析、ビッグデータ、機械学習プロジェクトでは、作業するデータを収集するためにウェブサイトをスクレイピングする必要があります。 Pythonプログラミング言語はデータサイエンスコミュニティで広く使用されているため、独自のプロジェクトで使用できるモジュールとツールのエコシステムがあります。 このチュートリアルでは、BeautifulSoupモジュールに焦点を当てます。
Beautiful Soup は、ルイス・キャロルの不思議の国のアリスの第10章にあるモックタートルのの曲のほのめかしであり、迅速なターンアラウンドを可能にするPythonライブラリです。ウェブスクレイピングプロジェクト。 現在BeautifulSoup4として利用可能で、Python2.7とPython3の両方と互換性があります。BeautifulSoupは、解析されたHTMLおよびXMLドキュメント(閉じられていないタグまたはタグスープおよびその他の不正な形式のマークアップを含むドキュメントを含む)から解析ツリーを作成します。 。
このチュートリアルでは、テキストデータを取得し、収集した情報をCSVファイルに書き込むために、Webページを収集して解析します。
前提条件
このチュートリアルに取り組む前に、ローカルまたはサーバーベースのPythonプログラミング環境をマシンにセットアップしておく必要があります。
RequestsとBeautifulSoupモジュールがインストールされている必要があります。これは、チュートリアル「RequestsとBeautifulSoupwith Python3を使用してWebデータを操作する方法」に従って実行できます。 これらのモジュールに実際に精通していることも役立ちます。
さらに、Webからスクレイピングされたデータを処理するため、HTML構造とタグ付けに慣れている必要があります。
データを理解する
このチュートリアルでは、米国の National Gallery ofArtの公式ウェブサイトのデータを使用します。 ナショナルギャラリーは、ワシントンDCのナショナルモールにある美術館です。 13,000人以上の芸術家によって行われたルネッサンスから現在までの12万点以上の作品を保持しています。
このチュートリアルの更新時に、インターネットアーカイブのウェイバックマシンから次のURLで入手できるアーティストのインデックスを検索したいと思います。
https://web.archive.org/web/20170131230332/https://www.nga.gov/collection/an.shtm
注:上記の長いURLは、このWebサイトがインターネットアーカイブによってアーカイブされているためです。
インターネットアーカイブは、インターネットサイトやその他のデジタルメディアへの無料アクセスを提供する非営利のデジタルライブラリです。 この組織は、サイトの履歴を保存するためにWebサイトのスナップショットを取得します。現在、このチュートリアルが最初に作成されたときに利用可能だったナショナルギャラリーのサイトの古いバージョンにアクセスできます。 Internet Archiveは、同じサイトと利用可能なデータの反復を比較するなど、あらゆる種類の履歴データのスクレイピングを行うときに覚えておくとよいツールです。
インターネットアーカイブのヘッダーの下に、次のようなページが表示されます。
このプロジェクトは、Beautiful Soupを使用したWebスクレイピングについて学習するために行うため、サイトからあまり多くのデータを取得する必要がないため、スクレイピングするアーティストデータの範囲を制限しましょう。 したがって、1つの文字を選択しましょう—この例では文字 Z を選択します—そして次のようなページが表示されます。
上のページでは、執筆時点で最初にリストされているアーティストが Zabaglia、Niccola であることがわかります。これは、データの取得を開始するときに注意することをお勧めします。 この最初のページで、文字Zの次のURLを使用して作業を開始します。
https://web.archive.org/web/20121007172955/http://www.nga.gov/collection/anZ1.htm
後で、リストすることを選択した手紙の合計ページ数に注意することが重要です。これは、アーティストの最後のページをクリックして見つけることができます。 この場合、合計4ページあり、執筆時点でリストされている最後のアーティストは Zykmund、Václavです。 Z アーティストの最後のページには、次のURLがあります。
https://web.archive.org/web/20121010201041/http://www.nga.gov/collection/anZ4.htm
ただし、最初のページと同じインターネットアーカイブの数値文字列を使用して上記のページにアクセスすることもできます。
https://web.archive.org/web/ 20121007172955 /http://www.nga.gov/collection/anZ4.htm
このチュートリアルの後半でこれらのページを繰り返し処理するため、これは注意することが重要です。
このWebページがどのように設定されているかを理解するために、HTMLがどのように構造化されているかを理解するのに役立つDOMを見ることができます。 DOMを検査するために、ブラウザの開発者ツールを開くことができます。
ライブラリのインポート
コーディングプロジェクトを開始するには、Python3プログラミング環境をアクティブ化しましょう。 環境が配置されているディレクトリにいることを確認し、次のコマンドを実行します。
- . my_env/bin/activate
プログラミング環境をアクティブにして、たとえばnanoを使用して新しいファイルを作成します。 ファイルには好きな名前を付けることができます。これを名前にします。 nga_z_artists.py
このチュートリアルでは。
- nano nga_z_artists.py
このファイル内で、使用するライブラリ( RequestsとBeautifulSoup)のインポートを開始できます。
Requestsライブラリを使用すると、Pythonプログラム内で人間が読める形式でHTTPを利用できます。また、Beautiful Soupモジュールは、Webスクレイピングをすばやく実行できるように設計されています。
importステートメントを使用してリクエストとBeautifulSoupの両方をインポートします。 美しいスープの場合は、からインポートします bs4
、BeautifulSoup4が入っているパッケージ。
# Import libraries
import requests
from bs4 import BeautifulSoup
RequestsモジュールとBeautifulSoupモジュールの両方がインポートされたら、最初にページを収集してから解析する作業に進むことができます。
Webページの収集と解析
次のステップは、リクエストを含む最初のWebページのURLを収集することです。 最初のページのURLを変数に割り当てます page
メソッドrequests.get()を使用します。
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')
<$>[注] ノート :URLが長いため、このチュートリアル全体の上記のコードは通過しません PEP 8 E501 79文字より長い行にフラグを立てます。 最終バージョンでコードを読みやすくするために、URLを変数に割り当てることができます。 このチュートリアルのコードはデモンストレーション用であり、独自のプロジェクトの一部として短いURLを交換できるようにします。<$>
次に、 BeautifulSoup
オブジェクト、または解析ツリー。 このオブジェクトは、引数として page.text
Requests(サーバーの応答のコンテンツ)からのドキュメントを作成し、Pythonの組み込みhtml.parserから解析します。
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ブラウザで右クリックします—または CTRL
+ macOSをクリックします—最初のアーティストの名前 Zabaglia、Niccolaをクリックします。 ポップアップ表示されるコンテキストメニュー内に、 Inspect Element (Firefox)または Inspect (Chrome)のようなメニュー項目が表示されます。
関連するInspectメニュー項目をクリックすると、Web開発者向けのツールがブラウザー内に表示されます。 このリストでアーティストの名前に関連付けられているクラスとタグを探します。
名前のテーブルが中にあることが最初にわかります <div>
ここでタグ class="BodyText"
. これは、Webページのこのセクション内のテキストのみを検索するように注意することが重要です。 また、 Zabaglia、Niccola という名前は、アーティストを説明するWebページを参照しているため、リンクタグに含まれていることにも注意してください。 したがって、参照する必要があります <a>
リンクのタグ。 各アーティストの名前は、リンクへの参照です。
これを行うには、BeautifulSoupを使用します find()
と find_all()
からアーティストの名前のテキストを引き出すためのメソッド BodyText
<div>
.
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 <a> tag within BodyText div
artist_name_list_items = artist_name_list.find_all('a')
次に、プログラムファイルの下部に、 for loop を作成して、入力したすべてのアーティスト名を繰り返し処理します。 artist_name_list_items
変数。
これらの名前を印刷します prettify()
BeautifulSoup解析ツリーを適切にフォーマットされたUnicode文字列に変換するためのメソッド。
...
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<a href="/web/20121007172955/https://www.nga.gov/cgi-bin/tsearch?artistid=11630">
Zabaglia, Niccola
</a>
...
<a href="/web/20121007172955/https://www.nga.gov/cgi-bin/tsearch?artistid=3427">
Zao Wou-Ki
</a>
<a href="/web/20121007172955/https://www.nga.gov/collection/anZ2.htm">
Zas-Zie
</a>
<a href="/web/20121007172955/https://www.nga.gov/collection/anZ3.htm">
Zie-Zor
</a>
<a href="/web/20121007172955/https://www.nga.gov/collection/anZ4.htm">
<strong>
next
<br/>
page
</strong>
</a>
この時点で出力に表示されるのは、内のすべてのアーティストの名前に関連する全文とタグです。 <a>
にあるタグ <div class="BodyText">
最初のページにタグを付け、下部に追加のリンクテキストをいくつか追加します。 この余分な情報は必要ないので、次のセクションでこれを削除してみましょう。
不要なデータの削除
これまでのところ、1つにすべてのリンクテキストデータを収集することができました <div>
私たちのウェブページのセクション。 ただし、アーティストの名前を参照しない下部リンクは必要ないので、その部分を削除してみましょう。
ページの下部のリンクを削除するには、もう一度右クリックしてDOMを検査します。 下部のリンクが表示されます <div class="BodyText">
セクションはHTMLテーブルに含まれています。 <table class="AlphaNav">
:
したがって、BeautifulSoupを使用して AlphaNav
クラスを使用して decompose()
解析ツリーからタグを削除し、その内容とともにタグを破棄するメソッド。
変数を使用します last_links
これらの下部のリンクを参照して、プログラムファイルに追加するには:
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
コマンドを実行すると、次の出力が返されます。
Output<a href="/web/20121007172955/https://www.nga.gov/cgi-bin/tsearch?artistid=11630">
Zabaglia, Niccola
</a>
<a href="/web/20121007172955/https://www.nga.gov/cgi-bin/tsearch?artistid=34202">
Zaccone, Fabian
</a>
...
<a href="/web/20121007172955/http://www.nga.gov/cgi-bin/tsearch?artistid=11631">
Zanotti, Giampietro
</a>
<a href="/web/20121007172955/http://www.nga.gov/cgi-bin/tsearch?artistid=3427">
Zao Wou-Ki
</a>
この時点で、出力にはWebページの下部にあるリンクが含まれなくなり、アーティストの名前に関連付けられたリンクのみが表示されるようになりました。
これまで、アーティスト名のリンクを具体的にターゲットにしてきましたが、本当に必要のない余分なタグデータがあります。 次のセクションでそれを削除しましょう。
タグからコンテンツをプルする
実際のアーティストの名前だけにアクセスするために、 <a>
リンクタグ全体を印刷するのではなく、タグを付けます。
私たちは美しいスープでこれを行うことができます .contents
、タグの子をPythonリストデータ型として返します。
修正しましょう for
リンク全体とそのタグを印刷する代わりに、子のリストを印刷するようにループします(つまり、 アーティストのフルネーム):
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 <a> tag’s children
for artist_name in artist_name_list_items:
names = artist_name.contents[0]
print(names)
各アイテムのインデックス番号を呼び出して、上記のリストを繰り返し処理していることに注意してください。
私たちはプログラムを実行することができます python
次の出力を表示するコマンド:
OutputZabaglia, Niccola
Zaccone, Fabian
Zadkine, Ossip
...
Zanini-Viola, Giuseppe
Zanotti, Giampietro
Zao Wou-Ki
手紙Zの最初のページにあるすべてのアーティストの名前のリストを受け取りました。
ただし、それらのアーティストに関連付けられているURLもキャプチャする場合はどうでしょうか。 ページ内で見つかったURLを抽出できます <a>
美しいスープを使用してタグを付ける get('href')
方法。
上記のリンクの出力から、URL全体がキャプチャされていないことがわかっているため、リンク文字列をURL文字列の先頭に連結します(この場合) https://web.archive.org/
).
これらの行も追加します for
ループ:
...
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)
上記のプログラムを実行すると、両方のアーティストの名前と、アーティストについて詳しく説明しているリンクへの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)ファイルを使用すると、表形式のデータをプレーンテキストで保存でき、スプレッドシートやデータベースの一般的な形式です。 このセクションを始める前に、Pythonでプレーンテキストファイルを処理する方法をよく理解しておく必要があります。
まず、Pythonの組み込みをインポートする必要があります csv
Pythonプログラミングファイルの先頭にある他のモジュールと一緒にモジュール:
import csv
次に、というファイルを作成して開きます z-artist-names.csv
への書き込み(変数を使用します) f
ここにファイルの場合)を使用して 'w'
モード。 一番上の行の見出しも記述します。 Name
と Link
これをに渡します writerow()
リストとしてのメソッド:
f = csv.writer(open('z-artist-names.csv', 'w'))
f.writerow(['Name', 'Link'])
最後に、私たちの中で for
ループ、各行をアーティストと一緒に書きます names
およびそれらに関連する links
:
f.writerow([names, links])
以下のファイルで、これらの各タスクの行を確認できます。
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
.
開くために使用するものによっては、次のようになります。
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ページがあります。
これらのページをすべて収集するために、次のコマンドでさらに反復を実行できます。 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)
このチュートリアルの前半で、文字 Z (または使用している文字)で始まるアーティストの名前を含むページの総数に注意する必要があることに注意しました。 )。 Z の文字は4ページあるので、 for
の範囲で上記のループ 1
に 5
4ページのそれぞれを繰り返すようにします。
この特定のWebサイトの場合、URLは文字列で始まります https://web.archive.org/web/20121007172955/https://www.nga.gov/collection/anZ
次に、ページの番号(整数になります)が続きます i
から for
文字列に変換して終了するループ .htm
. これらの文字列を連結して、結果をに追加します pages
リスト。
このループに加えて、上記の各ページを通過する2番目のループがあります。 この中のコード for
ループは、合計4ページのそれぞれについて、レター Z アーティストの最初のページで完了したタスクを実行しているため、これまでに作成したコードと同じように見えます。 元のプログラムを2番目に入れているので注意してください for
これで、元のループがネストされたforループとして含まれるようになりました。
二つ 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
loopは、これらの各ページからデータを取得し、各ページの各行にアーティストの名前とリンクを1行ずつ追加します。
この二つ for
ループは下に来る import
ステートメント、CSVファイルの作成とライター(ファイルのヘッダーを書き込むための行を含む)、および pages
変数(リストに割り当てられます)。
プログラミングファイルのより大きなコンテキスト内では、完全なコードは次のようになります。
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ページをスクレイピングするときは、情報を取得するサーバーに注意を払うことが重要です。
サイトにウェブスクレイピングに関連する利用規約または利用規約があるかどうかを確認します。 また、自分でデータを取得する前にデータを取得できるAPIがサイトにあるかどうかを確認してください。
データを収集するためにサーバーに継続的にアクセスしないようにしてください。 サイトから必要なものを収集したら、他の人のサーバーに負担をかけるのではなく、ローカルでデータを調べるスクリプトを実行します。
さらに、Webサイトがあなたを識別し、質問がある場合にフォローアップできるように、名前と電子メールが含まれるヘッダーをスクレイプすることをお勧めします。 PythonRequestsライブラリで使用できるヘッダーの例は次のとおりです。
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サイトからデータを取得することもできます。
Webから情報を取得する方法について引き続き学習するには、チュートリアル「ScrapyとPython3を使用してWebページをクロールする方法」をお読みください。