powershell Invoke-WebRequest Invoke-RestMethod 亂碼 encoding sharset CharacterSet html
Invoke-WebRequest和Invoke-RestMethod 爬部分網址會亂碼。這個問題好久了,不少人知道。
彷佛從有這兩個命令的時候起,就有這個問題,至今已經4年有餘了,但沒人知道緣由。或許是沒人關注它。
其實這個問題並不難,經我研究,找出了緣由,指出瞭解決方案。
但我當時片面地認爲,這有可能和linux的http服務器有關,但後來發現,
http://www.msn.com 是iis網站,微軟官方網址,這個網址也有此亂碼現象,
最後才肯定了這是Invoke-WebRequest Invoke-RestMethod,這兩個命令的bug。
纔敢給微軟提交bug,這個亂碼最終的消除,仍是要靠微軟。linux
powershell 傳教士 原創文章 2016-05-01 容許轉載,但必須保留名字和出處,不然追究法律責任web
2017-02-10更新: 參見下面的bug報告,因爲我報告bug時,只給出了utf8的例子,如今ps5.1版中,發現utf8的bug已經修復了,但gb2312的還沒修復。shell
編碼類型,和編碼值,是不可分割的一對。全部亂碼的產生,是因爲只知道編碼值,而不知道編碼類型! 如:編程
編碼值【70 00 73 00 20 4F 59 65 EB 58】 和 編碼類型【utf16】 結合起來,才知道,上述內容是【ps傳教士】。swift
這也是微軟發明,在文本中使用【bom頭】的緣由。windows
【bom頭】【bom頭】,有頭無亂碼!
【bom頭】【bom頭】,用的人多的牛x文本編輯器,都支持【bom頭】,如vi,gedit等。api
我之前遇到的某些爛人,怪人。他們很討厭,微軟使用的文本【bom頭】,非要不用。非要用某些野路子的奇技淫巧猜想編碼。 那麼將致使:瀏覽器
1)必然有必定的猜錯概率。此乃故意給本身亂碼吃。服務器
2)某些文檔,如html,多是多種編碼組合的。或許在【<>】中就使用了單獨的charset編碼。在這種單文件多編碼狀況下,猜錯概率更多。
3)不用【bom頭】的.py文檔,必然要用 coding:之類的。它們是同一種東西,都是編碼類型的標識。
有能耐你別用【bom頭】,也別用【coding】,純猜!腳本編碼未知,解析中文註釋報錯,致使的運行不了 活該! 寧肯py腳本不能運行,也別用【bom頭】和【coding】
【bom頭】只解決了,純文本文件的亂碼。傳輸字符串的時候,也必須跟着編碼類型。一旦編碼類型丟失或未知,將產生亂碼。
(PowerShell中的)兩隻爬蟲,兩隻爬蟲,跑地快,爬網頁不賴~~~
一隻基於com版的ie,一隻基於.net中的WebRequest類,都是老奶奶,不奇怪 。。。
雖然很老了,但爬的也很快 。。。
若是你的系統是win8,或者win8以上,或者win7安裝了powershell 4.0,5.0,那麼 powershell中自帶了這樣的兩個命令,【Invoke-WebRequest】和【Invoke-RestMethod】。 第一個命令返回的是對象,第二個返回的是(整個網頁)字符串。
這兩個命令有時候會返回亂碼,很長一段時間,我認爲,是這個命令有解碼bug,但後來發現,把結果用其自帶的-outfile參數輸出到文件以後,編碼是正確的。 也就是說,實際上是咱們不知道怎麼解碼。只能用寫入磁盤的慢方法。
後來我看了博客園友【暱稱:老馬說編程】的這兩篇帖子,琢磨出來的,感謝他! 也請你們先看看這兩篇亂碼修復類文章。
http://www.cnblogs.com/swiftma/p/5420145.html
http://www.cnblogs.com/swiftma/p/5430007.html
亂碼命令版本:
全部版本的powershell。
亂碼緣由:大概90%以上都是這種問題。
網頁編碼爲utf8,可是接收到編碼後,把網頁源碼,編碼類型認錯誤了,或者說丟失了。 把utf8編碼網頁源碼,錯誤地認爲是iso8859-1編碼類型的編碼,把此utf8再次轉換成了utf8,而後給咱們呈現了。
bug重現powershell命令:
Invoke-WebRequest -Uri 'http://www.msn.com' # return chinese messy code (Invoke-WebRequest -Uri 'http://www.msn.com').BaseResponse.CharacterSet # utf8 web page,but return ISO-8859-1 Invoke-RestMethod -Uri 'http://www.msn.com'
修復辦法: 對上述編碼進行逆轉換。
bug修復powershell命令:
$utf8 = [System.Text.Encoding]::GetEncoding(65001) $iso88591 = [System.Text.Encoding]::GetEncoding(28591) #ISO 8859-1 ,Latin-1 $wrong_string = Invoke-RestMethod -Uri 'http://www.msn.com' $wrong_bytes = $utf8.GetBytes($wrong_string) $right_bytes = [System.Text.Encoding]::Convert($utf8,$iso88591,$wrong_bytes) #仔細看這裏 $right_string = $utf8.GetString($right_bytes) #仔細看這裏 write-host $right_string
gbk亂碼的解決:網頁源碼聲明瞭gb2312,瀏覽器打開正常,但powershell識別不正常的解決。
$gbk = [System.Text.Encoding]::GetEncoding(936) $utf8 = [System.Text.Encoding]::GetEncoding(65001) $iso88591 = [System.Text.Encoding]::GetEncoding(28591) #ISO 8859-1 ,Latin-1 $wrong_string = Invoke-RestMethod -Uri 'http://1212.ip138.com/ic.asp' $wrong_bytes = $utf8.GetBytes($wrong_string) $right_bytes = [System.Text.Encoding]::Convert($utf8,$iso88591,$wrong_bytes) #仔細看這裏 $right_string = $gbk.GetString($right_bytes) #仔細看這裏 write-host $right_string
歡迎去頂這個bug:
https://windowsserver.uservoice.com/forums/301869-powershell/suggestions/13685217-invoke-restmethod-and-invoke-webrequest-encoding-b
問:在這個bug沒修復以前,如何用powershell爬數據?
答:請看我這篇文章: 轉帖不會亂碼的,powershell網絡蜘蛛 http://www.cnblogs.com/piapia/p/5093201.html
wincodepage 名稱
936 gbk
54936 gb18030
GB18030使用變長編碼,有的字符是兩個字節,有的是四個字節。 在兩字節編碼中,字節表示範圍與GBK同樣。在四字節編碼中,第一個字節的值從0x81到0xFE,第二個字節的值從0x30到0x39,第三個字節的值從0x81到0xFE,第四個字節的值從0x30到0x39。 解析二進制時,如何知道是兩個字節仍是四個字節表示一個字符呢?看第二個字節的範圍,若是是0x30到0x39就是四個字節表示,由於兩個字節編碼中第二字節都比這個大。
932 japanese
949 korean
950 big5
20127 us-ascii us 7bit
1252 ISO-8859-1
28591 ISO 8859-1 又稱Latin-1
1200 utf-16
1201 utf-16 Big-Endian
12000 utf-32
12001 utf-32 Big-Endian
65001 utf-8
gb2312,gbk,gb18030,之間是兼容的。因爲網頁中都是簡單中文,因此能夠把它們看做是同一種編碼。 因此經常使用(網頁!)編碼只有,gbk,big5,utf8,ISO 8859-1,1252, 因此經常使用(文本!)編碼只有,gbk,big5,utf8,ISO 8859-1,1252,utf16le,
摘自: https://msdn.microsoft.com/zh-cn/library/system.text.encodinginfo.codepage.aspx
問:如何獲取網頁編碼?
答: 下載網頁,並查找網頁中的charset關鍵字。
powershell代碼: $網址 = 'http://www.baidu.com' $網頁編碼字串 = (Invoke-RestMethod -Uri $網址 ) -split '>' | select-string "Content-Type.*charset" #如這個百度網頁,有些網頁沒有 "`n" 換行符
問:【Invoke-WebRequest】和【Invoke-RestMethod】如何獲取網頁編碼?
答:
這個獲取方法是不可靠的,有些是錯誤的。powershell傳教士注
(Invoke-WebRequest -Uri www.baidu.com ).BaseResponse.CharacterSet #返回 utf-8 (Invoke-WebRequest -Uri news.qq.com ).BaseResponse.CharacterSet #返回 GB2312 (Invoke-WebRequest -Uri http://www.nmc.cn ).Headers.'content-type' #text/html (Invoke-WebRequest -Uri http://www.nmc.cn ).BaseResponse.CharacterSet #ISO-8859-1 (Invoke-WebRequest -Uri http://www.scielo.br).BaseResponse.CharacterSet
問:如何給網頁傳值?
答:
$text = '要發送的內容' $postData = [System.Text.Encoding]::UTF8.GetBytes($text) Invoke-WebRequest -Uri 'http://www.mydomain.com/' -Method Post -Body $postData -ContentType "text/plain; charset=utf-8"