.NET、Javaで10年ほど開発の仕事をした後に、
企業と従業員の成長をもっと大切にする会社を増やしたい!と会社を飛び出した者です。
本を頭から進めてきてますが、10章のデバッグは飛ばしました。
今日はWEBスクレイピングです。
VBAでは何度かやってますが、Javaではやったことないので比較して感想は言えないですね。
使用するモジュールごとに簡単にまとめていきます。
今回からサードパーティ製のモジュールも使っていきますよ。
サードパーティ製モジュールダウンロード
コマンドプロンプトでpip使っていきます。次のコマンド打てばOK
1 |
pip install <モジュール> |
webbrowser
標準モジュールなんで、pip使わずとも使えます。
標準ブラウザを起動して、指定URLを表示させるくらいしかできない?
URLが存在するとか、描画完了を待たないのでいくつかのページを自動的に開きたい場合は使えそうです。
ブラウザが表示サポートしているファイルパス(PDFファイルなど)を渡すとブラウザで開いてくれます。
1 2 3 |
import webbrowser webbrowser.open('https://www.google.com') |
Requests
ここからサードパーティ製モジュールです。
初めて使う場合はインストール必須。
1 |
pip install requests |
1 2 3 4 5 |
import requests res = requests.get('https://www.google.com') print('リクエスト結果:' + str(res.status_code)) print(res.text) |
httpリクエストを受け付けていないドメインにget投げたりすると、
get関数の部分で例外発生するので、処理内容によってはここで例外処理も必要ですね。
サンプルコードでは変数resに結果が格納されているので、それを使って後処理します。
htmlソースは全てres.textに格納。
google chromeでページのソースを表示した時と同じ内容が入ってきてるので、単体で使う場合はファイルダウンロードが良いの?
Beautiful Soup
サードパーティ製モジュールです。
1 |
pip install beautifulsoup4 |
webbrowserとrequestsはページを要求する側ですが、
これはその結果(htmlソース)を解析するモジュール。
ページ(htmlソース)の中に特定の要素があるか?とか
要素の中のデータ収集していきます。
これも単体で使う事は少なそうですね。
1 2 3 4 |
import bs4 example_file = open('example.html') bs4soup = bs4.BeautifulSoup(example_file) |
bs4.BeautifulSoupにhtmlファイルか、htmlソース(requestsのresponse.text)を渡せばBeautifulSoupオブジェクトができるので、
CSSセレクタなどで、要素取り出して各値にアクセスしていきます。
1 2 3 4 5 6 |
#全ての<a>タグを取得 elements = bs4soup.select('a') for element in elements: #属性(id)の値を取得して表示 print(element.get('id')) |
Google検索結果のリンクを収集
これはVBAで作ってみたのをPythonのRequestsとBeautifulSoupに置き換えです。
コマンド引数でも、後入力でも検索ワードを受け取り、
Google検索をリクエストする。
1 2 3 4 5 6 7 8 9 10 11 |
#! Python3 # sample.py import bs4, requests, system, webbrowser if len(sys.argv) > 1: keyword = sys.argv[1] else: keyword = input('input keyword...') res = requests.get('https://www.google.com/search?q=' + keyword) res.raise_for_status() |
リクエスト結果をBeautifulSoupオブジェクトへ変換して、
検索結果のリンク要素を取り出す。
1 2 |
bs4_soup = bs4.BeautifulSoup(res.content,'html.parser') anchor_elems = bs4_soup.select('.r a') |
リンクタイトルとリンクURLを取り出して表示
(ブラウザのページを開く)
1 2 3 4 5 6 |
for elem in anchor_elems: title = elem.getText() link = elem.get('href').replace('/url?q=', '').split('&sa=U&ved')[0] print(title + ' ' + link) #ブラウザを開く場合はコメント解除 #webbrowser.open(link) |
anchorのhrefを取得だけだと、冒頭に”/url?q=”というゴミが入り、更に途中にも別のパラメータが入ったので、
replaceとsplitでちょっと強引にリンク先URLだけにしてます。
日本語を含むURLで挙動がおかしい
検索結果のURLに日本語が含まれていない場合は、上記でOKでした。
が、URLに日本語を含むサイトをwebbrowserでopenさせようとしたら、
無効な文字を含むんでいます。と・・・
例えばWikipediaのページでブラウザで表示するとURL表示がこうなるページ。
「https://ja.wikipedia.org/wiki/あいうえお」
収集したURLがこうなってました
「https://ja.wikipedia.org/wiki/%25E3%2581%2582%25E3%2581%2584%25E3%2581%2586%25E3%2581%2588%25E3%2581%258A」
なんか長すぎない?
2回エンコードされている?
対応として、収集したURLのエンコードされた文字列をデコードして、
openするURLした所正しいページを開くようになりました。
どうやら、URLの中の日本語部分が2回エンコードされている様子。
「あいうえお」
↓URLエンコード
「%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A」
↓更にURLエンコード
「%25E3%2581%2582%25E3%2581%2584%25E3%2581%2586%25E3%2581%2588%25E3%2581%258A」
収集したURLと一致しました!
webbrowser.open()ではURLを1回デコードしているけど、
よくわからない文字列になってしまうので正しいページが表示されなくなっていました。
URLにエンコードされた部分があった場合は、そこを1回デコードしてURLを組み立て。
1 2 3 4 5 |
encode_index = link.find('%') if encode_index > 0: param = link[encode_index:] param = urllib.parse.unquote(param) link = link[0:encode_index] + param |
コメント