美しいスープとPython 3でWebページをスクレイピングする方法

前書き

多くのデータ分析、ビッグデータ、機械学習プロジェクトでは、使用するデータを収集するためにWebサイトをスクレイピングする必要があります。 Pythonプログラミング言語はデータサイエンスコミュニティで広く使用されているため、独自のプロジェクトで使用できるモジュールとツールのエコシステムを備えています。 このチュートリアルでは、Beautiful Soupモジュールに焦点を当てます。

Beautiful Soup、ルイスキャロルの_Alice’s Adventuresの第10章で見つかったhttps://en.wikipedia.org/wiki/Mock_Turtle[Mock Turtle’s]の歌の暗示Wonderland_にある、Webスクレイピングプロジェクトの迅速なターンアラウンドを可能にするPythonライブラリです。 現在、Beautiful Soup 4として利用可能で、Python 2.7とPython 3の両方と互換性があります。BeautifulSoupは、解析されたHTMLおよびXMLドキュメント(閉じられていないタグまたはhttps://en.wikipedia.org/wiki/Tag_soupを含むドキュメント)から解析ツリーを作成します[タグスープ]およびその他の不正なマークアップ)。

このチュートリアルでは、テキストデータを取得し、収集した情報をCSVファイルに書き込むために、Webページを収集して解析します。

前提条件

このチュートリアルに取り組む前に、https://www.digitalocean.com/community/tutorial_series/how-to-install-and-set-up-a-local-programming-environment-for-python-3 [ local]またはhttps://www.digitalocean.com/community/tutorials/how-to-install-python-3-and-set-up-a-programming-environment-on-an-an-ubuntu-16-04-server [サーバーベース] Pythonプログラミング環境がマシンにセットアップされています。

RequestsおよびBeautiful Soupモジュールを*インストール*する必要があります。これは、チュートリアル「https://www.digitalocean.com/community/tutorials/how-to-work-with-web-data-using- requests-and-beautiful-soup-with-python-3 [リクエストとPython 3を使用したBeautiful Soupを使用してWebデータを操作する方法]。これらのモジュールに精通していることも役立ちます。

さらに、Webからスクレイピングされたデータを扱うため、HTMLの構造とタグ付けに慣れている必要があります。

データを理解する

このチュートリアルでは、米国のhttps://www.nga.gov/[National Gallery of Art]の公式ウェブサイトのデータを使用します。 ナショナルギャラリーは、ワシントンD.C.のナショナルモールにある美術館です。 ルネサンスから現在まで、13,000人以上のアーティストが制作した120,000を超える作品を所蔵しています。

このチュートリアルを更新する時点で、https://archive.org/ [Internet Archive]のhttps://web.archive.org/[Wayback]から入手できるアーティストのインデックスを検索したいマシン]次のURLで:

  • https://web.archive.org/web/20170131230332/https://www.nga.gov/collection/an.shtm*

インターネットアーカイブのヘッダーの下に、次のようなページが表示されます。

image:https://assets.digitalocean.com/articles/eng_python/beautiful-soup/index-of-artists-landing-page.png [アーティストのリンク先ページのインデックス]

Beautiful Soupを使用してWebスクレイピングについて学習するためにこのプロジェクトを行うため、サイトから大量のデータを取得する必要はありません。したがって、スクレイピングするアーティストデータの範囲を制限しましょう。 したがって、1つの文字を選択してみましょう(この例では、文字* Z *を選択します)。次のようなページが表示されます。

image:https://assets.digitalocean.com/articles/eng_python/beautiful-soup/artist-names-beginning-with-z-2018.png [Zリストで始まるアーティスト名]

上記のページでは、執筆時点で最初にリストされたアーティストは、ニッカラ州ザバリア*であることがわかります。これは、データのプルを開始するときの注意事項です。 この最初のページで作業を開始します。文字* Z *の次のURLを使用します。

リストすることを選択しているレターの合計ページ数を後で確認することが重要です。これは、アーティストの最後のページまでクリックして見つけることができます。 この場合、合計4ページあり、執筆時点でリストされている最後のアーティストは* Zykmund、Václav*です。 * Z *アーティストの最後のページには、次のURLがあります。

ただし、最初のページと同じインターネットアーカイブの数値文字列を使用して、上記のページにアクセスすることもできます。

このチュートリアルの後半でこれらのページを反復処理するため、これは重要です。

このWebページの設定方法を理解するには、https://www.digitalocean.com/community/tutorials/introduction-to-the-dom [DOM]をご覧ください。 HTMLの構造を理解します。 DOMを検査するには、ブラウザーのhttps://www.digitalocean.com/community/tutorials/how-to-use-the-javascript-developer-console#understanding-other-development-tools [開発者ツール]。

ライブラリのインポート

コーディングプロジェクトを開始するために、Python 3プログラミング環境をアクティブにしましょう。 環境が存在するディレクトリにいることを確認し、次のコマンドを実行します。

. /bin/activate

プログラミング環境をアクティブにして、たとえばnanoなどの新しいファイルを作成します。 ファイルには任意の名前を付けることができます。このチュートリアルでは、「+ nga_z_artists.py +」と呼びます。

nano

このファイル内で、使用するライブラリのインポートを開始できます-http://docs.python-requests.org/en/master/[Requests] and Beautiful Soup。

Requestsライブラリを使用すると、Pythonプログラム内で人間が読める方法でHTTPを使用できます。BeautifulSoupモジュールは、Webスクレイピングをすばやく実行できるように設計されています。

https://www.digitalocean.com/community/tutorials/how-to-import-modules-in-python-3 [`+ import `ステートメント]を使用してリクエストとビューティフルスープの両方をインポートします。 Beautiful Soupの場合、Beautiful Soup 4が含まれているパッケージである ` bs4 +`からインポートします。

nga_z_artists.py

# Import libraries
import requests
from bs4 import BeautifulSoup

RequestsモジュールとBeautiful Soupモジュールの両方をインポートしたら、まずページを収集してから解析する作業に進むことができます。

Webページの収集と解析

次のステップは、リクエストを含む最初のWebページのURLを収集することです。 httpを使用して、最初のページのURLをhttps://www.digitalocean.com/community/tutorials/how-to-use-variables-in-python-3[variable] + page +`に割り当てます://docs.python-requests.org/en/master/user/quickstart/#make-a-request [method `+ requests.get()+]。

nga_z_artists.py

import requests
from bs4 import BeautifulSoup


# Collect first page of artists’ list

ここで、 + BeautifulSoup +`オブジェクト、または解析ツリーを作成します。 このオブジェクトは引数としてRequestsからの `+ page.text +`ドキュメント(サーバーの応答のコンテンツ)を受け取り、Pythonの組み込みhttps://docs.python.org/3/library/html.parserからそれを解析します.html [+ 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

ページを収集して解析し、 `+ BeautifulSoup +`オブジェクトとして設定したら、希望するデータの収集に進むことができます。

Webページからテキストを取得する

このプロジェクトでは、アーティストの名前とウェブサイトで利用可能な関連リンクを収集します。 アーティストの国籍や日付など、さまざまなデータを収集できます。 収集するデータが何であれ、それがWebページのDOMによってどのように記述されているかを調べる必要があります。

これを行うには、Webブラウザーで、最初のアーティストの名前* Zabaglia、Niccola を右クリック(または、Mac OSでは「+ CTRL」キーを押しながらクリック)します。 ポップアップ表示されるコンテキストメニュー内に、 Inspect Element (Firefox)または Inspect *(Chrome)のようなメニュー項目が表示されます。

image:https://assets.digitalocean.com/articles/eng_python/beautiful-soup/inspect-element.png [コンテキストメニュー-要素の検査]

関連する[検査]メニュー項目をクリックすると、ブラウザ内にWeb開発者向けのツールが表示されます。 このリストでアーティストの名前に関連付けられているクラスとタグを探します。

image:https://assets.digitalocean.com/articles/eng_python/beautiful-soup/web-page-inspector.png [Webページインスペクター]

最初に、名前のテーブルが、 `+ class =" BodyText "`の ` <div> `タグ内にあることがわかります。 これは、Webページのこのセクション内のテキストのみを検索するように注意することが重要です。 また、* Zabaglia、Niccola *という名前は、リンクタグに含まれていることにも気付きます。これは、名前がアーティストを説明するWebページを参照しているためです。 したがって、リンクのために ` <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


# Pull text from all instances of <a> tag within BodyText div

次に、プログラムファイルの下部で、https://www.digitalocean.com/community/tutorials/how-to-construct-for-loops-in-python-3 [`+ for `を作成します。ループ]で、 ` artist_name_list_items +`変数に入れたすべてのアーティスト名を反復処理します。

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

これまでのプログラムを実行してみましょう。

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>

この時点で出力に表示されるのは、フルテキストと、上の「+ <div class = "BodyText"> + タグ内にある + <a> + `タグ内のすべてのアーティスト名に関連するタグです。最初のページ、および下部の追加のリンクテキスト。 この追加情報は必要ないので、次のセクションでこれを削除してみましょう。

余分なデータを削除する

これまでのところ、Webページの1つの `+ <div> +`セクション内ですべてのリンクテキストデータを収集することができました。 ただし、アーティストの名前を参照しない下部リンクは必要ないので、その部分を削除してみましょう。

ページの下のリンクを削除するには、もう一度右クリックしてDOMを*検査*します。 + <div class =" BodyText "> +`セクションの下部にあるリンクがHTMLテーブルに含まれていることがわかります: `+ <table class =" AlphaNav "> +

image:https://assets.digitalocean.com/articles/eng python / beautifulsoup / html-table.png [Alpha Nav HTMLテーブルのリンク]

したがって、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



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>

この時点で、出力にはウェブページの下部にリンクが含まれなくなり、アーティスト名に関連付けられたリンクのみが表示されるようになりました。

これまで、アーティスト名のリンクを具体的にターゲットにしてきましたが、あまり望まない余分なタグデータがあります。 次のセクションでそれを削除しましょう。

タグからコンテンツを引き出す

実際のアーティスト名のみにアクセスするには、リンクタグ全体を印刷するのではなく、「+ <a> +」タグのコンテンツをターゲットに設定します。

これは、Beautiful Soupの `+ .contents +`を使用して行うことができます。これにより、タグの子がPython list 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 <a> tag’s children
for artist_name in artist_name_list_items:

各アイテムのhttps://www.digitalocean.com/community/tutorials/understanding-lists-in-python-3#indexing-lists [インデックス番号]を呼び出して、上記のリストを繰り返し処理していることに注意してください。

`+ python`コマンドでプログラムを実行して、次の出力を表示できます。

OutputZabaglia, Niccola
Zaccone, Fabian
Zadkine, Ossip
...
Zanini-Viola, Giuseppe
Zanotti, Giampietro
Zao Wou-Ki

手紙* Z *の最初のページにあるすべてのアーティストの名前のリストを受け取りました。

ただし、それらのアーティストに関連付けられているURLもキャプチャする場合はどうでしょうか。 Beautiful Soupの `+ get( 'href')`メソッドを使用して、ページの ` <a> +`タグ内で見つかったURLを抽出できます。

上記のリンクの出力から、URL全体がキャプチャされていないことがわかっているため、https://www.digitalocean.com/community/tutorials/an-introduction-to-working-with-strings-in- python-3#string-concatenation [concatenate] URL文字列の前にあるリンク文字列(この場合は + https:// web.archive.org / +)。

これらの行は `+ for`ループにも追加されます:

nga_z_artists.py

...
for artist_name in artist_name_list_items:
   names = artist_name.contents[0]

   print(names)

上記のプログラムを実行すると、アーティストの名前と、アーティストの詳細を示すリンクへの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)ファイルを使用すると、表形式のデータをプレーンテキストで保存でき、スプレッドシートやデータベースの一般的な形式です。 このセクションを開始する前に、https://www.digitalocean.com/community/tutorials/how-to-handle-plain-text-files-in-python-3 [プレーンテキストファイルの処理方法Python]。

最初に、Pythonの組み込みファイル「+ csv +」モジュールと、Pythonプログラミングファイルの先頭にある他のモジュールをインポートする必要があります。

import csv

次に、 `+ .csv `というファイルを作成して開き、https://www.digitalocean.com/community/tutorials/how-to-handle-plain-text-files-in-python-3にアクセスします。 #step-4-%E2%80%94-writing-a-file [write to](ここではファイルに変数 ` 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])

以下のファイルで、これらの各タスクの行を確認できます。

nga_z_artists.py

import requests

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



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

`+ python`コマンドでプログラムを実行すると、出力はターミナルウィンドウに返されません。 代わりに、作業中のディレクトリに「+ .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
...

または、スプレッドシートのように見える場合があります。

image:https://assets.digitalocean.com/articles/eng_python/beautiful-soup/csv-spreadsheet-2018.png [CSV Spreadsheet]

どちらの場合でも、収集した情報がコンピュータのメモリに保存されるようになったため、このファイルを使用して、より意味のある方法でデータを操作できます。

関連ページの取得

姓が* 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)

https://www.digitalocean.com/community/tutorials/how-to-scrape-web-pages-with-beautiful-soup-and-python-3#understanding-the-data [このチュートリアルの前半]、文字* Z *(または使用している文字)で始まるアーティスト名を含むページの総数に注意する必要があります。 * Z *の文字には4ページあるため、上記の「+ for 」ループを「+1」から「5」の範囲で作成し、4ページごとに繰り返します。

この特定のWebサイトの場合、URLは文字列 `+ https://web.archive.org/web/20121007172955/https:// www.nga.gov / collection / anZ `で始まり、その後に番号が続きますページ(これは、https://www.digitalocean.com/community/tutorials/how-to-convert-data-types-in-python-3の「 for 」ループからの整数「 i 」になります[文字列に変換する])そして、 ` .htm `で終わります。 これらの文字列を連結して、結果を ` pages +`リストに追加します。

このループに加えて、上記の各ページを通過する2番目のループがあります。 この「+ for 」ループのコードは、これまでに作成したコードに似ています。これは、合計4ページごとに* Z *アーティストの文字の最初のページで完了したタスクを実行しているためです。 元のプログラムを2番目の「 for 」ループに入れているため、元のループはhttps://www.digitalocean.com/community/tutorials/how-to-construct-for-loops- in-python-3#nested-for-loops [ネストされた ` for +`ループ]が含まれます。

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ファイルを作成するには少し時間がかかります。 完了すると、出力が完了し、アーティスト名と、*ザバリア、ニコーラ*から*ジクムンド、ヴァーツラフ*への関連リンクが表示されます。

思いやりがある

Webページをスクレイピングするときは、情報を取得するサーバーを慎重に検討することが重要です。

サイトにWebスクレイピングに関連する利用規約または利用規約があるかどうかを確認します。 また、サイトに自分でデータを取得する前にデータを取得できるAPIがあるかどうかを確認します。

サーバーに連続的にアクセスしてデータを収集しないようにしてください。 サイトから必要なものを収集したら、他の人のサーバーに負担をかけるのではなく、データをローカルでスキャンするスクリプトを実行します。

さらに、ウェブサイトがあなたを特定し、質問がある場合はフォローアップできるように、あなたの名前とメールを含むヘッダーを削っておくことをお勧めします。 Python Requestsライブラリで使用できるヘッダーの例は次のとおりです。

import requests

headers = {
   'User-Agent': ', ',
   'From': ''
}

url = 'https://.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ページをクロールする方法]。