PythonでWebページ情報を取得してみる

More than 1 year has passed since last update.

学習履歴


■はじめに

Requestsと、Beautiful Soup で Web 上の情報を取ってこれるらしい。

Requests や BeautifulSoup の使い方、Web ページの情報を取得する方法などを

備忘として残しておく。


■テストURL

python 公式サイトを使って、勉強する。

※後述するが、筆者の環境だとネットワークを介した requests が使用できないので、

ローカル環境でテストした。


■requests モジュール(基本)


1. Requests モジュールのインポート

import requests

requests モジュールがない場合は、pip でインストールしておく。

$ pip install requests


2. Web 情報を取得

requests の get メソッドでページの情報が取得できる。

get_url_info = requests.get('https://www.python.org/')

print(get_url_info)
<Response [200]>

この時、以下のような 「NewConnectionError」のエラーが出た場合は通信がうまくいっていない。

requests.exceptions.ConnectionError: HTTPSConnectionPool(host='www.python.org', port=443): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x00000051AEC64CC0>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed',))

この場合は、ローカルの PC から対象の URL に ping を打ってみて、ping が通るか確認する。

ping が通らなかったら上記のエラーが出るらしい。

※ただし、エラー原因の一つでしかないので環境によって異なる

筆者の環境では、ping(ICMP)が通らない設定になっていたので、NewConnectionError が出てしまった。

設定を変えられない為、これ以降は Xampp 環境で検証を行う。

import requests

# xampp の htdocs に python 公式サイトの html ファイルを格納し、その情報を取得する
get_url_info = requests.get('http://localhost:8080/python.org.html')


3. ステータスコードの取得

ステータスコードは、簡単に取得できる。


python.code

# 存在する URL

get_url_info = requests.get('http://localhost:8080/python.org.html')
status_code = get_url_info.status_code
print(status_code) # => 200

# 存在しない URL
get_url_info = requests.get('http://localhost:8080/no_python.org.html')
status_code = get_url_info.status_code
print(status_code) # => 404


これが、javascript だと少しだけ手間がかかる。


javascript.code

// XHR インスタンスを取得

const request = new XMLHttpRequest();
// URL をオープン
request.open("GET", `http://localhost:8080/python.org.html`);
// オープンした際の挙動
request.addEventListener("load", (event) => {
console.log(event.target.status); // => 200
});
// リクエストを送信
request.send();


4. 情報の取得

web ページの情報も色々取得できる。

get_url_info = requests.post('http://localhost:8080/python.org.html')

# コンテンツタイプの取得
print(get_url_info.headers['content-type']) #=>text/html
# エンコーディング情報
print(get_url_info.encoding) #=>ISO-8859-1
# web ページの中身
print(get_url_info.text) #=> <!DOCTYPE html>...</html>

また、ヘッダ情報を見る機会も多いと思う。

headers を指定すれば、ヘッダ情報が全て見れる。

print(get_url_info.headers)

{
'Date': 'Mon, 26 Mar 2018 01:43:51 GMT',
'Server': 'Apache/2.4.29 (Win32) OpenSSL/1.0.2l PHP/7.1.11',
'Last-Modified': 'Mon, 26 Mar 2018 00:38:30 GMT',
'ETag': '"1afab-56845fe2ff151"',
'Accept-Ranges': 'bytes',
'Content-Length': '110507',
'Keep-Alive': 'timeout=5, max=100',
'Connection': 'Keep-Alive',
'Content-Type': 'text/html'
}


5. リクエストの種類

リクエストには以下の種類があるが、筆者は、get と post 以外は使ったことがない。

get_url_info = requests.get("http://localhost:8080/python.org.html")

get_url_info = requests.post("http://localhost:8080/python.org.html")
get_url_info = requests.put("http://localhost:8080/python.org.html")
get_url_info = requests.delete("http://localhost:8080/python.org.html")
get_url_info = requests.head("http://localhost:8080/python.org.html")
get_url_info = requests.options("http://localhost:8080/python.org.html")


6. リクエストにパラメータを付与

リクエストには、パラメータを付与できる。


python.code

# パラメータを設定

payload = {'key1': 'value1', 'key2': 'value2'}
# パラメータを付与した状態で、リクエストする
get_url_info = requests.get('http://localhost:8080/python.org.html', params=payload)
# URL取得
print(get_url_info.url)

http://localhost:8080/python.org.html?key1=value1&key2=value2


javascript でも同じことはできるが、個人的には python の方が分かりやすい。


javascript.code

var param = "key1=" + encodeURIComponent("value1") + "&key2=" + encodeURIComponent("value2");

var url = "http://localhost:8080/python.org.html?" + param;
// XHR インスタンスを取得
const request = new XMLHttpRequest();
// URL をオープン
request.open("GET", url);
// リクエストを送信
request.send();

# 7. URL 取得
console.log(request.responseURL)

http://localhost:8080/python.org.html?key1=value1&key2=value2



8. タイムアウト

timeout パラメータを指定して、 Requests のレスポンスの待機を止めることができるらしい。

get_url_info = requests.get('https://localhost:8080/python.org.html', timeout=0.001)


9. エラーと例外

requests を使用する上で発生するであろう、主なエラーの内容。

エラー名
内容

ConnectionError
ネットワークの問題が起こった場合(例:DNSのエラーやコネクションの切断等)

HTTPError
不正なHTTPレスポンスがあった場合

Timeout
リクエストがタイムアウトした場合

TooManyRedirects
リクエストが設定されたリダイレクトの最大数超えた場合

requests.exceptions.RequestException
全ての例外の継承元


■BeautifulSoup モジュール(基本)


1. モジュールのインポート

import bs4

BeautifulSoup モジュールがない場合は、pip でインストールしておく。

$ pip install beautifulsoup4


2. BeautifulSoup オブジェクトを作成する

BeautifulSoup を使うには、まずオブジェクトを作成する必要がある。

オブジェクトを作成するには、HTML 要素が必要なので、さっき勉強した requests でページソースを取得する。

import requests, bs4

# Web 情報取得
get_url_info = requests.get('http://localhost:8080/python.org.html')
# BeautifulSoup オブジェクトを作成
bs4Obj = bs4.BeautifulSoup(get_url_info.text, 'lxml')
print(type(bs4Obj))

<class 'bs4.BeautifulSoup'>


3. html 要素取得

BeautifulSoup オブジェクトを作成したら、select(セレクタ) メソッドを使って、

html 要素を取得できる。

# Web 情報取得

get_url_info = requests.get('http://localhost:8080/python.org.html')
# BeautifulSoup オブジェクトを作成
bs4Obj = bs4.BeautifulSoup(get_url_info.text, 'lxml')
# div タグに囲まれている全ての情報を取得
print(bs4Obj.select('div'))
# div -> nav タグに囲まれている全ての情報を取得
print(bs4Obj.select('div nav'))
# CSS の id に囲まれている全ての情報を取得
print(bs4Obj.select('#downloads'))
# CSS の Class に囲まれている全ての情報を取得
print(bs4Obj.select('.subnav menu'))
# input タグの name 属性を取得
print(bs4Obj.select('input[name]'))

戻り値はオブジェクト(リスト)になる。

print(bs4Obj.select('#downloads')[0])

<li aria-haspopup="true" class="tier-1 element-2 " id="downloads">
<a class=" selected" href="https://www.python.org/downloads/" title="">Downloads</a>
<ul aria-hidden="true" class="subnav menu" role="menu">
<li class="tier-2 element-1" role="treeitem"><a href="https://www.python.org/downloads/" title="">All releases</a></li>
<li class="tier-2 element-2" role="treeitem"><a href="https://www.python.org/downloads/source/" title="">Source code</a></li>
<li class="tier-2 element-3" role="treeitem"><a href="https://www.python.org/downloads/windows/" title="">Windows</a></li>
<li class="tier-2 element-4" role="treeitem"><a href="https://www.python.org/downloads/mac-osx/" title="">Mac OS X</a></li>
<li class="tier-2 element-5" role="treeitem"><a href="https://www.python.org/download/other/" title="">Other Platforms</a></li>
<li class="tier-2 element-6" role="treeitem"><a href="https://docs.python.org/3/license.html" title="">License</a></li>
<li class="tier-2 element-7" role="treeitem"><a href="https://www.python.org/download/alternatives" title="">Alternative Implementations</a></li>
</ul>
</li>

より詳細な情報を取得するには、以下のようにする。


例.文字列を取得

print(bs4Obj.select('#downloads')[0].get_text())

Downloads

All releases
Source code
Windows
Mac OS X
Other Platforms
License
Alternative Implementations



■応用編


1. エラーハンドリング

ステータスコードが 200 以外の場合、raise_for_status() で明示的にエラーがを発生させることができる。

import requests

get_url_info = requests.get('http://localhost:8080/python.org2.html')

try:
get_url_info.raise_for_status()
except Exception as exc:
print('問題が発生 : {}'.format(exc))

問題が発生 : 404 Client Error: Not Found for url: http://localhost:8080/python.org2.html

この例の場合は、指定した URL が存在しない(404)ので、例外を発生させることができた。

これが存在する URL(http://localhost:8080/python.org.html) の場合は、特に何も出力されない。


2.Web ページのダウンロード

Web ページをダウンロードしたくなることがあると思う。

import requests

# Web 情報取得
get_url_info = requests.get('http://localhost:8080/python.org.html')
# ステータスチェック
get_url_info.raise_for_status()
# Web 情報をダウンロード
with open('hogehoge.txt', 'wb') as file:
for chunk in get_url_info.iter_content(4029):
file.write(chunk)

特に保存先を指定してないので、python ファイルがある同じディレクトリに hogehoge.txt が生成される。

あと、エンコーディングの問題を回避する為 [wb] を必ず指定すること。


3. 検索結果表示

Requests と BeautifulSoup を使えばより高度なことができる。

今から、以下の機能を実装したスクリプトを作成する。

・コマンドラインから受け取った引数を使って Google 検索する

・検索結果を取得する

・検索したページをブラウザ上に表示させる

一番難しいのは、検索結果を指定する部分だと思うが心配はいらない。

Google で python と検索すると検索結果の一覧がページ上に表示されるが、よく見てみるとどの検索結果にも

「class= "r"」タグが付いているので、これをもとに検索結果を指定する。

search.png


search.py

#! python3

import requests, sys, webbrowser, bs4

print('Searching....')

# google 検索(sys.argv は、コマンドラインから受け取った引数)
# python search.py "test" と打ち込むと test が取得できる
get_url_info = requests.get('http://google.com/search?q=' + ''.join(sys.argv[1:]))

# ステータスチェック
get_url_info.raise_for_status()

# 検索結果をもとに BeautifulSoup オブジェクトを作成し、検索結果一覧を取得
bs4Obj = bs4.BeautifulSoup(get_url_info.text, 'html.parser')

# 検索結果に表示されるURLリンクのリストを取得する(class r の 配下の a タグ)
linkElems = bs4Obj.select('.r a')

# webbrowser で開くページの最大を 5 ページまでに指定
num = min(5, len(linkElems))

# 検索結果を基に Web ページを開く
[webbrowser.open('http://google.com' + linkElems[i].get('href')) for i in range(num)]

print('end search')


設定が終わったらコマンドラインから python スクリプトが置いてあるフォルダまで

移動して、スクリプトを起動させる。

今回は、コマンドライン上から Web ページを立ち上げたが、Google Home などの AI スピーカーを使えば、

「○○を検索して」と声をかけるだけでブラウザを検索できそう。

AI スピーカー書籍


■まとめ

・Requests 及び Beautifulsoup の基本的な使い方を学べた。

・Python は今年から触り始めたが、本当に色々なことができるなと思った。