下記ドキュメントを元に、下記スクリプトを作成しました。
https://docs.python.org/ja/3/howto/urllib2.html#wrapping-it-up
注釈 except HTTPError が 必ず 最初に来る必要があります、そうしないと except URLError も HTTPError を捕捉してしまいます。
HTTP の ステータスコードによって処理を分けたいので、
except句で、HTTPError, URLErrorを分けたいのですが、
ドキュメントの注釈に背くのが何か嫌なので、
URLError に code属性が「ある」・「なし」で
「HTTPError」・「URLError」か判定することにしました。
→質問1へ
【質問1】code属性を持っていれば必ずHTTPErrorと判定してよいですか。
【質問2】関数を再帰呼び出しし、main()のresに値を返すことはできないのですか。
【質問3】このサンプルを通して、ユーザーエージェントを簡単に偽装できるのを知ったのですが、IPを偽装したりはできないのでしょうか。
例えば、IP制限をかけているサイトに対し、IPを偽装して、リクエストを投げることはできますか。
【質問4】質問3ができない場合の回避策をできるだけ多く教えてもらえませんか。
やったことがないですが、私が思いつくのは下記2つです。
・許可されたネットワーク帯から、自宅へVPNを張る
・SSHポートフォワード?を利用して、トンネル?を掘る
(指定ドメインの80番だけトンネルを経由する?)
python
1#!/usr/bin/env python 2# encoding: utf-8 3import sys 4from urllib.request import Request, urlopen 5from urllib.error import URLError, HTTPError 6 7 8def main(): 9 url = "https://gihyo.jp/dp" 10 # url = "http://not_exist_site/" 11 res = throw_request(url) 12 html = gen_html(res) 13 save_file(html, "index.html") 14 15 16def throw_request(url, req=None, recursive=False): 17 if req is None: 18 req = Request(url) 19 try: 20 res = urlopen(req) 21 except HTTPError as e: 22 print('raise HTTPError') 23 print('StatusCode: ' + str(e.code)) 24 print('ErrorReason: ' + str(e.reason)) 25 if e.code == 403 and recursive is False: 26 print("アクセスが禁止されています") 27 print("ユーザーエージェントを偽装して再接続します") 28 req = Request(url, headers={'User-Agent': 'Mozilla/5.0'}) 29 return throw_request(url, req, True) # 再帰呼び出し 30 else: 31 print('正常なレスポンスでないため、エラー終了します') 32 sys.exit(1) 33 except URLError as e: 34 print('raise URLError') 35 print('ErrorReason: ' + str(e.reason)) 36 print('正常なレスポンスでないため、エラー終了します') 37 sys.exit(1) 38 else: 39 print("request was successful") 40 print('StatusCode: ' + str(res.getcode())) 41 return res 42 43 44def gen_html(res): 45 # f.read() の戻り値は bytes型 46 # 文字列(str型)として扱うには、文字コードを指定してデコードする 47 # res の charset でデコードして、保存する 48 encoding = res.info().get_content_charset(failobj="utf-8") 49 print("encoding: ", encoding) 50 html = res.read().decode(encoding) 51 return html 52 53 54def save_file(text, file_name): 55 with open(file_name, 'w') as f: 56 f.write(text) 57 print("save: " + file_name) 58 59 60if __name__ == "__main__": 61 main()
【補足】
質問1 につきましては、
ドキュメントの探し方が上手く慣れるようにしていかなきゃですね。
参考リンク先の情報で解決しました。ありがとうございます。
質問2 につきましては、
return throw_request(url, req)
の部分で再帰呼び出しした結果をreturnしていますが、
throw_request(url, req)
だけで、else句のreturn resより、
main()関数のresにthrow_requestのresを返したいということです。
なんとなく、変な気がしていたのですが、
else句のreturnを返す先はif句のthrow_requestに対してで、
return throw_request(url, req)
としなければ、返す先がないので、これが普通の動きなんだなと納得してきました。
質問3 につきましては、
HTTPプロトコルではできないとのことで、一旦納得しました。
きちんと理解するには、TCP/IPやOSI参照モデルを勉強する必要がありそうです。
質問4 につきましては、
別質問にして、再度掲載させていただこうと思います。

回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/03/24 08:19