Python - ウェブスクレイピング - request - 基本

 クラウディア
1. 概要
2. 取得してみる
3. 手直し
4. CERTIFICATE_VERIFY_FAILED

1. 概要

 早速、使ってみます。

import requests
 でいきなり

Traceback (most recent call last):
  File "./linkcheck.py", line 5, in <module>
    import request
ModuleNotFoundError: No module named 'request'
 というエラーが出るので、つまり「request」がインストールされていないのだな・・・と。  「pip」でインストールする方法はあるのでしょうが、できれば「ports」でインストールしたい。

/usr/ports/security/py-requests-credssp
 っていうのがあるのですがこれをインストールしたら「request」がインストールされるのでしょうか?  と思ったら

cd /usr/ports/security/py-requests-credssp
make
Makefile:22: *** 分離記号を欠いています.  中止.
 ですって。  仕方ない。pip でインストールしてみます。

$ pip install request
  Downloading https://files.pythonhosted.org/packages/b8/13/b88a65f14470f3e17d72a1a930f173b36717c211685dbbadfc2e5ba21303/request-1.0.2.tar.gz

・・・略・・・

  Running setup.py install for request ... done
Successfully installed get-1.0.3 post-1.0.2 public-1.0.3 query-string-1.0.2 request-1.0.2
You are using pip version 9.0.3, however version 10.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
 最後の方のメッセージが気になりますがとりあえず置いておきます。

2. 取得してみる

 参考サイトを真似て、ソースを書いて取得してみました。

#!/usr/local/bin/python3
# -*- coding: utf-8 -*-

import sys
import requests

argv = sys.argv
argc = len(argv)

if (argc < 2):
    print("チェック対象の URL が指定されていません")
    exit()

url = sys.argv[1];

r = requests.get(url)
print(r.content)
 linkcheck.py というソース名で実行権限をつけて実行してみました。

./linkcheck.py https://freebsd.sing.ne.jp/lang/python/
 これは、https のチェックでエラーになるようです。  エラーメッセージのみ掲載するとこんな感じです。

  File "/usr/local/lib/python3.6/site-packages/requests/adapters.py", line 504, in send
    raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='freebsd.sing.ne.jp', port=443): Max retries exceeded with url: /lang/python/ (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)",),))
 http であればエラーとはならず、取得できました。

./linkcheck.py http://freebsd.sing.ne.jp/lang/python/
 日本語はエンコードした形式で表示されるようです。

3. 手直し

 上記の設定であれこれやってみましたが・・・。

from urllib import request
from urllib.error import URLError, HTTPError
from urllib.parse import urlparse
from urllib.parse import urljoin

・・・	略	・・・

requestLink = request.Request(url)

html = request.urlopen(requestLink, timeout=10)
 てな感じで「Request」「urlopen」を組み合わせて、タイムアウト秒数を設定しないと、タイムアウトがやたら発生します。  さらに、外部リンクでは「400 bad request」がやたら発生します。  「UserAgent」や「method」等がないと「DOS」攻撃と勘違いされるようです。  で、「Nature Remo Cloud APIで400 Bad Requestが出る件 - Qiita」を参考にさせていただいて・・・。

from urllib import request
from urllib.error import URLError, HTTPError
from urllib.parse import urlparse
from urllib.parse import urljoin

・・・	略	・・・

self.headers = { 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.108 Safari/537.36' }
self.data = b'button=on'
self.method = 'POST'

・・・	略	・・・

requestLink = request.Request(url, data=self.data, headers=self.headers, method=self.method)

html = request.urlopen(requestLink, timeout=10)
 と書き換えましたらば、エラーがぐっと減りました。  (減りすぎて、逆にエラーにすべきところをエラーにしきれてないかもしれない・・・)

4. CERTIFICATE_VERIFY_FAILED

 前項までで、「http://」はアクセスできるようになりましたが。  「https://」へアクセスすると

ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1134)
 てな、エラーになります。  これは、「SSL」の認証の問題です。  回避方法は、いくつかあるようですが。  一番簡単な、回避方法をひとつ。  「Request」を行う前に

import ssl

ssl._create_default_https_context = ssl._create_unverified_context
 という行をいれておくと、わたしの場合は、エラーが発生しなくなりました。  しかし、ま、これは、認証を無視するというやり方なので、開く相手に問題がないというときに限ります。
earthcar(アースカー)
ハイスピードプラン
5G CONNECT