Invoke-WebRequest Invoke-RestMethod 亂碼研究

 

  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"
相關文章
相關標籤/搜索