powershell Invoke-WebRequest Invoke-RestMethod 乱码 encoding sharset CharacterSet

  Invoke-WebRequest和Invoke-RestMethod 爬部分网址会乱码。这个问题很久了,很多人知道。
似乎从有这两个命令的时候起,就有这个问题,至今已经4年有余了,但没人知道原因。或许是没人关注它。
  其实这个问题并不难,经我研究,找出了原因,指出了解决方案。
但我当时片面地认为,这有可能和linux的http服务器有关,但后来发现,
http://www.msn.com 是iis网站,微软官方网址,这个网址也有此乱码现象,
最后才确定了这是Invoke-WebRequest Invoke-RestMethod,这两个命令的bug。
才敢给微软提交bug,这个乱码最终的消除,还是要靠微软。

powershell 传教士 原创文章 2016-05-01 允许转载,但必须保留名字和出处,否则追究法律责任

2017-02-10更新: 参见下面的bug报告,由于我报告bug时,只给出了utf8的例子,现在ps5.1版中,发现utf8的bug已经修复了,但gb2312的还没修复。

------------【第一章 编码知识点】-----------------

编码类型,和编码值,是不可分割的一对。所有乱码的产生,是由于只知道编码值,而不知道编码类型! 如:

编码值【70 00 73 00 20 4F 59 65 EB 58】 和 编码类型【utf16】 结合起来,才知道,上述内容是【ps传教士】。

这也是微软发明,在文本中使用【bom头】的原因。

【bom头】【bom头】,有头无乱码!
【bom头】【bom头】,用的人多的牛x文本编辑器,都支持【bom头】,如vi,gedit等。

我以前遇到的某些烂人,怪人。他们很讨厌,微软使用的文本【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"

Invoke-WebRequest Invoke-RestMethod 乱码研究的更多相关文章

  1. WebRequest 获取网页乱码

    问题:在用WebRequest获取网页源码时得到的源码是乱码. 原因:1,编码不对 解决办法:设置对应编码 WebRequest request = WebRequest.Create(Url);We ...

  2. [05] 通过P/Invoke加速C#程序

    通过P/Invoke加速C#程序 任何语言都会提供FFI机制(Foreign Function Interface, 叫法不太一样), 大多数的FFI机制是和C API. C#提供了P/Invoke来 ...

  3. public static void Invoke (Action action)

    using System; using System.Security.Principal; using System.Security.Permissions; namespace Demo { c ...

  4. C#中Invoke 和 BeginInvoke 的区别

    Control.Invoke 方法 (Delegate) :在拥有此控件的基础窗口句柄的线程上执行指定的委托. Control.BeginInvoke 方法 (Delegate) :在创建控件的基础句 ...

  5. C#中的线程二(Cotrol.BeginInvoke和Control.Invoke)

    C#中的线程二(Cotrol.BeginInvoke和Control.Invoke) 原文地址:http://www.cnblogs.com/whssunboy/archive/2007/06/07/ ...

  6. 转载:C# this.Invoke()的作用与用法 理解三

    Invoke()的作用是:在应用程序的主线程上执行指定的委托.一般应用:在辅助线程中修改UI线程( 主线程 )中对象的属性时,调用this.Invoke();   在多线程编程中,我们经常要在工作线程 ...

  7. c#多线程(UI线程,控件显示更新) Invoke和BeginInvoke 区别

    如果只是直接使用子线程访问UI控件,直接看内容三,如果想深入了解从内容一看起. 一.Control.Invoke和BeginInvoke方法的区别 先上总结: Control.Invoke 方法 (D ...

  8. Dispatcher中Invoke与BeginInvoke

    [同步]Invoke Application.Current.Dispatcher.Invoke(AutoIncreaseNumber); [异步]BeginInvoke Application.Cu ...

  9. c# Invoke和BeginInvoke 区别

    原文:http://www.cnblogs.com/mashang/archive/2009/08/01/1536730.html Control.Invoke 方法 (Delegate) :在拥有此 ...

随机推荐

  1. POJ - 2339 Rock, Scissors, Paper

    初看题目时就发了个错误,我因为没有耐心看题而不了解题目本身的意思,找不到做题的突破口,即使看了一些题解,还是没有想到方法. 后来在去问安叔,安叔一语道破天机,问我有没有搞清题目的意思,我才恍然大悟,做 ...

  2. MSDTC故障排除

    “由于 Microsoft 分布式事务处理协调器出现问题,因此无法连接到配置数据库. 该事务管理器已经禁止了它对远程/网络事务的支持".   第一步: 请确保iis(运行程序的机器)和sql ...

  3. [转]Win7 64位搭建本地SVN服务器 Apache+Subversion

    转载地址:http://blog.sina.com.cn/s/blog_4f072a7001015j5z.html 一.工具下载 01.SVN 服务器Subversion:Setup-Subversi ...

  4. [课程设计]Scrum 1.4 多鱼点餐系统开发进度(点餐页面框架布置)

    Scrum 1.4 多鱼点餐系统开发进度 (点餐页面框架布置) 1.团队名称:重案组 2.团队目标:长期经营,积累客户充分准备,伺机而行 3.团队口号:矢志不渝,追求完美 4.团队选题:餐厅到店点餐系 ...

  5. 关于一个新的DOM选择器querySelector

    在传统的javascript中,提到DOM选择器,大家比较熟悉的方式是通过tag,name,id来获取,其实大家都发现如果获取比较复杂的话,用这个方法会很繁琐,这时大家应该都会想到jquery里获取一 ...

  6. 实现一个名为Person的类和它的子类Employee,Employee有两个子类Faculty 和Staff。

    (1)Person类中的属性有:姓名name(String类型),地址address(String类型), 电话号码telphone(String类型)和电子邮件地址email(String类型): ...

  7. Thinkphp单字母快捷键

    在ThinkPHP中有许多使用简便的单字母函数(即快捷方法),可以很方便开发者快速的调用,但是字母函数却不方便记忆,本文将所有的字母函数总结一下,以方便以后查找. 1.U() URL组装 支持不同UR ...

  8. python 学习笔记十四 jQuery案例详解(进阶篇)

    1.选择器和筛选器 案例1 <!DOCTYPE html> <html lang="en"> <head> <meta charset=& ...

  9. 【前端】互联网公司2014前端笔试面试题JavaScript篇(待续)

    // 网上找的题目,自己做了下 /**************************** *1. 用js实现随机选取10–100之间的10个数字,存入一个数组,并排序 *************** ...

  10. Java程序员开发参考资源

    构建 这里搜集了用来构建应用程序的工具. Apache Maven:Maven使用声明进行构建并进行依赖管理,偏向于使用约定而不是配置进行构建.Maven优于Apache Ant.后者采用了一种过程化 ...