C#爬页面总结

错误的思路是这样的:发送一个访问页面的请求过去,得到一个html页面,然后我要的数据全都在这上面。后来发现不是这样的,也猜到可能是页面加载之后还有js代码的ajax的异步加载,那么问题来了?我是不是要等到这些ajax请求结束之后,我才能拿到数据呢?我怎么判断有没有结束?我要等多久合适呢?嗯,仔细向下,还有个问题是,发送的post请求过去,又没有浏览器渲染,谁去执行这些js代码呢?

实际上是这样的:发送一个访问页面的请求过去,上面可能有我要的数据,也可能没有,如果没有,那就看看是不是要发另外的请求。

1、相关工具和技巧

1.1 Chrome浏览器

打开浏览器,按F12进入调式状态,例如打开www.cnblogs.com

  

1.2 fiddler工具

用fiddler工具查看原始的请求数据,一般都会有一定的编码格式。用Chrome工具可能看不出来编码格式。

1.3 编码解码的工具

这些就不列举了,可以找在线工具。比如下面这个的:

http://meyerweb.com/eric/tools/dencoder/

附js编码与.net编码:

1.window.escape()与HttpUtility.UrlEncodeUnicode()编码格式一样:将一个汉字编码为%uxxxx格式

不会被window.escape编码的字符有:@ _ - . * / +

2.window.encodeURIComponent()与HttpUtility.UrlEncode()编码格式一样:将一个汉字编码为%xx%xx%xx的格式

不会被window.encodeURIComponent编码的字符有:‘  (  )  *  -  . _   ! ~

不会被HttpUtility.UrlEncode编码的字符有:‘  (  )  *  -  .  _  ! 相比较而言,HttpUtility.UrlEncode比window.encodeURIComponent多一个 ~ 编码

3.不会被window.encodeURI编码的字符有: -  _  .  !  * (  )  ;  /  ?  :  @  &  =  $  ,  #,与encodeURIComponent对比,发现encodeURI不对:;/?:@&=+$,#这些用于分隔 URI 组件的标点符号进行编码

参考博文地址:

http://www.cnblogs.com/mxw09/archive/2010/04/06/1704986.html

1.4 正则表达式工具

解析返回的请求,如果是html格式的,就需要解析一下返回的结果。简单的话可以直接用正则表达式解析。反正我就是这么干的。

2 常遇到的问题

2.1 编码问题

(1)返回的信息为空

最开始,用chrome找目标请求,按照Header上的信息构造请求。结果发现怎么都不行,返回都是空。后来发现是编码问题,从chrome上看到的是编码之前的信息,从fiddler上面才能看到原始的请求。

(2)请求之后,结果跟页面上操作的不一致

我创单的时候,明明是有儿童,而且有不同性别的人创单。结果创单之后全部变成女性,全部是成人。我找了好久这个问题,仍然从chrome上一一检查参数发现没有什么问题,直到我看raw请求的时候,我才发现一个是编了码的,一个是没有编码的。一般请求都会进行编码,只是数字和字母基本上编码之后都是一样的,所以没有进行编码就访问了。只要有中文和某些特殊字符就必须要编码,否则可能会引起错误。

2.2 cookie问题

(1)报500,内部服务器错误

自己测的时候没问题,一发布测试就出问题,报500,内部服务器错误。后来才发现是cookie问题,重新登录一下就可以了。原因推测是,因为每次登录成功之后都会存redis,下次再请求,从redis中获取cookie发送请求。因为存redis中的cookie的过期时间跟网站的不一致,也就是网站本身对这个cookie已经失效了,而redis中还存有这个cookie。后来的解决办法是,一遇到这种报500就重新再登录一次。

(2)远程服务器返回错误: (600)

没有登录起,Cookie不对。

2.3代理IP的问题

报字符串格式不正确,这些报错信息有时候并不能说明什么问题,只有解决了这个问题之后,才能发现确实是这个问题。我的意思是,不一定请求过去报输入字符串格式不正确就是代理IP的问题。但是如果我一解决了代理IP的问题,这个报错就解决了。那么我推测是这就是代理IP引起的。

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Business
{
    /// <summary>
    /// HttpCallHelper
    /// </summary>
    public class HttpCallHelper
    {
        /// <summary>
        /// post
        /// </summary>
        /// <param name="param">param</param>
        /// <returns>HttpResultInfo</returns>
        public static HttpResultInfo Post(HttpRequestParams param)
        {
            HttpResultInfo res = null;
            try
            {
                param.RequestEncoding = Encoding.Default;
                byte[] bs = param.RequestEncoding.GetBytes(param.Data);
                HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(param.Url);
                req.Method = "POST";
                req.ContentType = "application/x-www-form-urlencoded";
                req.ContentLength = bs.Length;
                if (!string.IsNullOrEmpty(param.Cookie))
                {
                    req.Headers[HttpRequestHeader.Cookie] = param.Cookie;
                }
                req.Referer = param.Cookie;
                using (Stream reqStream = req.GetRequestStream())
                {
                    reqStream.Write(bs, 0, bs.Length);
                }
                string strResponse = string.Empty;
                HttpWebResponse httpResponse = (HttpWebResponse)req.GetResponse();
                using (Stream responseStream = httpResponse.GetResponseStream())
                {
                    Stream stream = responseStream;
                    StreamReader streamReader = new StreamReader(stream, param.ResponseEncoding);
                    strResponse = streamReader.ReadToEnd();
                    streamReader.Close();
                }
                string retcookie = req.GetResponse().Headers["Set-Cookie"];
                res = new HttpResultInfo()
                {
                    Cookie = retcookie,
                    StatusCode = httpResponse.StatusCode,
                    StatusDescription = httpResponse.StatusDescription,
                    Headers = httpResponse.Headers,
                    ErrorMsg = string.Empty,
                    Html = strResponse,
                    ResponseUrl = httpResponse.ResponseUri,
                };
                return res;
            }
            catch (Exception esx)
            {
                res = new HttpResultInfo()
                {
                    ErrorMsg = esx.Message.ToString(),
                };
                Console.WriteLine(esx.Message.ToString());
            }
            return res;
        }
        /// <summary>
        /// Get
        /// </summary>
        /// <param name="httpParam">httpParam</param>
        /// <param name="param">param</param>
        /// <returns>结果</returns>
        public static HttpResultInfo Get(HttpRequestParams httpParam, Dictionary<string, string> param)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var item in param)
            {
                sb.AppendFormat("{0}={1}&", item.Key, item.Value);
            }
            httpParam.Data = sb.ToString();
            return Get(httpParam);
        }
        /// <summary>
        /// Get
        /// </summary>
        /// <param name="param">param</param>
        /// <returns>结果</returns>
        public static HttpResultInfo Get(HttpRequestParams param)
        {
            HttpResultInfo ret = null;
            try
            {
                string strResult = string.Empty;
                HttpWebRequest httpRequest;
                HttpWebResponse httpResponse;
                string urlStr = param.Url;
                if (!string.IsNullOrEmpty(param.Data))
                {
                    urlStr = string.Format("{0}{1}", param.Url + "?", param.Data);
                }
                httpRequest = (HttpWebRequest)WebRequest.Create(new Uri(urlStr));
                httpRequest.Timeout = param.Timeout;
                httpRequest.Method = "Get";
                httpRequest.ContentType = param.ContentType;
                if (!string.IsNullOrEmpty(param.Cookie))
                {
                    httpRequest.Headers[HttpRequestHeader.Cookie] = param.Cookie;
                }
                //// 获取提交返回信息
                httpResponse = (HttpWebResponse)httpRequest.GetResponse();
                string returnStr = string.Empty;
                using (Stream st = httpResponse.GetResponseStream())
                {
                    returnStr = new StreamReader(st, param.ResponseEncoding).ReadToEnd();
                }
                string cookie1 = httpResponse.Headers["Set-Cookie"];
                ret = new HttpResultInfo()
                {
                    Cookie = cookie1,
                    StatusCode = httpResponse.StatusCode,
                    StatusDescription = httpResponse.StatusDescription,
                    Headers = httpResponse.Headers,
                    ErrorMsg = string.Empty,
                    Html = returnStr,
                    ResponseUrl = httpResponse.ResponseUri,
                };
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString().ToString());
                ret = new HttpResultInfo()
                {
                    Html = string.Empty,
                    ErrorMsg = ex.Message.ToString(),
                    Cookie = string.Empty,
                };
            }
            return ret;
        }
        /// <summary>
        /// GetQueryString
        /// </summary>
        /// <param name="param">param</param>
        /// <returns>结果</returns>
        public static string GetQueryString(Dictionary<string, string> param)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var item in param)
            {
                sb.AppendFormat("{0}={1}&", item.Key, item.Value);
            }
            if (sb.Length > 0)
            {
                sb = sb.Remove(sb.Length - 1, 1);
            }
            return sb.ToString();
        }
    }
    /// <summary>
    /// 请求消息
    /// </summary>
    public class HttpRequestParams
    {
        /// <summary>
        /// 请求编码
        /// </summary>
        private Encoding requestEncoding = Encoding.Default;
        /// <summary>
        /// 响应编码
        /// </summary>
        private Encoding responseEncoding = Encoding.Default;
        /// <summary>
        /// 请求超时时间(以毫秒为单位,默认180秒)
        /// </summary>
        private int timeout = 180000;
        /// <summary>
        /// 请求返回类型(默认text/html)
        /// </summary>
        private string contentType = "text/html";
        /// <summary>
        /// HttpRequestParams
        /// </summary>
        public HttpRequestParams()
        {
        }
        /// <summary>
        /// 请求地址
        /// </summary>
        public string Url
        {
            get;
            set;
        }
        /// <summary>
        /// 数据
        /// </summary>
        public string Data
        {
            get;
            set;
        }
        /// <summary>
        /// Cookie
        /// </summary>
        public string Cookie
        {
            get;
            set;
        }

        /// <summary>
        /// ContentType
        /// </summary>
        public string ContentType
        {
            get { return this.contentType; }
            set { this.contentType = value; }
        }
        /// <summary>
        /// Referer
        /// </summary>
        public string Referer
        {
            get;
            set;
        }
        /// <summary>
        /// Timeout
        /// </summary>
        public int Timeout
        {
            get { return this.timeout; }
            set { this.timeout = value; }
        }
        /// <summary>
        /// RequestEncoding
        /// </summary>
        public Encoding RequestEncoding
        {
            get { return this.requestEncoding; }
            set
            {
                if (value == null)
                {
                    throw new Exception("请求编码格式不能设置为空!");
                }
                this.requestEncoding = value;
            }
        }
        /// <summary>
        /// 返回编码
        /// </summary>
        public Encoding ResponseEncoding
        {
            get { return this.responseEncoding; }
            set
            {
                if (value == null)
                {
                    throw new Exception("响应编码格式不能设置为空!");
                }
                this.responseEncoding = value;
            }
        }
    }
    /// <summary>
    /// 返回消息
    /// </summary>
    public class HttpResultInfo
    {
        /// <summary>
        /// Html
        /// </summary>
        public string Html
        {
            get;
            set;
        }
        /// <summary>
        /// Cookie
        /// </summary>
        public string Cookie
        {
            get;
            set;
        }
        /// <summary>
        /// IsSuccess
        /// </summary>
        public HttpStatusCode StatusCode
        {
            get;
            set;
        }
        /// <summary>
        /// ErrorMsg
        /// </summary>
        public string ErrorMsg
        {
            get;
            set;
        }
        /// <summary>
        /// 状态描述
        /// </summary>
        public string StatusDescription { get; set; }
        /// <summary>
        /// 响应头
        /// </summary>
        public WebHeaderCollection Headers { get; set; }
        /// <summary>
        /// 返回Uri
        /// </summary>
        public Uri ResponseUrl { get; set; }
    }
}

4 举个简单的例子

时间: 2024-10-11 06:34:55

C#爬页面总结的相关文章

python2.0_s12_day9_协程&amp;Gevent协程

Python之路,Day9 - 异步IO\数据库\队列\缓存 本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 协程 1.协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是协程:协程是一种用户态的轻量级线程.(操作系统跟不知道它存在),那你指定协程的实现原理是什么吗? 我们来聊聊协程的实现原理: 首先我们知道多个线程在一个单核CPU上进行并发,它的操作过程是,操作系统能调动的最小单位是线程,当操作系统触发多个线

推荐系统--揭开推荐的神奇面纱

开篇 先推荐几篇关于推荐的文章,个人感觉对于入门非常有实际意义,是IBM的project师写的,例如以下: 探索推荐引擎内部的秘密,第 1 部分: 推荐引擎初探 探索推荐引擎内部的秘密,第 2 部分: 深入推荐引擎相关算法 - 协同过滤 探索推荐引擎内部的秘密,第 3 部分: 深入推荐引擎相关算法 - 聚类 推荐两本书,例如以下: 项亮:<推荐系统实践> 蒋凡:<推荐系统> 推荐系统是什么 推荐,就是把你可能喜欢的商品,推到你的面前.构建一个推荐系统,就是构建怎样把商品推到你面前的

webmagic的设计机制及原理-如何开发一个Java爬虫 转

此文章是webmagic 0.1.0版的设计手册,后续版本的入门及用户手册请看这里:https://github.com/code4craft/webmagic/blob/master/user-manual.md 之前就有网友在博客里留言,觉得webmagic的实现比较有意思,想要借此研究一下爬虫.最近终于集中精力,花了三天时间,终于写完了这篇文章.之前垂直爬虫写了一年多,webmagic框架写了一个多月,这方面倒是有一些心得,希望对读者有帮助. webmagic的目标 一般来说,一个爬虫包括

全国各省、市、县、镇、村的mysql数据库和JSON格式数据

直接开门见山了,放出下载地址先: 1.http://blog.jjonline.cn/soft/J_Position/ajing.sql.gz phpmyadmin压缩导出的mysql库,库名:ajing,内有6个表,一个表不带后缀的是原始数据,每一行是一个村,从省至村:另外5个带后缀的表是相关联的,关联id为各自的行政编码,例如湖北省id为420(其实是42,数据库中省份编码均是3位数字,最后一个0是多余的),宜昌市id为4205(然后用8个0补齐就是420500000000),当阳市(我的家

PhantomJS(转)

# coding=utf-8 import random,headers,xmlParse from bs4 import BeautifulSoup from selenium import webdriver from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.proxy import ProxyType phantomjs_

GuozhongCrawler看准网爬虫动态切换IP漫爬虫

有些关于URL去重的方面代码没有提供,须要自己去实现.主要这里提供思路 项目地址:http://git.oschina.net/woshidaniu/GuozhongCrawler/tree/master/example/changeProxyIp/ 首先爬虫入口类: public class PervadeSpider { public static void main(String[] args) { CrawTaskBuilder builder = CrawlManager.getIns

OAuth 2.0安全案例回顾

转载自:http://www.360doc.com/content/14/0311/22/834950_359713295.shtml 0x00 背景 纵观账号互通发展史,可以发现OAuth比起其它协议(如OpenID)更流行的原因是,业务双方不仅要求账号本身的认证互通(authentication:可理解为“我在双方的地盘姓甚名谁”),而是更需要双方业务流的授权打通(authorization:可理解为“我在双方的地盘上可做什么”),因为后者才能产生实际的互惠互利. 2013年将过大半,有关O

HttpUtility.UrlEncode,Server.UrlEncode 的区别

引用: 1.HttpUtility.UrlEncode,HttpUtility.UrlDecode是静态方法,而Server.UrlEncode,Server.UrlDecode是实例方法. 2.Server是HttpServerUtility类的实例,是System.Web.UI.Page的属性. 3.用HttpUtility.UrlEncode编码后的字符串和用Server.UrlEncode进行编码后的字符串对象不一样 server.urlEncode 可以根据你页面定义好的编码方式进行编

phantomjs和selenium设置proxy、headers

设置ip 方法1: service_args = [ '--proxy=%s' % ip_html, # 代理 IP:prot (eg:192.168.0.28:808) '--proxy-type=http', # 代理类型:http/https '--load-images=no', # 关闭图片加载(可选) '--disk-cache=yes', # 开启缓存(可选) '--ignore-ssl-errors=true' # 忽略https错误(可选) ] driver = webdriv