我正在编写一个 Python 脚本,该脚本从 weather.gov(NDFD SOAP 服务和当前观测 XML)获取数据以绘制屏幕保护程序图片。该脚本在我的普通计算机上运行,但在我的 pi zero w 上却不行,这让我相信 nftables 可能阻止了流量。
当我在 pi 上运行脚本时,它会挂起。当我通过键盘中断停止脚本时,它会给我这个回溯:
Traceback (most recent call last):
File "makeimage.py", line 121, in <module>
weather = fetch_weather(latitude, longitude, current_observations_url)
File "makeimage.py", line 78, in fetch_weather
weather_xml = minidom.parseString(urllib.request.urlopen(current_observations_url).read())
File "/usr/lib/python3.9/urllib/request.py", line 214, in urlopen
return opener.open(url, data, timeout)
File "/usr/lib/python3.9/urllib/request.py", line 517, in open
response = self._open(req, data)
File "/usr/lib/python3.9/urllib/request.py", line 534, in _open
result = self._call_chain(self.handle_open, protocol, protocol +
File "/usr/lib/python3.9/urllib/request.py", line 494, in _call_chain
result = func(*args)
File "/usr/lib/python3.9/urllib/request.py", line 1389, in https_open
return self.do_open(http.client.HTTPSConnection, req,
File "/usr/lib/python3.9/urllib/request.py", line 1346, in do_open
h.request(req.get_method(), req.selector, req.data, headers,
File "/usr/lib/python3.9/http/client.py", line 1255, in request
self._send_request(method, url, body, headers, encode_chunked)
File "/usr/lib/python3.9/http/client.py", line 1301, in _send_request
self.endheaders(body, encode_chunked=encode_chunked)
File "/usr/lib/python3.9/http/client.py", line 1250, in endheaders
self._send_output(message_body, encode_chunked=encode_chunked)
File "/usr/lib/python3.9/http/client.py", line 1010, in _send_output
self.send(msg)
File "/usr/lib/python3.9/http/client.py", line 950, in send
self.connect()
File "/usr/lib/python3.9/http/client.py", line 1417, in connect
super().connect()
File "/usr/lib/python3.9/http/client.py", line 921, in connect
self.sock = self._create_connection(
File "/usr/lib/python3.9/socket.py", line 831, in create_connection
sock.connect(sa)
如果这是防火墙问题,我该如何告诉 nftables 接受这些连接?
答案1
解决方案 1:wget
最初有效的方法是使用一种变通方法:我不通过 Python 请求获取数据,而是将wget
数据下载到我选择的文件名中,然后让我的 Python 脚本读取这些文件以获取数据。虽然这不是我想要的,但至少有效。
示例 Bash 脚本:
#! /usr/bin/bash
wget -O /var/www/forecast.xml "http://graphical.weather.gov/xml/SOAP_server/ndfdSOAPclientByDay.php?whichClient=NDFDgenByDay&lat=40.71&lon=-74.00&format=12+hourly&numDays=1&Unit=e"
python3 /var/www/makeimage.py
解决方案 2:超时
在我的 pi 上摆弄了很长时间后,我发现只有对 IPv6 地址的请求失败了,而且它总是先尝试联系这些地址。我天真地以为 python 请求有默认的超时长度……但事实并非如此。所以如果我的 pi 无法联系这些 IPv6 地址,它就会永远挂起。一旦我添加了 5 秒的超时,代码运行就会很慢,但它会按计划完成请求并生成图像。
示例python:
#with import requests
requests.get(current_observations_url, timeout=5)
#with import zeep
transport = zeep.transports.Transport(timeout=5)
soap_client = zeep.Client(wsdl=wsdl_url, transport=transport)
回避这个 pi 总是出现的网络怪异现象很烦人,但是如果我弄清楚如何让它访问 IPv6 地址,我会添加解决方案 3。