BeautifulSoup
前回、urllibライブラリを使って、Webページの取得と保存を行いました。
今回からは取得したWebページを解析する手法を色々と試していきましょう。
Webページを解析するには「BeautifulSoup」というライブラリを用います。
と言うことで今回はBeautifulSoupのインストールと多分皆さんが一番興味があるだろうリンクの取得を行なっていきます。
それでは始めていきましょう。
BeautifulSoupのインストール
BeautifulSoupのインストールはpipで行います。
pip install bs4
「bs4」と言うのはBeautifulSoup 4の略で、4はバージョンのようです。
ここで指定しない(つまりpip install beautifulsoupとすると)と古いBeautifulSoupがインストールされてしまうこともあるようです。
Webから直接BeautifulSoupで解析する方法
前回、サーバーに負荷を掛けないようにWebページのデータを保存したのですが、十分に気をつけて解析する場合、保存せずに直接解析することが多いようです(現時点では私は怖くてできませんが)。
ということでまずは「Webから直接BeautifulSoupにデータを渡し、解析する方法」を試してみましょう。
今回使用するサイトはこの3PySciです。
前回同様、サーバーに負荷をかけない程度(1回/5秒程度でしょうか)であれば3PySciを使っていただいて構いませんが、毎秒何十回もアクセスするようなやり方はやめてください。
ということで書いてみるとこんな感じです。
from bs4 import BeautifulSoup
import urllib
url = 'https://3pysci.com'
with urllib.request.urlopen(url) as response:
soup = BeautifulSoup(response)
print(soup)
実行結果
<!DOCTYPE html>
<html data-loaded="false" data-scrolled="false" data-spmenu="closed" lang="ja">
<head>
<meta charset="utf-8"/>
<meta content="telephone=no" name="format-detection"/>
<meta content="IE=edge" http-equiv="X-UA-Compatible"/>
<meta content="width=device-width, viewport-fit=cover" name="viewport"/>
(以下略)
前回同様、Webページを取得するため「urllib」を使用します。
またBeautifulSoupを使うためインポートしています(from bs4 import BeautifulSoup)。
そして「urllib.request.urlopen」でWebページを取得し、それをそのままBeautifulSoupに渡します(soup = BeautifulSoup(response))。
そしてそのBeautifulSoupから出力されるデータ(上の例では「soup」)が解析されたデータになります。
しかし「print(soup)」では結果が表示されるのではなく、解析したhtmlのデータがそのまま出力されれます。
保存したhtmlファイルをBeautifulSoupで解析する方法
次に「保存したhtmlファイルをBeautifulSoupで解析する方法」を試してみましょう。
と言っても難しいことななく、単にhtmlファイルを開いて、それをBeautifulSoupに渡すだけです。
from bs4 import BeautifulSoup
inputfile = './3pysci.html'
with open(inputfile, 'r') as f_in:
soup = BeautifulSoup(f_in)
print(soup)
実行結果
<!DOCTYPE html>
<html data-loaded="false" data-scrolled="false" data-spmenu="closed" lang="ja">
<head>
<meta charset="utf-8"/>
<meta content="telephone=no" name="format-detection"/>
<meta content="IE=edge" http-equiv="X-UA-Compatible"/>
<meta content="width=device-width, viewport-fit=cover" name="viewport"/>
(以下略)
では今回はこの解析されたデータからリンクを出力してみましょう。
タグを指定して、リンクを出力:.find(‘タグ’)と.find_all(‘タグ’)
htmlデータからリンクを出力するには、「aタグ」なるものを抽出します。
例えばhtml上でのリンクの記載はこんな感じです。
<a href="https://3pysci.com/about/">About</a>
つまり「<a href=’リンク先’>リンクのテキスト</a>」という構成でリンクを表現しています。
ちなみに上記の例はあくまでも基本の形で、表現が複雑になると「aタグ」内の記載が複雑になります。
とりあえず「aタグ」を抽出できれば、リンクの情報を取得できるというわけです。
その場合に使うコマンドは「.find(‘タグ’)」と「.find_all(‘タグ’)」です。
「.find(‘タグ’)」では最初に見つけたタグの情報を取得します(つまり一つだけ)。
「.find_all(‘タグ’)」ではhtmlに含まれるタグの情報をリスト形式で全て取得します。
まずは「.find(‘タグ’)」を試してみましょう。
from bs4 import BeautifulSoup
inputfile = './3pysci.html'
with open(inputfile, 'r') as f_in:
soup = BeautifulSoup(f_in)
print(soup.find('a'))
実行結果
<a href="https://3pysci.com/about/">About</a>
最初(かどうかは確認していませんが)のaタグの情報が取得できました。
次に「.find_all(‘タグ’)」を試してみます。
from bs4 import BeautifulSoup
inputfile = './3pysci.html'
with open(inputfile, 'r') as f_in:
soup = BeautifulSoup(f_in)
print(soup.find_all('a'))
実行結果
[<a href="https://3pysci.com/about/">About</a>,
<a href="https://3pysci.com/category/3dprinter/">3D Printer</a>,
<a href="https://3pysci.com/category/programming/">Programming</a>,
<a aria-current="page" href="https://3pysci.com/category/device/">Device</a>,
<a href="https://3pysci.com/category/other/">Other</a>,
<a href="https://3pysci.com/privacy-policy/">Privacy Policy</a>,
<a aria-label="twitter" class="c-iconList__link u-fz-14 hov-flash"
href="https://twitter.com/3PySci_Nori" rel="noopener" target="_blank">
<i class="c-iconList__icon icon-twitter" role="presentation"></i></a>,
(以下略)
リスト形式で沢山のリンクの情報が取得できました。
ただこのままでは使いにくいので、リンクのテキストとリンクのURLの取得をしてみましょう。
リンクのテキストの取得
まずはリンクのテキストの取得を試してみます。
リンクのテキストを取得するには「.find(‘a’).getText()」です。
ちなみにリンクを取得するためaタグを指定していますが、他のタグでもテキストを取得する際は「.getText()」で取得します。
「.find(‘a’)」だけの結果と比較してみましょう。
from bs4 import BeautifulSoup
inputfile = './3pysci.html'
with open(inputfile, 'r') as f_in:
soup = BeautifulSoup(f_in)
print(soup.find('a'))
print(soup.find('a').getText())
実行結果
<a href="https://3pysci.com/about/">About</a>
About
確かに「.getText()」でテキスト部分だけ取得できているのが分かります。
リンクのURLの取得
次にリンクのURLを取得してみます。
この場合はaタグ内の「href属性」、つまり「<a href=’リンク先’>リンクのテキスト</a>」の「href=’リンク先’」の部分を取得します。
このように特定の属性を取得するには「.get(‘属性’)」を用います。
こちらも「.find(‘a’)」だけの結果と比較してみましょう。
from bs4 import BeautifulSoup
inputfile = './3pysci.html'
with open(inputfile, 'r') as f_in:
soup = BeautifulSoup(f_in)
print(soup.find('a'))
print(soup.find('a').get('href'))
実行結果
<a href="https://3pysci.com/about/">About</a>
https://3pysci.com/about/
確かにリンクのURL情報を取得できました。
.find_all(‘a’)でのリンクのテキストとURLの取得
上記の例では「.find(‘a’)」で一番最初のaタグの情報を取得しました。
この場合は取得するリンクが一つだけなので、そのまま「.getText()」や「.get(‘href’)」を使用することができました。
しかし「.find_all(‘a’)」の場合は、”リスト形式で複数のリンクの情報”が取得されるため、直接「.getText()」や「.get(‘href’)」を使用することはできません。
なので「.find_all(‘a’)」を用いた場合は「for文」を用いて、一つずつリンクの情報を取得し、「.getText()」や「.get(‘href’)」でリンクのテキストやURLを取得します。
from bs4 import BeautifulSoup
inputfile = './3pysci.html'
with open(inputfile, 'r') as f_in:
soup = BeautifulSoup(f_in)
for link in soup.find_all('a'):
print(link.getText())
print(link.get('href'))
実行結果
About
https://3pysci.com/about/
3D Printer
https://3pysci.com/category/3dprinter/
Programming
https://3pysci.com/category/programming/
Device
https://3pysci.com/category/device/
Other
https://3pysci.com/category/other/
Privacy Policy
https://3pysci.com/privacy-policy/
Tweets by 3pysci_nori
https://github.com/Nori-3PySci
https://3pysci.com/feed/
(以下略)
こう見ていくと、リンク先のURLはあるのに、テキストがない場合が存在しています。
その理由の一つとして、テキストでリンクしているのではなく、画像でリンクしている場合もあるからです。
これでリンクのテキストとURLを取得できるようになりました。
これができるようになると例えばウェブサイトのリンクを辿っていき、そのウェブサイトの全てのページをローカルに保存したり、解析したりすることができるようになります。
ちなみに再度になりますが、くれぐれもアクセス先のサーバーに高負荷を掛けないように注意してください。
次回は記事のページを取得して、見出しタグを取得してみましょう。
ではでは今回はこんな感じで。
コメント