前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Selenium+PhantomJS抓取数据

Selenium+PhantomJS抓取数据

作者头像
code2roc
发布2023-07-19 14:24:26
2650
发布2023-07-19 14:24:26
举报
文章被收录于专栏:IT民工的代码世界

Selenium在前面的一篇文章中说过是一种浏览器自动化测试的工具,可以利用浏览器的驱动去控制浏览器访问网站,从

而模拟浏览行为抓取数据,这种方式可以抓到更多的数据,但是效率不是很高,而且浏览器的页面必须一直开着,比较

吃资源。最近看到了一个无页面的浏览器PhantomJS,访问网站效率高,速度快,无页面全后台抓取数据,而且可以和

Selenium结合使用个性化定制网站的数据抓取,下面会详细讲一下Selenium与PhantomJS在vs2013中是如何抓取数据

的,以携程网的酒店数据为例。

首先下载Selenium的dll文件和PhantomJS资源,在我的资源中都已经上传了地址在这里~

http://download.csdn.net/detail/u013407099/9687589

然后引用Selenium中的4个dll文件,将PhantomJS中bin目录下的exe文件放到工程目录下就好了

第一步我们先初始化PhantomJS类型的Selenium中的driver来控制浏览器

var driver = new OpenQA.Selenium.PhantomJS.PhantomJSDriver("../../Phantomjs");

第二步就让这个drivier去访问我们想要访问的地址

 driver.Navigate().GoToUrl("http://hotels.ctrip.com/citylist");

第三步先在浏览器中访问这个网址,观察网页的DOM结构的规律,去将所有的城市的酒店列表地址所在的元素获取到,也就是使用css选择器来筛选DOM结构

  //锁定留个城市名模块             ReadOnlyCollection<IWebElement> elements = driver.FindElementsByClassName("des_cont");             foreach (var e in elements)             {                 //每个字母对应的城市集合                 ReadOnlyCollection<IWebElement> hreflist = e.FindElements(By.TagName("a"));                 foreach (var h in hreflist)                 {                     string cityname = h.GetAttribute("innerHTML");                     string hotellisthref = h.GetAttribute("href");                     Console.WriteLine(cityname + hotellisthref);                     City city = new City(cityname, hotellisthref);                     if (!list.Contains(city))                     {                         list.Add(city);                     }                 }             }

因为携程网的城市按字母排序的,而且切换字母时的数据就是在一个页面中,所以可以一次性把所有的城市对应的酒店介绍地址获取到,下面就可以去分别访问每个城市的酒店列表,获取每个酒店更加详细的信息 ,这里因为单线程比较慢,所以开了多线程去跑,跑多线程的时候原来想把每个城市建一个文本文件记录的,但是多线程的执行方式会是的有很多重复数据写入(坑了自己好久),所以就将数据分组,然后一组一个文本文件就好了

分组代码:

  int p = 10;             //商             int value = list.Count / 10;             //余数             int remainder = list.Count % 10;             List<List<City>> citylist = new List<List<City>>();             for (int i = 0; i < p; i++)             {                 List<City> grouplist = new List<City>();                 if (i < p - 1)                 {                     for (int j = i * value; j < value * (i + 1); j++)                     {                         grouplist.Add(list[j]);                     }                 }                 else                 {                     for (int j = i * value; j < list.Count; j++)                     {                         grouplist.Add(list[j]);                     }                 }                 string filename = "../../Data/File/Cash" + DateTime.Now.ToString("yyyyMMddHHmmss") + "_" + i + ".txt";                 File.Create(filename);                 cachelist.Add(filename);                 citylist.Add(grouplist);             }

获取每个酒店的详细页面地址

  public async Task<string> StartDetailTask(List<City> list, string CacheFileName)         {             return await Task.Run(() =>              {                  var driver = new OpenQA.Selenium.PhantomJS.PhantomJSDriver("../../Phantomjs");                  var result = string.Empty;                  try                  {                      foreach (var city in list)                      {                          driver.Navigate().GoToUrl(city.Url.ToString());                          ReadOnlyCollection<IWebElement> elements = driver.FindElementsByClassName("searchresult_name");                          foreach (var e in elements)                          {                              IWebElement w = e.FindElement(By.TagName("a"));                              string hotelname = w.GetAttribute("title");                              string allhref = w.GetAttribute("href");                              //string hotelhref = allhref.Substring(0, allhref.IndexOf('?') - 1);                              result += hotelname + "|" + allhref + "\r\n";                              Console.WriteLine(hotelname + allhref);                              StreamWriter sw = new StreamWriter(CacheFileName);                              try                              {                                  sw.Write(result);                              }                              catch (Exception)                              {                                  throw;                              }                              finally                              {                                  sw.Flush();                                  sw.Close();                              }                          }                      }                  }                  catch (Exception e)                  {                      Console.WriteLine(e.StackTrace); ;                  }                  finally                  {                      driver.Close();                      driver.Quit();                  }                  return result;              });

在访问 的过程中可以设置PhantomJS的一些属性,比如HideCommandPromptWindow属性可以控制是否弹出PhantomJS的命令框,LoadImages可以控制是否加载页面图片等

最后一步就是获取每个酒店的详细评论了,在获取房间评论的过程中因为网站需要滑动才会动态加载完毕,从而选择切换到评论,所以需要人为的控制窗口滑动

  var driver = new PhantomJSDriver(driverService);             //var driver = new ChromeDriver(@"C:\Program Files (x86)\Google\Chrome\Application");             driver.Navigate().GoToUrl("http://hotels.ctrip.com/hotel/434938.html");             //滚动到底部             Actions action = new Actions(driver);             for (int i = 0; i < 4; i++)             {                 action.MoveToElement(driver.FindElementByClassName("gns")).Perform();             }

其中“gns”是网站的底部一个元素的class,来定位网站的底部在哪里,然后控制div的店家来切换到评论窗口

   //切换到评论             driver.FindElementById("commentTab").Click();

最后来抓取详细评论

  //评论集合             ReadOnlyCollection<IWebElement> commentlist = driver.FindElementsByCssSelector("div[class^='comment_block']");             foreach (var comment in commentlist)             {                 Console.WriteLine("用户账号:" + comment.FindElement(By.ClassName("name")).FindElement(By.TagName("span")).GetAttribute("innerHTML"));                 Console.WriteLine("用户评分:" + comment.FindElement(By.ClassName("score")).FindElement(By.ClassName("n")).GetAttribute("innerHTML"));                 Console.WriteLine("入住时间:" + comment.FindElement(By.ClassName("date")).GetAttribute("innerHTML"));                 Console.WriteLine("房间类型:" + comment.FindElement(By.CssSelector("a[class^='room J_baseroom_link']")).GetAttribute("innerHTML"));                 Console.WriteLine("详细评论" + comment.FindElement(By.ClassName("J_commentDetail")).GetAttribute("innerHTML"));                 Console.WriteLine();             }

在这个过程中有一个问题没有解决,就是只能抓取5条评论,即使设置了等待时间或者等待条件也没有用,而等待条件的设置与chromedriver配合确可以完美解决,如果大家有什么好的解决方法可以提给我哦,等待条件的设置给大家看一下

  //等待加载完毕             WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5));             wait.Until<bool>((d) =>             {                 return d.FindElement(By.XPath("//*[@id='commentList']")).Displayed && d.FindElement(By.XPath("//*[@id='hotel_info_comment']/div[@id='commentList']")).Displayed                     && !d.FindElement(By.XPath("//*[@id='hotel_info_comment']/div[@id='commentList']")).Text.Contains("点评载入中");             });

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016-11-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档