我们在用Http请求的时候,某些页面是ajax加载的,所以请求过来的页面数据不完整。也就是说ajax局部加载数据的地方,我们请求不到,这时候该怎么办呢?

  WebDriver+phantomjs 这两个组合在一起使用,可以完成此任务。分别简单介绍下,WebDriver是一个前端的自动化测试框架,phantomjs是一个无界面的浏览器,基于webkit。WebDriver调用phantomjs.exe工作。下面是WebDriver提供的API,看来它能驱动各种浏览器工作。

  

  使用前准备:

在Nuget上,下载 Selenium.WebDriverSelenium.PhantomJS.WebDriver两个包,在项目中引用 WebDriver.dll,在输出目录下要有phantomjs.exe。

  我们看一个完整的例子:

  

  1. using OpenQA.Selenium;
  2. using OpenQA.Selenium.PhantomJS;
  3. using OpenQA.Selenium.Support.UI;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10.  
  11. namespace ConsoleApplication1
  12. {
  13. public interface ICrawler
  14. {
  15. event EventHandler<OnStartEventArgs> OnStart;
  16. event EventHandler<OnCompletedEvent> OnCompleted;
  17. event EventHandler<OnErrorEventArgs> OnError;
  18.  
  19. Task Start(Uri uri, Script script, Operation opreation);
  20. }
  21.  
  22. public class Operation
  23. {
  24.  
  25. public Action<PhantomJSDriver> Action;
  26.  
  27. public Func<IWebDriver, bool> Condition;
  28.  
  29. public int timeout { get; set; }
  30. }
  31.  
  32. public class Script
  33. {
  34. public string Code { set; get; }
  35.  
  36. public object[] Args { set; get; }
  37.  
  38. }
  39.  
  40. public class OnStartEventArgs
  41. {
  42. public Uri Uri { set; get; }
  43.  
  44. public OnStartEventArgs(Uri uri)
  45. {
  46. this.Uri = uri;
  47. }
  48. }
  49.  
  50. public class OnErrorEventArgs
  51. {
  52. public Uri Uri { set; get; }
  53.  
  54. public Exception Exception { set; get; }
  55.  
  56. public OnErrorEventArgs(Uri uri, Exception ex)
  57. {
  58. this.Uri = uri;
  59.  
  60. this.Exception = ex;
  61. }
  62. }
  63.  
  64. public class OnCompletedEvent
  65. {
  66. public Uri Uri { set; get; }
  67.  
  68. public int ThreadId { set; get; }
  69.  
  70. public string PageSource { get; private set; }
  71.  
  72. public long Milliseconds { get; private set; }
  73.  
  74. public PhantomJSDriver Driver { get; private set; }
  75.  
  76. public OnCompletedEvent(Uri uri, int threadId, string pageSource, long milliseconds, PhantomJSDriver driver)
  77. {
  78. this.Uri = uri;
  79. this.ThreadId = threadId;
  80. this.PageSource = pageSource;
  81. this.Milliseconds = milliseconds;
  82. this.Driver = driver;
  83. }
  84. }
  85.  
  86. public class HighCrawler : ICrawler
  87. {
  88.  
  89. public event EventHandler<OnStartEventArgs> OnStart;
  90.  
  91. public event EventHandler<OnCompletedEvent> OnCompleted;
  92.  
  93. public event EventHandler<OnErrorEventArgs> OnError;
  94.  
  95. private static PhantomJSOptions _options;
  96. private static PhantomJSDriverService _service;
  97.  
  98. static HighCrawler()
  99. {
  100. var service = PhantomJSDriverService.CreateDefaultService();
  101. service.DiskCache = true;
  102. service.IgnoreSslErrors = true;
  103. service.HideCommandPromptWindow = true;
  104. service.LoadImages = false;
  105. service.LocalToRemoteUrlAccess = true;
  106.  
  107. _service = service;
  108.  
  109. _options = new PhantomJSOptions();
  110. }
  111.  
  112. public Task Start(Uri uri, Script script, Operation operation)
  113. {
  114. return Task.Factory.StartNew(() =>
  115. {
  116. if (OnStart != null)
  117. {
  118. this.OnStart(this, new OnStartEventArgs(uri));
  119. }
  120.  
  121. var driver = new PhantomJSDriver(_service, _options);
  122. try
  123. {
  124. var watch = DateTime.Now;
  125. driver.Navigate().GoToUrl(uri.ToString());
  126.  
  127. if (script != null)
  128.  
  129. driver.ExecuteScript(script.Code, script.Args);
  130.  
  131. if (operation.Action != null) operation.Action.Invoke(driver);
  132.  
  133. var driverWait = new WebDriverWait(driver, TimeSpan.FromMilliseconds(operation.timeout)); //设置超时时间
  134.  
  135. if (operation.Condition != null) driverWait.Until(operation.Condition);
  136.  
  137. var threadId = Thread.CurrentThread.ManagedThreadId;
  138.  
  139. var milliseconds = DateTime.Now.Subtract(watch).Milliseconds;
  140.  
  141. var pageSource = driver.PageSource;
  142.  
  143. if (this.OnCompleted != null)
  144. this.OnCompleted(this, new OnCompletedEvent(uri, threadId, pageSource, milliseconds, driver));
  145.  
  146. }
  147. catch (Exception ex)
  148. {
  149. if (OnError != null)
  150. this.OnError(this, new OnErrorEventArgs(uri, ex));
  151. }
  152. finally
  153. {
  154. driver.Close();
  155. driver.Quit();
  156. }
  157. });
  158. }
  159. }
  160. }

  这是封装了一个类,方便使用,我们看如何使用:

  1. /// <summary>
  2. /// 解析网站
  3. /// </summary>
  4. /// <param name="url">待解析的网站</param>
  5. /// <param name="waitId">等待加载的元素Id:"search-main"</param>
  6. /// <param name="xpath">解析路径:"//div[@class=\"article panel article-result\"]//h5[@class=\"title\"]//a"</param>
  7. private static void TestWaitForReady(string url, string waitId, string xpath, int timeout = )
  8. {
  9.  
  10. var crawler = new HighCrawler();
  11.  
  12. crawler.OnStart += (s, e) =>
  13. {
  14.  
  15. Console.WriteLine("爬虫开始抓取地址:" + e.Uri.ToString());
  16. };
  17.  
  18. crawler.OnError += (s, e) =>
  19. {
  20. Console.WriteLine("爬虫出现错误:" + e.Uri.ToString() + ",异常信息" + e.Exception.ToString());
  21. };
  22.  
  23. crawler.OnCompleted += (s, e) =>
  24. {
  25. Console.WriteLine("接收到的源码长度:" + e.PageSource.Length);
  26.  
  27. Thread.Sleep();
  28. Console.WriteLine("爬虫结束,花费时间:" + e.Milliseconds);
  29. var items = e.Driver.FindElements(By.XPath(xpath));
  30.  
  31. foreach (var item in items)
  32. {
  33. Console.WriteLine(item.Text);
  34. }
  35. };
  36.  
  37. var operition = new Operation
  38. {
  39. Action = (x) =>
  40. {
  41.  
  42. },
  43. Condition = (x) =>
  44. {
  45. return x.FindElement(By.Id(waitId)).Displayed;
  46. },
  47. timeout = timeout
  48. };
  49.  
  50. crawler.Start(new Uri(url), null, operition);
  51.  
  52. }

  取ajax异步结果的核心原理:WebDriver把页面上的某个元素,作为标识,一旦出现此元素,表明ajax结束,这时候再返回结果,中间有个等待的过程。

  

c# http请求ajax页面的更多相关文章

  1. C# 动态创建SQL数据库(二) 在.net core web项目中生成二维码 后台Post/Get 请求接口 方式 WebForm 页面ajax 请求后台页面 方法 实现输入框小数多 自动进位展示,编辑时实际值不变 快速掌握Gif动态图实现代码 C#处理和对接HTTP接口请求

    C# 动态创建SQL数据库(二) 使用Entity Framework  创建数据库与表 前面文章有说到使用SQL语句动态创建数据库与数据表,这次直接使用Entriy Framwork 的ORM对象关 ...

  2. ajax 多个setInterval进行ajax请求的页面长时间打开会出现页面卡死问题

     多个setInterval进行ajax请求的页面长时间打开会出现页面卡死问题 浏览器的渲染(UI)线程和js线程是互斥的,在执行js耗时操作时,页面渲染会被阻塞掉.当我们执行异步ajax的时候没有问 ...

  3. Egret和Http请求 (Ajax、XMLHttpRequest、Post、Get)

    一  Http请求 二  AJax和XMLHttpRequest 三  一个Ajax例子 四 Egret中的egret.HttpRequest 五 Post和Get区别 一 Http请求 Http深入 ...

  4. Learning Scrapy笔记(六)- Scrapy处理JSON API和AJAX页面

    摘要:介绍了使用Scrapy处理JSON API和AJAX页面的方法 有时候,你会发现你要爬取的页面并不存在HTML源码,譬如,在浏览器打开http://localhost:9312/static/, ...

  5. 使用服务器端控制AJAX页面缓存

    你知道 response.setHeader("Cache-Control","no-cache"); 这条语句是干什么的吗? 这是用来防止浏览器缓存动态内容生 ...

  6. JavaScrpit中异步请求Ajax实现

    在前端页面开发的过程中,经常使用到Ajax请求,异步提交表单数据,或者异步刷新页面. 一般来说,使用Jquery中的$.ajax,$.post,$.getJSON,非常方便,但是有的时候,我们只因为需 ...

  7. 异步请求Ajax(取得json数据)

    异步请求Ajax 没有学习Ajax之前请求数据的时候都是整个页面全部刷新了一次,也就是每次请求都会重新请求所有的资源.但是在很多时候不需要页面全部刷新,仅仅是需要页面的局部数据刷新即可,此时需要发送异 ...

  8. ajax 页面无刷新

    <!-- 使用原生Ajax 和 $.ajax 实现局部刷新的过程 --><!-- 封装通用XMLHttpRequest对象 --><!DOCTYPE html>&l ...

  9. HTTP 错误 404.3 – Not Found 由于扩展配置问题而无法提供您请求的页面。如果该页面是脚本,请添加处理程序。如果应下载文件,请添加 MIME 映射。

    今天,在vs2013中新建了一个placard.json文件,当我用jq读取它的时候,去提示404,直接在浏览器访问这个文件,提示: HTTP 错误 404.3 – Not Found 由于扩展配置问 ...

随机推荐

  1. Linux系统编程---实现目录或者文件拷贝

    关于拷贝文件,前面写过一个例子:点击打开链接 ,可以看看,实现cp命令. 这次我们实现一个目录和文件的拷贝,综合点. #include <stdio.h> #include <fcn ...

  2. 程序员必须搞清的概念-equals和=和hashcode的区别

    1. 首先equals()和hashcode的介绍 equals 方法在非空对象引用上实现相等关系: * 自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true. * 对称性:对于 ...

  3. 剑指Offer--排序算法小结

    剑指Offer--排序算法小结 前言 毕业季转眼即到,工作成为毕业季的头等大事,必须得认认真真进行知识储备,迎战笔试.电面.面试. 许久未接触排序算法了.平时偶尔接触到时自己会不假思索的百度,然后就是 ...

  4. Android实现横屏以及全屏的小技巧

    分享两个安卓的实用小技巧,那就是横屏和全屏的实现. 首先是横屏的实现 首先是在清单文件中实现 <activity android:name=".MainActivity" a ...

  5. Docker教程:使用docker配置python开发环境

    http://blog.csdn.net/pipisorry/article/details/50808034 Docker的安装和配置 [Docker教程:docker的安装] [Docker教程: ...

  6. HMM:隐马尔科夫模型-维特比算法

    http://blog.csdn.net/pipisorry/article/details/50731584 目标-解决HMM的基本问题之二:给定观察序列O=O1,O2,-OT以及模型λ,如何选择一 ...

  7. ROS_Kinetic_01 在ubuntu 16.04安装ROS Kinetic 2017.01更新

    ROS_Kinetic系列学习(一),在ubuntu 16.04安装ROS Kinetic. Celebrating 9 Years of ROS! ubuntu16.04已经发布半年多了,ROS的K ...

  8. 【Unity Shaders】Reflecting Your World —— 在Unity3D中创建Cubemaps

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  9. [Django高级]理解django中的中间件机制和执行顺序

    原文来自 Understanding Django Middlewares, 这篇文章从整体上介绍了django中中间件定义,作用,和怎么样自己写中间件 –orangleliu. 注:middlewa ...

  10. UILTView经典知识点练习

    作者:韩俊强   未经允许,请勿转载! 关注博主:http://weibo.com/hanjunqiang 声明:UILTView 指:UILabel 和 UITextField 的复合 #impor ...