ホームページ >バックエンド開発 >Python チュートリアル >Python ソケットを使用して http(s) リクエスト メソッドを送信する

Python ソケットを使用して http(s) リクエスト メソッドを送信する

不言
不言オリジナル
2018-05-07 11:54:244378ブラウズ

この記事では、Python ソケットを使用して http(s) リクエストを送信することに関する関連情報を、サンプル コードを通じて詳しく紹介します。Python を必要とするすべての人にとって、学習の参考となる価値があります。一緒に見てみましょう

前書き

これは、コンピューターネットワークコースの設計を書いているときに遭遇した問題で、1日引っかかったのでまとめておきます。

実際、私は以前にリクエストを使用して Python クローラーを作成したことがありますが、コンピューター ネットワークには低レベルの実装が必要です。たまたま [この記事]1 を見て、リクエストの実装にソケットを使用していることを発見したので、それを学びました。 。

最初は、TCP 接続を確立するだけなので、難しくないと思っていました。

元の Web サイトの例は次のとおりです:

 def fetch(url):
 sock = socket.socket() # 建立socket
 sock.connect(('xkcd.com', 80)) # 远程连接
 request = 'GET {} HTTP/1.0\r\nHost: xkcd.com\r\n\r\n'.format(url) # 构建请求
 sock.send(request.encode('ascii')) # 向socket发送数据
 response = b'' 
 chunk = sock.recv(4096) # 从socket接收数据
 while chunk:
 response += chunk
 chunk = sock.recv(4096)

 # Page is now downloaded.
 links = parse_links(response)
 q.add(links)

もちろん、私はパケットをキャプチャするために fiddler を使用した他の多くの例も見てきました。最初は、私が読んだこの記事の参考資料です: https://segmentfault.com/a/1190000005126160:

Python はソケット経由で http リクエストを送信します

Baidu ホームページへのアクセスを例として取り上げます。ソケットを使用して http リクエストを送信します。

import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('www.baidu.com',80))
s.send('''GET https://www.baidu.com/ HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36
Accept-Language: zh-CN,zh;q=0.8

''')

buf=s.recv(1024)
while len(buf):
print buf
buf = s.recv(1024)

ソケットに基づく HTTP プログラミングはリクエストパラメータの制御性が優れていますが、それに応じて難易度も高くなります。上記で送信されたデータは、fiddler パケット キャプチャーから直接コピーされます。

上記に基づいて、次のコードを作成します:

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('www.baidu.com',80))
s.send('''GET / HTTP/1.1
Host: zh.lianjia.com
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: https://www.baidu.com/link?url=4J5Kx--GLdLFESJhkfRePU8Ac_0agnTcOtB-b3kfnX8VNdZ_6TPqOyJGKVXkTczg&ck=6140.3.83.296.315.287.208.155&shh=www.baidu.com&sht=94886267_hao_pg&wd=&eqid=af98b98700060b77000000065aef0524
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-CA;q=0.8,en;q=0.7
Cookie: lianjia_uuid=ce61c41c-25b0-46d6-a0a0-d57a75ee8706; UM_distinctid=1631f588055f9-0286722badd3ec-b34356b-1fa400-1631f58805657f; _ga=GA1.2.43397143.1525239286; _smt_uid=5ae94e02.558be516; _jzqx=1.1525248800.1525335927.1.jzqsr=zh%2Elianjia%2Ecom|jzqct=/ershoufang/xiangzhouqu/.-; _jzqc=1; _jzqckmp=1; _gid=GA1.2.1028411676.1525594529; select_city=440400; all-lj=c60bf575348a3bc08fb27ee73be8c666; _qzjc=1; CNZZDATA1254525948=963210960-1525238218-https%253A%252F%252Fwww.lianjia.com%252F%7C1525608956; CNZZDATA1255633284=1054798284-1525238580-https%253A%252F%252Fwww.lianjia.com%252F%7C1525608969; lianjia_ssid=c046ddb3-3e66-4809-998a-52ade335fdfc; _qzja=1.1070225156.1525239298260.1525603274282.1525613866775.1525609113492.1525613866775.0.0.0.92.9; _qzjto=29.3.0; _jzqa=1.3750161754444366000.1525239284.1525603274.1525613867.9; _jzqy=1.1525239284.1525613867.3.jzqsr=baidu.jzqsr=baidu; Hm_lvt_9152f8221cb6243a53c83b956842be8a=1525607433,1525607626,1525609113,1525613867; Hm_lpvt_9152f8221cb6243a53c83b956842be8a=1525613867; _qzjb=1.1525613866775.1.0.0.0; _jzqb=1.1.10.1525613867.1; CNZZDATA1255604082=964175865-1525237915-https%253A%252F%252Fwww.lianjia.com%252F%7C1525612833
''')

結果は常に報告されます 400(Bad Request)、この場所は長い間行き詰まっています、最終的な解決策は、1つずつ送信し、それぞれの後にrnを追加することです1つ。

 sock = socket.socket()
 sock.connect(('zh.lianjia.com', 80))
 sock.send('GET /ershoufang/ HTTP/1.1\r\n'.encode())
 sock.send('Host: zh.lianjia.com\r\n'.encode())
 sock.send('Connection: keep-alive\r\n'.encode())
 sock.send('Cache-Control: no-cache\r\n'.encode())
 sock.send('Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\n'.encode())
 sock.send('Upgrade-Insecure-Requests: 1\r\n'.encode())
 sock.send('User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36\r\n'.encode())
 sock.send('Accept-Encoding: gzip, deflate, br\r\n'.encode())
 sock.send('Cookie: lianjia_uuid=ce61c41c-25b0-46d6-a0a0-d57a75ee8706; UM_distinctid=1631f588055f9-0286722badd3ec-b34356b-1fa400-1631f58805657f; _ga=GA1.2.43397143.1525239286; _smt_uid=5ae94e02.558be516; _jzqx=1.1525248800.1525335927.1.jzqsr=zh%2Elianjia%2Ecom|jzqct=/ershoufang/xiangzhouqu/.-; _jzqc=1; _jzqy=1.1525239284.1525594526.2.jzqsr=baidu.jzqsr=baidu|jzqct=%E9%93%BE%E5%AE%B6; _jzqckmp=1; _gid=GA1.2.1028411676.1525594529; Hm_lvt_9152f8221cb6243a53c83b956842be8a=1525594526,1525594536,1525594804,1525595210; select_city=440400; all-lj=c60bf575348a3bc08fb27ee73be8c666; _qzjc=1; lianjia_ssid=99306d63-8ee5-a53c-a740-2d3021f3db2f; CNZZDATA1255604082=964175865-1525237915-https%253A%252F%252Fwww.lianjia.com%252F%7C1525602095; _jzqa=1.3750161754444366000.1525239284.1525594526.1525603274.8; CNZZDATA1254525948=963210960-1525238218-https%253A%252F%252Fwww.lianjia.com%252F%7C1525603556; CNZZDATA1255633284=1054798284-1525238580-https%253A%252F%252Fwww.lianjia.com%252F%7C1525603557; Hm_lpvt_9152f8221cb6243a53c83b956842be8a=1525606057; _jzqb=1.9.10.1525603274.1; _qzja=1.1070225156.1525239298260.1525597069547.1525603274282.1525605398368.1525606071025.0.0.0.86.8; _qzjb=1.1525603274282.9.0.0.0; _qzjto=23.2.0\r\n\r\n'.encode())

結果は常にステータス コード 301 でリダイレクトされます。長い間探していましたが、原因がわかりません。また、ブラウザのURLバーにURLを直接入力し、fiddlerを使用してパケットをキャプチャしましたが、それでもパケットをキャプチャできませんでした。ステータス301。最後に、フィドラーのコンポーザーを使用して http://zh.lianjia.com/ershoufang と入力し、301 と 200 をキャッチします。下の図に示すように、200 のアドレスは https://zh.lianjia.com/ershoufang です。

理由が分かりました。http と https の違いです。 (実はレスポンス部分のLocationは301ステータスコードで確認できるのですが、sが目立たないので気付かずに長い間止まってしまいました)

次のステップはhttps リクエストの送信方法を知るためだけに。以下はソケットを確立して接続する部分を主に変更したコードです。ポート番号は 443 であることに注意してください。参考記事はこちらです

 sock = ssl.wrap_socket(socket.socket())
 sock.connect(('zh.lianjia.com', 443))

色々な所で知識が足りていない気がしますし、学校側もアプリ層については今のところ話がありません。時間が来たらもう一度勉強してみますので、間違いや漏れがあればご指摘ください。

関連する推奨事項:

Pythonを使用してpdfをtxtに出力する例

Pythonを使用してシェルスクリプトを実行し、パラメータを動的に転送し、サブプロセスの基本的な使用方法を

以上がPython ソケットを使用して http(s) リクエスト メソッドを送信するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。