使用 socket 和 ssl 手动获取网页
Posted
技术标签:
【中文标题】使用 socket 和 ssl 手动获取网页【英文标题】:Fetch web page manually with socket and ssl 【发布时间】:2022-01-19 13:09:47 【问题描述】:我正在尝试使用低级 socket
和 ssl
库来获取网页。
我当前的代码基于ssl library's official documentation 中的第一个示例。创建 SSL 套接字后,我发送一个手写的GET
请求并读取响应:
import socket
import ssl
hostname = 'www.python.org'
context = ssl.create_default_context()
with socket.create_connection((hostname, 443)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
request = f'GET / HTTP/1.1\r\nHost: hostname\r\nConnection: close\r\n\r\n'
ssock.sendall(request.encode())
response = b''
while True:
chunk = ssock.recv(4096)
if not chunk:
break
response += chunk
print(response.decode('utf-8'))
www.python.org 工作正常,但大多数时候当我尝试从***的List of most visited websites 获取前 10 个网页之一时出现问题。由于返回的 HTTP 状态代码通常是 302 Found
告诉我类似
HTTP/1.1 302 Found
Location: https://www.facebook.com/unsupportedbrowser
我尝试在GET
请求中将www.facebook.com
替换为https://www.facebook.com
:
request = f'GET / HTTP/1.1\r\nHost: https://hostname\r\nConnection: close\r\n\r\n'
现在,我得到不同的状态代码,例如:
400 Bad Request
500 Internal Server Error
我想要实现的几乎就是以下代码所做的。
import requests
url = 'https://python.org'
response = requests.get(url)
print(response.text)
注意事项:
我不一定需要安全连接,但没有ssl
,我的成功率就更低了。
我不想在生产中使用它。
【问题讨论】:
...但大多数时候都会出现问题... 没有任何问题,只是 HTTP 协议比您准备实现的更复杂。 ssl 文档中的示例只是一个演示。它们绝不会伪装成功能齐全的 HTTP 客户端。 【参考方案1】:Facebook 的问题显然是它需要一个 User-Agent 标头,浏览器通常在请求中包含该标头。由于您不是浏览器,因此您至少需要通过包含它来假装您是浏览器。
如果您希望仅使用套接字提交请求,但获得与浏览器相同类型的响应,那么最好的选择可能是首先通过浏览器提交请求并查看发送的标头并由您感兴趣的每个站点返回(为此使用浏览器自己的开发工具)。然后,只需将任何和所有看起来像是网站预期的标题添加到您自己的请求中。
【讨论】:
以上是关于使用 socket 和 ssl 手动获取网页的主要内容,如果未能解决你的问题,请参考以下文章
Flutter webview:ssl_client_socket_impl 和 Uncaught SecurityError 错误