概述

爬虫需要抓取网站价格,与一般抓取网页区别的是抓取内容是通过AJAX加载,并且价格是通过CSS背景图片显示的。

每一个数字对应一个样式,如'p_h57_5'

  1. .p_h57_5 {
  2. background: url('http://pic.c-ctrip.com/priceblur/h57/3713de5c594648529f39d031243966dd.gif') no-repeat -590px;
  3. padding: 0 6px;
  4. font-size: 18px;
  5. }

数字对应的样式和对应的backgroundimg都是动态改变的,需要获取到每一个房型的房价。虽然后来有了其它渠道获取房价,这里记录一下用Selenium&Emgu抓取的方式。

流程:

  1. 1.Selenium访问网址
  2. 2.全屏截图
  3. 3.Selenium选择器获取房型等信息
  4. 4.Selenium选择器获取价格DOM元素,计算出价格元素的相对位置,截取价格图片,使用Emgu识别价格并且输出

实现

  1. static void Main(string[] args)
  2. {
  3. //访问网址
  4. ChromeOptions options = new ChromeOptions();
  5. options.AddArguments("--start-maximized --disable-popup-blocking");
  6. var driver = new ChromeDriver(options);
  7. driver.Navigate().GoToUrl("http://hotels.ctrip.com/hotel/992765.html");
  8. try
  9. {
  10. new WebDriverWait(driver, TimeSpan.FromSeconds(1)).Until(
  11. ExpectedConditions.ElementExists((By.ClassName("htl_room_table")))); //表示已加载完毕
  12. }
  13. finally
  14. {
  15. }
  16. //删除价格的¥符号
  17. ReadOnlyCollection<IWebElement> elementsList = driver.FindElementsByCssSelector("tr[expand]");
  18. driver.ExecuteScript(@"
  19. var arr = document.getElementsByTagName('dfn');
  20. for(var i=0;i<arr.length;i++){
  21. arr[i].style.display = 'none';
  22. }
  23. ");
  24. //全屏截图
  25. var image2 = GetEntereScreenshot(driver);
  26. image2.Save(@"Z:\111.jpg");
  27. //输出
  28. Console.WriteLine("{0,-20}{1,-20}{2,-20}", "房型", "类型", "房价");
  29. foreach (IWebElement _ in elementsList)
  30. {
  31. //var image = _.Snapshot();
  32. //image.Save(@"Z:\" + Guid.NewGuid() + ".jpg");
  33. //var str = ORC_((Bitmap)image);
  34. var roomType = "";
  35. try
  36. {
  37. roomType = _.FindElement(By.CssSelector(".room_unfold")).Text;
  38. }
  39. catch (Exception)
  40. {
  41. }
  42. var roomTypeText = regRoomType.Match(roomType);
  43. var roomTypeName = _.FindElement(By.CssSelector("span.room_type_name")).Text;
  44. //价格元素生成图片
  45. var image = _.FindElement(By.CssSelector("span.base_price")).SnapshotV2(image2);
  46. //识别
  47. var price = ORC_((Bitmap)image);
  48. Console.WriteLine("{0,-20}{1,-20}{2,-20}", roomTypeText.Value, roomTypeName, price);
  49. }
  50. Console.Read();
  51. }

图片识别方法


  1. static Program()
  2. {
  3. _ocr.SetVariable("tessedit_char_whitelist", "0123456789");
  4. }
  5. private static Tesseract _ocr = new Tesseract(@"C:\Emgu\emgucv-windows-universal-cuda 2.9.0.1922\bin\tessdata", "eng", Tesseract.OcrEngineMode.OEM_TESSERACT_CUBE_COMBINED);
  6. //传入图片进行识别
  7. public static string ORC_(Bitmap img)
  8. {
  9. //""标示OCR识别调用失败
  10. string re = "";
  11. if (img == null)
  12. return re;
  13. else
  14. {
  15. Bgr drawColor = new Bgr(Color.Blue);
  16. try
  17. {
  18. Image<Bgr, Byte> image = new Image<Bgr, byte>(img);
  19. using (Image<Gray, byte> gray = image.Convert<Gray, Byte>())
  20. {
  21. _ocr.Recognize(gray);
  22. Tesseract.Charactor[] charactors = _ocr.GetCharactors();
  23. foreach (Tesseract.Charactor c in charactors)
  24. {
  25. image.Draw(c.Region, drawColor, 1);
  26. }
  27. re = _ocr.GetText();
  28. }
  29. return re;
  30. }
  31. catch (Exception ex)
  32. {
  33. return re;
  34. }
  35. }
  36. }

Selenium内置了截图方法,只能截取浏览器中显示的内容,找到一个全屏截图的方式(内置截图+控制滚动条,图片拼接)


  1. public static Bitmap GetEntereScreenshot(IWebDriver _driver)
  2. {
  3. Bitmap stitchedImage = null;
  4. try
  5. {
  6. long totalwidth1 = (long)((IJavaScriptExecutor)_driver).ExecuteScript("return document.body.offsetWidth");//documentElement.scrollWidth");
  7. long totalHeight1 = (long)((IJavaScriptExecutor)_driver).ExecuteScript("return document.body.parentNode.scrollHeight");
  8. int totalWidth = (int)totalwidth1;
  9. int totalHeight = (int)totalHeight1;
  10. // Get the Size of the Viewport
  11. long viewportWidth1 = (long)((IJavaScriptExecutor)_driver).ExecuteScript("return document.body.clientWidth");//documentElement.scrollWidth");
  12. long viewportHeight1 = (long)((IJavaScriptExecutor)_driver).ExecuteScript("return window.innerHeight");//documentElement.scrollWidth");
  13. int viewportWidth = (int)viewportWidth1;
  14. int viewportHeight = (int)viewportHeight1;
  15. // Split the Screen in multiple Rectangles
  16. List<Rectangle> rectangles = new List<Rectangle>();
  17. // Loop until the Total Height is reached
  18. for (int i = 0; i < totalHeight; i += viewportHeight)
  19. {
  20. int newHeight = viewportHeight;
  21. // Fix if the Height of the Element is too big
  22. if (i + viewportHeight > totalHeight)
  23. {
  24. newHeight = totalHeight - i;
  25. }
  26. // Loop until the Total Width is reached
  27. for (int ii = 0; ii < totalWidth; ii += viewportWidth)
  28. {
  29. int newWidth = viewportWidth;
  30. // Fix if the Width of the Element is too big
  31. if (ii + viewportWidth > totalWidth)
  32. {
  33. newWidth = totalWidth - ii;
  34. }
  35. // Create and add the Rectangle
  36. Rectangle currRect = new Rectangle(ii, i, newWidth, newHeight);
  37. rectangles.Add(currRect);
  38. }
  39. }
  40. // Build the Image
  41. stitchedImage = new Bitmap(totalWidth, totalHeight);
  42. // Get all Screenshots and stitch them together
  43. Rectangle previous = Rectangle.Empty;
  44. foreach (var rectangle in rectangles)
  45. {
  46. // Calculate the Scrolling (if needed)
  47. if (previous != Rectangle.Empty)
  48. {
  49. int xDiff = rectangle.Right - previous.Right;
  50. int yDiff = rectangle.Bottom - previous.Bottom;
  51. // Scroll
  52. //selenium.RunScript(String.Format("window.scrollBy({0}, {1})", xDiff, yDiff));
  53. ((IJavaScriptExecutor)_driver).ExecuteScript(String.Format("window.scrollBy({0}, {1})", xDiff, yDiff));
  54. System.Threading.Thread.Sleep(200);
  55. }
  56. // Take Screenshot
  57. var screenshot = ((ITakesScreenshot)_driver).GetScreenshot();
  58. // Build an Image out of the Screenshot
  59. Image screenshotImage;
  60. using (MemoryStream memStream = new MemoryStream(screenshot.AsByteArray))
  61. {
  62. screenshotImage = Image.FromStream(memStream);
  63. }
  64. // Calculate the Source Rectangle
  65. Rectangle sourceRectangle = new Rectangle(viewportWidth - rectangle.Width, viewportHeight - rectangle.Height, rectangle.Width, rectangle.Height);
  66. // Copy the Image
  67. using (Graphics g = Graphics.FromImage(stitchedImage))
  68. {
  69. g.DrawImage(screenshotImage, rectangle, sourceRectangle, GraphicsUnit.Pixel);
  70. }
  71. // Set the Previous Rectangle
  72. previous = rectangle;
  73. }
  74. }
  75. catch (Exception ex)
  76. {
  77. // handle
  78. }
  79. return stitchedImage;
  80. }

最后的是根据传入的元素和全屏截图,获取到价格元素的图片


  1. public static Image SnapshotV2(this IWebElement element, Bitmap bitmap)
  2. {
  3. Size size = new Size(
  4. Math.Min(element.Size.Width, bitmap.Width),
  5. Math.Min(element.Size.Height, bitmap.Height));
  6. Rectangle crop = new Rectangle(element.Location, size);
  7. return bitmap.Clone(crop, bitmap.PixelFormat);
  8. }

运行效果如下

Selenium&EmguCV实现爬虫图片识别的更多相关文章

  1. 爬虫笔记之自如房屋价格图片识别(价格字段css背景图片偏移显示)

    一.前言 自如房屋详情页的价格字段用图片显示,特此破解一下以丰富一下爬虫笔记系列博文集. 二.分析 & 实现 先打开一个房屋详情页观察一下: 网页的源代码中没有直接显示价格字段,价格的显示是使 ...

  2. 【Selenium-WebDriver实战篇】selenium之使用Tess4J进行验证码图片识别内容

    ==================================================================================================== ...

  3. Selenium&Pytesseract模拟登录+验证码识别

    验证码是爬虫需要解决的问题,因为很多网站的数据是需要登录成功后才可以获取的. 验证码识别,即图片识别,很多人都有误区,觉得这是爬虫方面的知识,其实是不对的. 验证码识别涉及到的知识:人工智能,模式识别 ...

  4. Selenium&Pytesseract模拟登录+验证码识别

    验证码是爬虫需要解决的问题,因为很多网站的数据是需要登录成功后才可以获取的. 验证码识别,即图片识别,很多人都有误区,觉得这是爬虫方面的知识,其实是不对的. 验证码识别涉及到的知识:人工智能,模式识别 ...

  5. 使用Python + Selenium打造浏览器爬虫

    Selenium 是一款强大的基于浏览器的开源自动化测试工具,最初由 Jason Huggins 于 2004 年在 ThoughtWorks 发起,它提供了一套简单易用的 API,模拟浏览器的各种操 ...

  6. 1个小时!从零制作一个! AI图片识别WEB应用!

    0 前言 近些年来,所谓的人工智能也就是AI. 在媒体的炒作下,变得神乎其神,但实际上,类似于图片识别的AI,其原理只不过是数学的应用. 线性代数,概率论,微积分(著名的反向传播算法). 大家觉得这些 ...

  7. 【Machine Learning】KNN算法虹膜图片识别

    K-近邻算法虹膜图片识别实战 作者:白宁超 2017年1月3日18:26:33 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本系列文章是作者结 ...

  8. 【基于WPF+OneNote+Oracle的中文图片识别系统阶段总结】之篇一:WPF常用知识以及本项目设计总结

    篇一:WPF常用知识以及本项目设计总结:http://www.cnblogs.com/baiboy/p/wpf.html 篇二:基于OneNote难点突破和批量识别:http://www.cnblog ...

  9. 【基于WPF+OneNote+Oracle的中文图片识别系统阶段总结】之篇二:基于OneNote难点突破和批量识别

    篇一:WPF常用知识以及本项目设计总结:http://www.cnblogs.com/baiboy/p/wpf.html 篇二:基于OneNote难点突破和批量识别:http://www.cnblog ...

随机推荐

  1. Python--Cmd窗口运行Python时提示Fatal Python error: Py_Initialize: can't initialize sys standard streams LookupError: unknown encoding: cp65001

    源地址连接: http://www.tuicool.com/articles/ryuaUze 最近,我在把一个 Python 2 的视频下载工具 youku-lixian 改写成 Python 3,并 ...

  2. Github的基本配置与使用

    第一步:尝试创建SSH key ssh-keygen -t rsa -C xxxxx@gmail.com 默认在~/.ssh目录生成id_rsa与id_rsa.pub. -t代表密钥类型,常见的类型有 ...

  3. Android开源代码分享

    一.AppMsg实现自定义Toast. github下载地址 二.CircleImageView实现带边框圆形头像.                               github下载地址 ...

  4. Qt Creator 黑色主题配置

    可能是一个习惯了吧,我个人比较喜欢在黑色主题的环境下进行编程.黑色主题对眼睛稍微友好一点,看起来也不是那么low.这里给出QtCreator的黑色主题配置方案. 如果是最新的Creator3.3+的版 ...

  5. C#获取类以及类下的方法(用于Asp.Net MVC)

    在C#中,实现动态获取类和方法主要通过反射来实现,要引用System.Reflection. public ActionResult GetControllerAndAction() List< ...

  6. EHCACHE采用分布需要注意的地方

    分布式EHCACHE系统,有两种同步方式 方式1 :  RMI组播方式 这也是最常用的方式,配置简单,关键一点,各EHCACHE的节点配置都是一样的 原理:这样当缓存改变时,ehcache会向230. ...

  7. stl的优先级队列

    #include <iostream> #include <vector> #include <queue> using namespace std; class ...

  8. sysbench测试服务器性能

    sysbench目前已经有0.5的版本,不过最普遍使用的依旧是0.4.12,所以接下来我们会以0.4.12这个版本作为测试 Step1:下载安装sysbench wget http://pkgs.fe ...

  9. struts2重点——ModelDriven

    一.属性驱动 在目标 Action 类中,通过 setXxx() 方法来接收请求参数. 二.模型驱动 1.ParametersInterceptor 拦截器工作原理 ParametersInterce ...

  10. ASP.NEt MVC5--创建下拉列表

    Adding Search by Genre If you added the HttpPost version of the Index  method, delete it now. Next, ...