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
という行をいれておくと、わたしの場合は、エラーが発生しなくなりました。
しかし、ま、これは、認証を無視するというやり方なので、開く相手に問題がないというときに限ります。