1-2
Pythonでスクレイピング(HTMLやXMLから情報を抽出)をするときの便利なライブラリにBeautifulSoup(綺麗なスープ!!!!???????!?!?!!??!!??!?!)がある。
※「データ抽出」のみの機能であり、ダウンロードの機能はないので、そこはurllibを使って自分で組む必要がある。
BeautifulSoup使い方その1(HTMLの文字列からデータを取得する)
ア:HTMLから情報を抽出(基本ver)
from bs4 import BeautifulSoup #解析したいHTMLの例 html = ''' <html><body> <h1>スクレイピングとは?</h1> <p>Webページを解析すること。</p> <p>任意の情報を抽出すること。</p> </body><html> ''' #HTMLの解析。第一引数にhtml(上の文章)、第二引数に文を解析するもの(パーサー)を入れる。今回はHTMLなのでhtml.parserを入れる soup = BeautifulSoup(html, 'html.parser') #HTMLと同じようにアクセスできる。例えば、h1は<html><body><h1>にある要素なので、それをドットでつないでアクセス h1 = soup.html.body.h1 p1 = soup.html.body.p p2 = p1.next_sibling.next_sibling #pタグは二つあり、後ろの方(「任意の情報を抽出すること。」の一文)にアクセスするには「p1の次」というアクセスの仕方をする。1つ目のnext_siblingはp1直後の改行、スペースを得る。 #出力 print('h1 = ' + h1.string) print('p = ' + p1.string) print('p = ' + p2.string)
ア':find()を使って、任意のidで探す(アのように、ルートから一つずつ辿るのは面倒なので)
from bs4 import BeautifulSoup html = ''' <html><body> <h1 id = 'title'>スクレイピングとは?</h1> <p id = 'body'>ページから任意のデータを抽出すること。</p> </body></html> ''' soup = BeautifulSoup(html, 'html.parser') title = soup.find(id = 'title') body = soup.find(id = 'body') print('#title=' + title.string) print('#body=' + body.string)
ア'':find_all()を使って複数要素を取得
from bs4 import BeautifulSoup #ulは順序のないリストを指す。a hrefはリンクを指すタグ。 html = ''' <html><body> <ul> <li><a href='http://uta.pw'>uta</a></li> <li><a href='http://oto.chu.jp'>oto</a></li> </ul> </body></html> ''' soup = BeautifulSoup(html, 'html.parser') #flnd_all()メソッドでaタグ(リンク)を全て取り出す links = soup.find_all('a') #リンク一覧を表示。href属性(リンクの部分)はattrs['href']のようなattrsプロパティで取得できる。textはstringから。 for a in links: href = a.attrs['href'] text = a.string print(text, '>', href)
BeautifulSoup使い方その2(urlopen()を使ってリンク先を持ってくる)
郵便番号検索APIにアクセスして、郵便番号の「県」「市」「町」を表示させる
from bs4 import BeautifulSoup import urllib.request as req #ここの数字の部分を変えれば任意の住所が検索できる url = 'http://api.aoikujira.com/zip/xml/1500042' #urlopenでデータ取得 res = req.urlopen(url) #データ解析(なんでXML読んでんのにパーサーがhtmlなのかは分からん) soup = BeautifulSoup(res, 'html.parser') #soup(XMLとして読んだ情報)の中から、find('ken')なら<ken>東京都</ken>となっているところを文字列として取り出す ken = soup.find('ken').string shi = soup.find('shi').string cho = soup.find('cho').string print(ken,shi,cho)
BeautifulSoupの使い方その3(CSSセレクタを使う)
CSS(Cascading Style Sheets:要はHTMLみたいなのでできた文章のレイアウトを指定するヤツ)を指定して、その要素を抽出するみたいなことを行う。
from bs4 import BeautifulSoup #divはその部分をくくってひとまとめのグループにする意味。ulは順序のないリスト。 html = ''' <html><body> <div id='meigen'> <h1>トルストイの名言</h1> <ul class='items'> <li>汝の心に教えよ、心に学ぶな。</li> <li>謙虚な人は誰からも好かれる。</li> <li>強い人々は、いつも気取らない。</li> </ul> </div> </body></html> ''' soup = BeautifulSoup(html, 'html.parser') #select_one(セレクタ)でCSSセレクタで要素を一つ取り出す。div#meigen > h1はHTMLの木構造をイメージ。「meigenっていう名前のついたdivタグの中にあるh1」みたいな h1 = soup.select_one('div#meigen > h1').string print('h1 =', h1) #リスト部分を取得。select(セレクタ)でCSSセレクタで複数要素取り出し、リスト型で返す。 li_list = soup.select('div#meigen > ul.items > li') for li in li_list: print('li =', li.string)
まとめ
Yahoo!ファイナンスの為替情報(USD/JPY)をスクレイピングしてみる。
from bs4 import BeautifulSoup import urllib.request as req url = 'https://stocks.finance.yahoo.co.jp/stocks/detail/?code=USDJPY=X' res = req.urlopen(url) soup = BeautifulSoup(res, 'html.parser') #なぜかわからないがここのstoksprice、stocks(株式)じゃなくてstoksになってる むずむずするわね price = soup.select_one('.stoksPrice').string print('usd/jpy=', price)
実行結果(+soupの中身)はこんな感じ。