Help us understand the problem. What is going on with this article?

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

学習履歴

■はじめに

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 は今年から触り始めたが、本当に色々なことができるなと思った。

■参考

プログラミング記事

__init__
PythonとGo言語が一番好きです。どちらも仕事で使っています!
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした