最近學會使用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調用時不支持該功能,所以需要手工調整。如果大家有更加準確的解釋,歡迎留言。