レッスンで使ったファイルはこちら
キノクエストでアカウントの新規登録に進み、メール認証を完了します。
ログインした状態(プラン選択画面が表示されます)で下記のボタンをクリックしてください。
ライブラリインポート
from bs4 import BeautifulSoup
import requests
import pandas as pd
import time
それでは、ライブラリをインポートする記述をします。
bs4のパッケージの中にあるBeautifulSoupを読み込みます。
BeautifulSoupは、複雑なHTMLの構造を解析し、必要な部分を取り出すことができるWebスクレイピング用のライブラリです。
次に、requestsをインポートします。これはPythonを使ってHTTP接続するために必要なライブラリです。
前回のWebスクレピングのレッスンで紹介したPythonの標準のurllibモジュールよりもコード量が少なく記述することができ、シンプルに実装できるライブラリです。
次に、取得したデータをCSVに書き出すために、pandasをインポートします。
asを記述するとライブラリ名を好きな名前で使うことができます。
pandasについては、「Pandas入門講座」にて詳しくご紹介していますので、ご興味があればご覧ください。
また、HTTPに接続した後、すぐに次の処理が実行されないようにするためtimeをインポートします。
timeモジュールを使うことで、Webページのデータを取得する前に次の処理にいかないように、3秒間であったり5秒間、次の処理を待機させることができます。
それでは、実行します。
インポートが完了しました。
url = 'https://kino-code.work/python-super-basic-course/'
r = requests.get(url)
time.sleep(3)
では、kinocodeのWebサイトの「Python超入門コース」のコース一覧にあるタイトルとリンク先のURLのデータを取得してみましょう。
また、そのタイトルとリンク先URLをセットにして、CSVにデータを書き込む処理を記述します。
まず、変数urlにPython超入門コースのコース一覧ページのURLを代入します。
そのurlをrequestsに渡してgetメソッドを使ってWebページのデータを取得して、変数rに代入をします。
次に、Webページへ移動する前に、次の処理に行かないように、time.sleep(3)で、3秒待機する記述をします。
<html>
<head>
<meta charset="utf-8">
<title>キノコード
</title>
</head>
<body>
<h1>こんにちは</h1>
</body>
</html>
例えば、このようなシンプルなHTMLであっても、HTMLの構造はこのようになっています。
soup = BeautifulSoup(r.text, 'html.parser')
では早速、BeautifulSoupを使って、HTMLのデータを取得するする記述をします。
BeautifulSoup()と書いてカッコの中の、第1引数に、先ほど、取得したWebページが格納されている変数rに.textを追加したものを記述します。
第二引数には、'html.parser'と記述します。
これで、Python超入門コースのコース一覧のHTMLのデータが取得できました。
変数soupを表示させてみましょう。実行します。ずらーーーといろいろデータが取得できているようです。
soup
contents = soup.find(class_="entry-content")
これだとHTMLの構造がわかりにくいので、Google Chromeを使ってHTMLの構造をみてみましょう。
Google Chrome画面を右クリックするとメニュー画面が表示されます。
一番下にある「検証」を選択してみましょう。
HTMLのソースコードの中身が確認できます。
タイトルがリンク先が記述されているのはクラス"entry-content"内のテキストと、pタグ内のhrefに記載されているリンクです。
こちらが、entry-content部分のHTMLです。
aタグ内にあるhrefのリンクです。
これらを全て取得していきます。
続いて、BeautifulSoupのfindメソッドで取得したい部分のクラスを指定し、HTMLを取得します。
classアンダースコア、イコール、entry-contentを記述します。
classはPythonの予約語のため、アンダースコアをclassの後に追加します。
ちなみに、予約語とは、プログラムミングであらかじめ決められていて、変数名などに使用できない文字列のことです。
例えば、Pythonの予約語には、if, while, with, True, Falseなどがあります。
実行します。
これで「entry-content」のクラスの情報が変数contentsに代入されたはずです。
contents
表示させてみましょう。
実行します。
entry-contentの情報が取得できています。
get_a = contents.find_all("a")
次に、find_allメソッドで、entry-contentsクラス内にあるaタグを全て取得します。
実行します。
get_a
表示させてみましょう。aタグが取得できています。
len(get_a)
今回は、aタグをカウントしてその個数分の処理をするようにします。
len関数で、変数get_aの個数を確認します。
15と出力されます。
15個のaタグが存在しています。
次は、forループでその個数分の処理をするようにします。
title_links = []
for i in range(len(get_a)):
try:
link_ = get_a[i].get("href")
title_links.append(link_)
except:
pass
forループで抜き取った複数のリンクを格納できる変数title_linksを用意します。
リスト型としたいので、角かっこで括り、中には何も代入しないでおきます。
forループで数値をカウントする場合、range関数を使用します。
例えば、for i in range(5)と記述すれば5回ループがまわります。
今回は、リンクの個数分だけループを回したいので、range関数の引数にlen(get_a)を記述します。
もし、このURL取得する際にエラーが起きた場合は、処理が止まってしまいます。
それを避けるために、例外処理を記述しましょう。
例外処理とは、プログラム内で予期せぬエラーが発生した際に、実行を止めたり、エラーを飛ばして実行を続けたりする処理のことです。
プログラミングで一般的に使われる、try-exceptで記述してみましょう。
try-exceptの構文はこのようになっています。
try:
エラーが起きない場合に実行する処理
except:
エラーが起きた場合に実行する処理
エラーが起きない場合に実行する処理を記述します。
この場合、try:の下に記述します。
リストが代入された変数の「get_a」からaタグ内にあるhrefを、getメソッドで、最初から順番に取得していきます。
iには0から14までの数字が順番に代入されていきます。
つまり、リストget_aの1つめのhrefを取得してlink_に代入、次にリストget_aの2つめのhrefをlink_に代入といった処理になります。
そして、リストのtitle_linksに対して、appendメソッドで、取得したhref、つまりリンク先URLをリストのtitle_linksに次々と追加していきます。
続いて、もしエラーが起きた場合にはexcept:の下に処理を実行します。
今回は、エラーが起きた場合は、エラーを無視するのでpassと記述します。
ちなみに、passは、特に何も処理を実行しない時に使用します。
実行します。
リンク先のURLが取得できるはずです。
title_links
取得できているか確認をしてみましょう。
実行します。
取得できています。
title_link = title_links[0]
print(title_link)
ここからは、コースの一覧ページから取得した先程のURLを利用して、各ページに移動。
そして、Youtubeのタイトルとリンクを取得する処理を行います。
for文を使って各ページに移動をするのですが、いきなりそれをやるとわかりにくいので分解して説明をします。
まず、リストの「title_links」の1番目、つまり、添字の0では、どのようなURLが取得されているかprintで表示させてみましょう。
このように添え字を使うと、リストの1番目の値を取得できますよね。
for i in range(15):
title_link = title_links[i]
print(str(i)+"回目のループ→",title_link)
したがって、このように書くと、すべてのURLが順番にtitle_linkに代入されるはずです。
わかりやすく何回目のループかも表示させてみます。
実行してみましょう。
順番にURLを取得できたようです。
for i in range(len(title_links)):
title_link = title_links[i]
print(str(i)+"回目のループ→",title_link)
先ほどはrange関数の中に直接15と記述しました。
しかし、このようにtitle_linksの数をlen関数で数えて、その個数分、for文まわせばtitle_linksの個数がいくらであっても対応可能です。
このような記述に変えてみましょう。
実行します。
問題ないですね。
youtube_titles = []
youtube_links = []
for i in range(len(title_links)):
title_link = title_links[i]
# print(str(i)+"回目のループ→",title_link)
r = requests.get(title_link)
time.sleep(3)
soup = BeautifulSoup(r.text, 'html.parser')
youtube_title = soup.find(class_="entry-title").text
print(youtube_title)
では、先ほどに記述に色々加えていき、リンク先URLのタイトルを取得しましょう。
まず、「youtube_titles」と「youtube_links」というリストを用意します。
次に、先ほど説明をしたfor文を記述します。
先程も説明した通り、リストのtitle_linksに格納されているリンクを1つずつ取り出し、変数title_linkに代入していきます。
その取得したtitle_linkをrequestsに渡して、getメソッドを使ってWebページのデータを取得し、変数rに代入をします。
Webページが読み込まれる前に、次の処理に行かないようにtime.sleep(3)で3秒待機させます。
そして、BeautifulSoupで、読み込まれたWebページのHTMLを解析をします。
ちなみに、タイトルが記載されているHTMLとなります。
<h1 class="entry-title" itemprop="headline">【5分レッスン】Python超入門コース#01 Pythonのコース紹介</h1>
したがって、find(class_="entry-title")を記述するとタイトルが取得できます。
そして、ドットtextを追加すると、タイトルのテキストを抜き取ることができます。
printでタイトルも取得できているか確認してみましょう。
実行します。
リンク先のURLとタイトルが取得できています。
youtube_titles = []
youtube_links = []
for i in range(len(title_links)):
title_link = title_links[i]
print(title_link)
r = requests.get(title_link)
time.sleep(3)
soup = BeautifulSoup(r.text, 'html.parser')
youtube_title = soup.find(class_="entry-title").text
if youtube_title == '404 NOT FOUND':
continue
else:
youtube_titles.append(youtube_title)
youtube_link = soup.find('iframe')['src'].replace("embed/","watch?v=")
youtube_links.append(youtube_link)
ちなみに、「【5分レッスン】Python超入門コース#03 環境構築 for Windows」のタイトルのリンク先のページは削除されていて、
クラスentry-titleのテキストが「404 NOT FOUND」になっていますよね。
こちらのページの処理が実行されてしまうと、エラーが起きてしまいます。
それを避けるために、変数youtube_titleが、「404 NOT FOUND」の場合は、処理がおこなわれないようにしましょう。
if文で、youtube_titleが、「404 NOT FOUND」であるか、そうでないかの判定を行います。
左辺と右辺が等しいかどうか判定する場合は、左辺イコールイコール右辺とイコールを2つ記述します。
エラーが起きた場合、処理は行わないので、その後にpassを記述します。
そして、youtube_titleが「404 NOT FOUND」ではない場合は、その下のelse:の処理に進みます。
リストのyoutube_titlesにappendを追加し、テキストを代入します。
次に、Youtubeのリンク先URLを取得します。
<iframe width="560" height="315" src="https://www.youtube.com/embed/3jymAyMJjR8" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="allowfullscreen"></iframe>
iframeタグの中のsrc、つまり、ソースに記載されているリンクを取得したいと思います。
findメソッドでiframeを渡すとiframeのタグが取得できます。
それに、丸括弧の中にsrcを加えて、srcのリンクが取得できます。
srcのリンクのアドレスですが、このままだと、Youtubeのチャンネル画面ではなく、動画のみが出てくるリンクになってしまいます。
"https://www.youtube.com/embed/3jymAyMJjR8"の「embed/」の部分を「/watch?v=」に変更すると、youtubeのチャンネル画面のリンクとなります。
したがって、replace関数を使用して、文字列を置換します。
replaceの丸括弧中の第一引数に"置換前の文字列"、第二引数に"置換後の文字列"を渡すことで、文字列の置き換えができます。
youtube_linksリストにappendを追加し、取得したリンクを格納します。
実行します。
これで、タイトルとリンク先URLが取得できているはずです。
表示させてみましょう。
youtube_titles
youtube_links
取得できています。
result ={
'youtube_title': youtube_titles,
'youtube_link': youtube_links
}
辞書型にまとめておくと、PandasのDataFrameにしやすいです。
したがって、取得したデータを辞書型にまとめておきましょう。
波括弧の中にキーと値を設定することで辞書型を作成できます。
ここでは、変数resultに、辞書型を代入する記述をします。
タイトルのキーを'youtube_title'、リンクのキーを'youtube_link'とします。
値は、先ほど取得したリストを設定します。
result
resultの中身を表示させてみましょう。
実行します。
リストを辞書型として表示できました。
df = pd.DataFrame(result)
それではデータフレームにしてみましょう。
データフレームの作り方はPandas超入門コースのレッスン4でも、詳しく解説をしています。
そちらもご覧ください。
dfイコール、pd.DataFrame丸括弧で、データフレームを用意します。
辞書型のresultで取得したデータを格納します。
df
データフレームを確認してみましょう。
綺麗にデータを取得できているようです。
またリンクエラーの環境構築のWindowsは取得せずにエラーになっておりません。
df.to_csv('result.csv', index=False, encoding='utf-8')
データフレームを、CSVへ書き出しましょう。
pandasのto_csvメソッドを使ってCSVへ書き出す記述をします。
第一引数には、任意のCSVファイル名を記述し、シングルコーテーションでくくります。
ここでは、result.csvとします。
indexイコールFalseとすることで、インデックスをつけない設定にします。
インデックスとは、データフレームにした際に自動的に出力される行番号のことです。
最後に、文字化けを避けるために、endodingで文字コードを指定します。
ここではutf-8とします。
実行します。
CSVファイルを作成できました。
レッスンで使ったファイルはこちら
キノクエストでアカウントの新規登録に進み、メール認証を完了します。
ログインした状態(プラン選択画面が表示されます)で下記のボタンをクリックしてください。