【问题标题】:how to access embedded pdf file in web page如何访问网页中嵌入的pdf文件
【发布时间】:2015-01-08 03:56:45
【问题描述】:

当我下载一个嵌入了 pdf 文件的 url 时,我可以访问所有页面 html,而不能访问 pdf 文件本身。我尝试过 HttpWebRequest、WebClient、HtmlAgilityPack、memorystreams 等。不确定什么路径可以工作。这是我得到的最接近的地方。任何帮助表示赞赏。

string url = "http://emaps.emapsplus.com/rdl/MadisonCoAl/MadisonCoAl.aspx?showimg=yes&pid=1701013003029000";

byte[] result;
byte[] buffer = new byte[4096];
WebRequest wr = WebRequest.Create(url);
using (WebResponse response = wr.GetResponse())
{
    using (Stream responseStream = response.GetResponseStream())
    {
        using (MemoryStream memoryStream = new MemoryStream())
        {
            int count = 0;
            do
            {
                count = responseStream.Read(buffer, 0, buffer.Length);
                memoryStream.Write(buffer, 0, count);

            } while (count != 0);

            result = memoryStream.ToArray();

            File.WriteAllBytes(@"C:\testpdf.pdf", result);
       }
    }
}

【问题讨论】:

    标签: c# pdf webpage


    【解决方案1】:

    这真的很棘手,因为它实际上不是正在下载的 pdf 文件。如果它是一个普通的 pdf,你的代码就可以工作。这是一个运行一些 javascript 的网页,这些 javascript 会发回自身以生成 pdf。

    我有您当前问题的答案,但如果您需要对许多文件执行此操作,您可能还有很长的路要走。为了让它工作,我通过Fiddler 运行页面以获取它发回给自身的帖子字符串,然后我使用 C# 模拟该过程并将结果保存为 pdf。

    这很好用,但问题是如果没有通过 Fiddler 获取帖子字符串的手动步骤,您基本上必须创建自己的 Web 浏览器来理解所有 javascript 代码并执行它们以了解字符串是如何生成的。

        using System;
        using System.Collections.Generic;
        using System.ComponentModel;
        using System.Data;
        using System.Drawing;
        using System.IO;
        using System.Linq;
        using System.Net;
        using System.Text;
        using System.Threading.Tasks;
        using System.Windows.Forms;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                string sURL = "http://emaps.emapsplus.com/rdl/MadisonCoAl/MadisonCoAl.aspx?showimg=yes&pid=1701013003029000";
                string sSource = "";
    
                byte[] buffer = new byte[4096];
                WebRequest wr = WebRequest.Create(sURL);
                using (WebResponse response = wr.GetResponse())
                {
                    using (Stream responseStream = response.GetResponseStream())
                    {
                        using (MemoryStream memoryStream = new MemoryStream())
                        {
                            int count = 0;
                            do
                            {
                                count = responseStream.Read(buffer, 0, buffer.Length);
                                memoryStream.Write(buffer, 0, count);
    
                            } while (count != 0);
    
                            sSource = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
                        }
                    }
                }
    
                if (!string.IsNullOrEmpty(sSource))
                {
                    const string sQuoteString = "\"";   // If the values are not being found it could be because the markup is being output with single quotes change this variable from "\"" to "'" in that case
                    const string sViewStateString = "__VIEWSTATE";
                    const string sEventValidationString = "__EVENTVALIDATION";
                    const string sValueString = "value=" + sQuoteString;
    
                    Int32 nIndex1 = sSource.IndexOf(sViewStateString);
                    Int32 nIndex2 = default(Int32);
                    bool bFoundValues = false;
                    string sViewState = "";
                    string sEventValidation = "";
    
                    // Look for the view state and event validation tags and grab the values
                    // Without these values we cannot continue
    
                    if (nIndex1 > -1)
                    {
                        nIndex2 = sSource.IndexOf(sValueString, nIndex1);
    
                        if (nIndex2 > -1)
                        {
                            nIndex1 = sSource.IndexOf(sQuoteString, nIndex2 + sValueString.Length);
    
                            if (nIndex1 > -1)
                            {
                                sViewState = sSource.Substring(nIndex2 + sValueString.Length, nIndex1 - nIndex2 - sValueString.Length);
                                nIndex1 = sSource.IndexOf(sEventValidationString);
    
                                if (nIndex1 > -1)
                                {
                                    nIndex2 = sSource.IndexOf(sValueString, nIndex1);
    
                                    if (nIndex2 > -1)
                                    {
                                        nIndex1 = sSource.IndexOf(sQuoteString, nIndex2 + sValueString.Length);
    
                                        if (nIndex1 > -1)
                                        {
                                            sEventValidation = sSource.Substring(nIndex2 + sValueString.Length, nIndex1 - nIndex2 - sValueString.Length);
                                            bFoundValues = true;
                                        }
                                    }
                                }
                            }
                        }
                    }
    
                    if (bFoundValues == true)
                    {
                        Int32 nTimeout = 30;
                        HttpWebRequest oRequest = HttpWebRequest.Create(new Uri(sURL).AbsoluteUri) as HttpWebRequest;
                        string sPostData = "__EVENTTARGET=btnPageLoad&__EVENTARGUMENT=&__VIEWSTATE=" + System.Web.HttpUtility.UrlEncode(sViewState) + "&__EVENTVALIDATION=" + System.Web.HttpUtility.UrlEncode(sEventValidation) + "&hdnLoaded=false&ReportViewer1%24ctl03%24ctl00=&ReportViewer1%24ctl03%24ctl01=&ReportViewer1%24ctl11=&ReportViewer1%24ctl12=standards&ReportViewer1%24AsyncWait%24HiddenCancelField=False&ReportViewer1%24ToggleParam%24store=&ReportViewer1%24ToggleParam%24collapse=false&ReportViewer1%24ctl09%24ClientClickedId=&ReportViewer1%24ctl08%24store=&ReportViewer1%24ctl08%24collapse=false&ReportViewer1%24ctl10%24VisibilityState%24ctl00=Error&ReportViewer1%24ctl10%24ScrollPosition=&ReportViewer1%24ctl10%24ReportControl%24ctl02=&ReportViewer1%24ctl10%24ReportControl%24ctl03=&ReportViewer1%24ctl10%24ReportControl%24ctl04=100";
                        byte[] oPostDataBuffer = System.Text.Encoding.ASCII.GetBytes(sPostData);
    
                        oRequest.UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10; rv:33.0) Gecko/20100101 Firefox/33.0";
                        oRequest.Timeout = nTimeout * 1000;
                        oRequest.Method = "POST";
                        oRequest.ContentType = "application/x-www-form-urlencoded";
                        oRequest.ContentLength = oPostDataBuffer.Length;
    
                        using (Stream oRequestStream = oRequest.GetRequestStream())
                        {
                            oRequestStream.Write(oPostDataBuffer, 0, oPostDataBuffer.Length);
                            oRequestStream.Close();
                        }
    
                        HttpWebResponse oResponse = oRequest.GetResponse() as HttpWebResponse;
    
                        if (oResponse.StatusCode != HttpStatusCode.OK)
                        {
                            // Error
    
                            MessageBox.Show(oResponse.StatusCode.ToString());
                        }
                        else
                        {
                            // Status is OK
    
                            byte[] oBuffer = null;
                            byte[] oFile = null;
    
                            using (BinaryReader reader = new BinaryReader(oResponse.GetResponseStream()))
                            {
                                using (MemoryStream oMemoryStream = new MemoryStream())
                                {
    
                                    oBuffer = reader.ReadBytes(1024);
    
                                    while (oBuffer.Length > 0)
                                    {
                                        oMemoryStream.Write(oBuffer, 0, oBuffer.Length);
                                        oBuffer = reader.ReadBytes(1024);
                                    }
    
                                    oFile = new byte[Convert.ToInt32(Math.Floor(Convert.ToDouble(oMemoryStream.Length)))];
                                    oMemoryStream.Position = 0;
                                    oMemoryStream.Read(oFile, 0, oFile.Length);
                                }
                            }
    
                            using (FileStream oFileStream = new FileStream("C:\\testpdf.pdf", FileMode.Create))
                            {
                                oFileStream.Write(oFile, 0, oFile.Length);
                            }
                        }
    
                        MessageBox.Show("PDF downloaded to C:\\testpdf.pdf");
                    }
                    else
                    {
                        MessageBox.Show("Cannot find the __VIEWSTATE and/or __EVENTVALIDATION variables.");
                    }
                }
                else
                {
                    MessageBox.Show("Cannot find source code for original url.");
                }
            }
        }
    }
    

    更新:

    发布数据很可能涉及某种会话,并且在您能够对其进行测试之前它已经超时。因此,这意味着我们必须变得更有创意。我承认这有点反复试验,这段代码真的是为这个网址量身定制的,可能适用于同一网站上的其他 pdf,也可能不适用。通过将我之前发布的 sPostData 字符串与我现在通过 Fiddler 代理运行网站获取的新字符串进行比较,我发现发布的众多变量中只有 2 个发生了变化。这两个变量都可以从原始 C# 代码生成的 html 源代码中获得。所以我们所做的只是对字符串进行一些操作并获取这些变量的副本,然后THEN 执行我发布的原始代码。看?我们现在一起努力!此更新后的代码现在应该每次都能正常工作,而不会出现 500 内部服务器错误消息。

    注意:因为我们发布的数据没有为网络正确编码,所以我们必须包含对 system.web 的引用才能访问 urlencode 方法。为此,您需要:

    1. 在“解决方案资源管理器”中右键单击“参考”并选择“添加参考”
    2. 点击左侧的“程序集”,在“框架”部分找到“System.Web”或使用最右侧的搜索框
    3. 勾选“System.Web”并点击“确定”

    这里是简化捕获回发数据的代码

            var postData = new System.Collections.Generic.List<string>();
            var document = new HtmlWeb().Load(url);
            foreach (var input in document.DocumentNode.SelectNodes("//input[@type='hidden']"))
            {
                var name = input.GetAttributeValue("name", "");
                name = Uri.EscapeDataString(name);
                var value = input.GetAttributeValue("value", "");
                value = Uri.EscapeDataString(value);
                if (name == "__EVENTTARGET")
                {
                    value = "btnPageLoad";
                }
    
                postData.Add(string.Format("{0}={1}", name, value));
            }
    
            // Use StringBuilder for concatenation 
            System.Text.StringBuilder sb = new System.Text.StringBuilder(postData[0]);
            for (int i = 1; i < postData.Count; i++)
            {
                sb.Append("&");
                sb.Append(postData[i]);
            }
            var postBody = sb.ToString();
    

    【讨论】:

    • 谢谢!当我运行它时,我收到以下错误:远程服务器返回错误:(500)内部服务器错误。在线 HttpWebResponse oResponse = ..... 有什么想法吗?
    • 我更新了我的答案以及一些关于为什么它之前不适合你的更新信息。希望这次能成功!
    • 太棒了,Tom,你捕获回发数据的新代码肯定比我的干净得多!此外,由于这对您有用,请通过单击答案左侧的复选标记(它将变为绿色)来接受答案,以便其他人知道您找到了问题的解决方案!
    • 我想知道如何接受答案,点击向上箭头告诉我我没有足够的积分来投票。我真的很感谢你的帮助。另外,我不想因为我简化代码而受到赞扬,这是我从别人那里得到的。
    【解决方案2】:
    string sPDFPath= "FULL PATH";
      WebClient User = new WebClient();
                    Byte[] FileBuffer = User.DownloadData(sPDFPath);
                    if (FileBuffer != null)
                    {
                        Response.ContentType = "application/pdf";
                        Response.AddHeader("content-length", FileBuffer.Length.ToString());
                        Response.BinaryWrite(FileBuffer);
                    }
    

    【讨论】:

      猜你喜欢
      • 2011-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-31
      相关资源
      最近更新 更多