使用C# WebClient或HttpWebRequest下载网站内容到字符串

6
我正在尝试下载一个网站的内容。但是对于某个网页,返回的字符串包含了许多乱码字符,其中包括很多�字符。
以下是我最初使用的代码。
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);
req.Method = "GET";
req.UserAgent = "Mozilla/5.0 (Windows; U; MSIE 9.0; WIndows NT 9.0; en-US))";
string source;
using (StreamReader reader = new StreamReader(req.GetResponse().GetResponseStream()))
{
    source = reader.ReadToEnd();
}
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(source);

我还尝试使用WebClient的其他实现方式,但结果仍然相同:
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
using (WebClient client = new WebClient())
using (var read = client.OpenRead(url))
{
    doc.Load(read, true);
}

从搜索结果来看,我猜测这可能与编码有关,因此我尝试了下面发布的两个解决方案,但仍无法使其正常工作。

无法下载的网站是维基百科英文版(en . wikipedia . org / wiki / United_States)上的 United_States 文章,虽然我尝试过其他维基百科文章,但没有出现此问题。

3个回答

3
我使用HtmlAgilityPack中内置的加载器,这对我很有效:
HtmlWeb web = new HtmlWeb();
HtmlDocument doc = web.Load("http://en.wikipedia.org/wiki/United_States");
string html = doc.DocumentNode.OuterHtml; // I don't see no jumbled data here

编辑:

使用标准的WebClient和您的用户代理将导致HTTP 403 - 禁止访问 - 使用以下方法可以解决问题:

using (WebClient wc = new WebClient())
{
    wc.Headers.Add("user-agent", "Mozilla/5.0 (Windows; Windows NT 5.1; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4");
    string html = wc.DownloadString("http://en.wikipedia.org/wiki/United_States");
    HtmlDocument doc = new HtmlDocument();
    doc.LoadHtml(html);
}

还可以参考这个SO线程:WebClient禁止打开维基百科页面?


我尝试了你建议的第一种方法,但是出现了以下错误: “gzip”不是受支持的编码名称。 参数名:name 在 System.Globalization.EncodingTable.internalGetCodePageFromName(String name) 在 System.Globalization.EncodingTable.GetCodePageFromName(String name)。 - Nick Collier
@Nick:对我来说运行得很好 - 确保你拥有最新版本的HtmlAgilityPack - 我从NuGet获取了我的。 - BrokenGlass
从NuGet获取HtmlAgilityPack后,仍然出现相同的错误。由NuGet安装的版本是1.4.0.0。 - Nick Collier
@Nick - 这很奇怪,两个选项在我的这里都能正常工作 - 由于我无法重现问题,所以我无法再提供更多帮助了。 - BrokenGlass

2

响应已进行gzip编码。 尝试以下方法解码流:

更新

根据BrokenGlass的评论,设置以下属性应该可以解决您的问题(对我有效):

req.Headers[HttpRequestHeader.AcceptEncoding] = "gzip, deflate";
req.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;

旧/手动解决方案:

string source;
var response = req.GetResponse();

var stream = response.GetResponseStream();
try
{
    if (response.Headers.AllKeys.Contains("Content-Encoding")
        && response.Headers["Content-Encoding"].Contains("gzip"))
    {
        stream = new System.IO.Compression.GZipStream(stream, System.IO.Compression.CompressionMode.Decompress);
    }

    using (StreamReader reader = new StreamReader(stream))
    {
        source = reader.ReadToEnd();
    }
}
finally
{
    if (stream != null)
        stream.Dispose();
}

1
你不应该手动操作,这已经内置了,即请参见此答案:https://dev59.com/DnA85IYBdhLWcg3wCe9Z - BrokenGlass
@BrokenGlass 感谢你的提示。我之前就想知道为什么我以前从未遇到过gzip编码的问题。 - Peter

1

这是我通常将页面获取为字符串的方法(使用VB,但易于转换):

req = Net.WebRequest.Create("http://www.cnn.com")
Dim resp As Net.HttpWebResponse = req.GetResponse()
sr = New IO.StreamReader(resp.GetResponseStream())
lcResults = sr.ReadToEnd.ToString

而且我没有遇到你所遇到的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接