最近学会使用cURL来快速访问网络资源,确实很好用,但在使用过程中遇到一个奇怪的问题,多方查询也没有找到现成答案,最后经摸索终于解决,特记录如下。
我们一般访问网站使用Chrome浏览器获取的cURL命令大概是这个样子:
curl 'https://www.csdn.net/?spm=1010.2135.3001.4476' \ (仅作演示举例,非实际内容)
我在 Linux 终端中运行该命令,在 spyder 里使用 subprocess.getoutput() 调用该命令,均能够按预期执行。
直到我使用某个cURL命令失败,这个失败的命令大概是这个样子:
curl $'https://www.csdn.net/?spm=\u00211010.2135.3001.4476' \ (仅作演示举例,非实际内容,是POST请求)
问题表现:在 Linux 终端中运行该命令,能够正常获取网页内容,但在 spyder 里,使用 subprocess.getoutput() 调用该命令,结果为空。
排查问题的过程:
1.通过比较此前能够正常运行的cURL命令,发现这个异常命令开头是 curl $,多了个$。于是我在正常的cURL命令中也加上$,结果能正常运行。但在异常命令中去掉$,结果不能正常运行。我查询了很多关于cURL的用法,但均未提及$的作用。一度怀疑$是不是与POST请求有关,但cURL本身有POST请求的参数,去掉$添加POST参数也不能解决问题。
2.通过深入学习subprocess,发现subprocess.run()能够捕获 stdout 和 stderr,于是换成subprocess.run(),然后在 stderr 中发现 “curl 6 could not resolve host $http”的错误提示,从提示来看,是把curl $'http 错误解析成了 curl $http ,导致运行失败。但为什么在 Linux 终端中就可以正常解析。
最后解决问题的方法:
经过长时间的摸索,我观察到 Chrome 浏览器提交POST请求时的网址与上面不完全一致,大概是这样:https://www.csdn.net/?spm=!11010.2135.3001.4476,差别是cURL中用的是\u0021,实际提交用的是!,前者是后者Unicode编码。
最后误打误碰发现了解决方案,一是要把 $ 去掉,二是要把命令中的\u0021改成对应符号!,这样调整后,在Linux 终端和 spyder 里,就都可以正常执行了。
推测原因:
在Linux 终端中,加上$符号后,就会自动把后面的字符串中的\u0021转化为!(推测Unicode编码都会进行转化),但在subprocess调用时不支持该功能,所以需要手工调整。如果大家有更加准确的解释,欢迎留言。