主要的核心思想是取cookie然后发查询请求,不需要浏览器做代理(转)
需求是催生项目和推进项目的不竭动力。
背景:
最近,因为媳妇要做个B超检查,想着去大医院查查应该更放心,所以就把目标瞄准在A医院。早已耳闻A院一号难求万人空巷,所以把所有能接触到的机会都看了一遍,线下听传闻说早上徐亚5点左右去排队还未必能排上,线上主要有以下两个来源:
1.支付宝
在支付宝的城市服务中,定位到指定城市,是能够看一些医院提供了预约挂号接口的,显然A医院当之无愧也在其中。
简便易用的支付宝用户体验,即便是第一次来也好像是经常使用这项服务般熟练。找到A院,搜索妇产科,在list中有若干医生,有的标注无号源,有的标注可预约,大抵如下:
于是满怀激动的点击"可预约",可是弹出来的却不是我想要的结果--!
后来听到诸如凌晨12点会有号放出,但是最终也是收到同样冷冰冰的弹出窗口。对于用此招挂上号的我深表佩服,只是抛开这个不说,感觉A院在支付宝这块的投入太低,UI设计也很呆板,最主要的是抢不到号。
2.百度医生
相对来说,百度医生要比上面做的实诚的多,有就是有,没有就是没有。不管是PC端还是app端,用户界面更加柔和smooth。
于是我把希望寄托在这里,但是A院的号难抢,这是事实。而百度医生我觉得还有一块空白可以实现的就是监控机制,好比12306可以刷票一样,添加这个模块,相信app的下载量和使用量会提高一个"当量"。
很显然,这个功能,还没有,那我只能自己动手了~~~
我的思路
1. 百度从医院拿数据,那我就从百度拿数据。我能够监控百度医生放出来的消息,就基本与医院同步了;
2. 我要使用的是百度医生,但是这个需要登录,而且登录方式只有使用手机号+验证码的方式。这个方法可行,但是需要中间sleep以输入验证码,或者是调用短信接口,显然这两个都不是一个很好的途径,时间金钱成本高,用户体验差;
3. 于是我想到,可以先登录百度账户(用户名+密码),然后利用这个账户进入百度医生,就免去了短信验证这个环节。
码前预热
1. 框架选择
毫无疑问,我们采用selenium,一款web测试应用工具,模拟我在浏览器上的操作。可以基于IE、FF、Chrome等等浏览器,实现启动关闭浏览器/页面,在页面上点击、定位元素等相应操作。关于selenium webdriver的背景知识就不做介绍,一篇博文显然难以阐述清楚。
2. 工具使用
在使用selenium过程中,页面元素的定位是个核心问题。我们可以使用By类下面的By.name,By.id,By.linkText分别获取获取name属性,id属性,超链接文本。这些方式的定位我们直接可以在DOM结构中看出来,其中比较复杂的是xpath,需要根据DOM结构实现定位,这时候我们需要一个工具可以实时的测试我们的xpath表达式是否能够正确定位到指定元素。
a.在Firefox浏览器中,我们可以安装插件FirePath
这里我们通过字符串".//*[@id='su']"就能够定位到"百度一下"这个按钮
b.在chrome里面,我们可以下载插件XPath Helper,有关它的用户,请参看
http://www.chromein.com/crx_11654.html
思路有了,工具齐了,那就开始着手做吧
1.启动chrome浏览器
需要下载chrome的驱动
1
2
|
System.setProperty ( "webdriver.chrome.driver" , "C:\\Users\\Administrator\\Downloads\\chromedriver_win32\\chromedriver.exe" ); WebDriver driver = new ChromeDriver(); |
2.定位元素执行动作
如定位百度页面的登录按钮,并执行点击操作
1
2
|
WebElement loginLink = driver.findElement(By.xpath( ".//*[@id='u1']/a[7]" )); loginLink.click(); |
3.等待页面加载完成
有时候在driver.get()到某个页面时,如果页面没有加载完成,这时候去定位元素容易抛出异常,所以需要加入等待页面加载完成的功能。这里将其封装在一个函数中:
1
2
3
4
5
6
7
8
9
10
|
public static void waitForLoad(WebDriver driver) { ExpectedCondition<Boolean> pageLoad= new ExpectedCondition<Boolean>() { public Boolean apply(WebDriver driver) { return ((JavascriptExecutor)driver).executeScript( "return document.readyState" ).equals( "complete" ); } }; WebDriverWait wait = new WebDriverWait(driver, 30 ); wait.until(pageLoad); } |
4.遇到异常重新启动机制
监控的原理在于间歇性的点击相应的科室并监听页面中是否有想要的元素出现(如出现预约挂号),如果出现则点击进入相应界面,如果没有出现则一直监听。
但是在实测过程中,发现持续点击某科室会出现页面一直加载的情况,这时候会抛出异常,程序无法正常进行。
所以在这里捕获异常,通过递归调用的思想,关闭先前的driver对象,并调用自己重新生成一份监听driver对象,从而保证程序正常执行,提高了程序的健壮性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
try { WebDriverWait wait = new WebDriverWait(driver, 7000 ); wait.until( new ExpectedCondition<WebElement>(){ public WebElement apply(WebDriver d) { try { Thread.sleep( 2000 ); //为避免给baidu早成麻烦,每2秒监听一次 } catch (InterruptedException e) { e.printStackTrace(); } departLink.click(); //departLink为妇产科的文本链接 monitoringTimes++; //监听的次数 System.out.println( "第" + monitoringTimes + "次监控" ); return d.findElement(By.xpath( "//*[@id='doctor-info-list']/descendant::*[contains(text(), '预约挂号')][1]" )); } }); waitForLoad(driver); } catch (Exception e) { ticket = true ; System.out.println( "抱歉,目前余号不足,请稍后再试" ); } finally { if (ticket){ driver.close(); startMonitor(); //递归调用 } } |
5.成果展示
但从程序来说,可以现实自动抢号功能,已成功预约到非妇产科以外科室的号。
运行到监控的页面并监听:
实时监听过程:
难点和展望
- dom结构变动,会导致无法正常定位;
- 代码执行过程,有时会抛出异常,需要处理;
- 频繁的登录,需要在登录界面输入验证码,验证码的识别可以采用OCR破解;
- 最好做成一个客户端,提供给用户自定义输入医院和科室乃至指定时间段或医生
一般情况下是登录成功后取到cookie直接放Python里跑一下就完事,几乎不用考虑掉线的情况。
http://www.cnblogs.com/bigdataZJ/p/hittest.html
主要的核心思想是取cookie然后发查询请求,不需要浏览器做代理(转)的更多相关文章
- 读《SQL优化核心思想》:你不知道的优化技巧
SQL性能问题已经逐步发展成为数据库性能的首要问题,80%的数据库性能问题都是因SQL而导致. 1.1 基数(CARDINALITY) 某个列唯一键(Distinct_Keys)的数量叫作基数.比如性 ...
- laravel生命周期和核心思想
工欲善其事,必先利其器.在开发Xblog的过程中,稍微领悟了一点Laravel的思想.确实如此,这篇文章读完你可能并不能从无到有写出一个博客,但知道Laravel的核心概念之后,当你再次写起Larav ...
- jQuery的核心思想
jQuery?----www.jQuery.com jQuery的理念:write less, do more jQuery的成就:世界排名前100的公司,46%都在使用jQuery,远远超过其他库, ...
- 浅谈Vue.js2.0核心思想
Vue.js是一个提供MVVM数据双向绑定的库,专注于UI层面,核心思想是:数据驱动.组件系统. 数据驱动: Vue.js数据观测原理在技术实现上,利用的是ES5Object.defineProper ...
- 《深入理解Spark:核心思想与源码分析》——SparkContext的初始化(叔篇)——TaskScheduler的启动
<深入理解Spark:核心思想与源码分析>一书前言的内容请看链接<深入理解SPARK:核心思想与源码分析>一书正式出版上市 <深入理解Spark:核心思想与源码分析> ...
- 《深入理解Spark:核心思想与源码分析》(前言及第1章)
自己牺牲了7个月的周末和下班空闲时间,通过研究Spark源码和原理,总结整理的<深入理解Spark:核心思想与源码分析>一书现在已经正式出版上市,目前亚马逊.京东.当当.天猫等网站均有销售 ...
- 《深入理解Spark:核心思想与源码分析》(第2章)
<深入理解Spark:核心思想与源码分析>一书前言的内容请看链接<深入理解SPARK:核心思想与源码分析>一书正式出版上市 <深入理解Spark:核心思想与源码分析> ...
- 《深入理解Spark:核心思想与源码分析》一书正式出版上市
自己牺牲了7个月的周末和下班空闲时间,通过研究Spark源码和原理,总结整理的<深入理解Spark:核心思想与源码分析>一书现在已经正式出版上市,目前亚马逊.京东.当当.天猫等网站均有销售 ...
- 《深入理解Spark:核心思想与源码分析》正式出版上市
自己牺牲了7个月的周末和下班空闲时间,通过研究Spark源码和原理,总结整理的<深入理解Spark:核心思想与源码分析>一书现在已经正式出版上市,目前亚马逊.京东.当当.天猫等网站均有销售 ...
随机推荐
- 基于Hadoop技术实现的离线电商分析平台(Flume、Hadoop、Hbase、SpringMVC、highcharts)
离线数据分析平台是一种利用hadoop集群开发工具的一种方式,主要作用是帮助公司对网站的应用有一个比较好的了解.尤其是在电商.旅游.银行.证券.游戏等领域有非常广泛,因为这些领域对数据和用户的特性把握 ...
- 利用Xtrabackup备份集合恢复一台从库的过程
1 time tar -xvf Open..tarx.gz real 35m22.502s user 10m16.499s sys 1m28.578s You have new m ...
- 大约sources.list和apt-get [转载]
个人觉得,Debian这与最大的方便apt-get安装软件,apt-get这可能是工作:/etc/apt/sources.list文件中保存着一些server的设置,在这些server上有大量的能够用 ...
- String[255]在高版本Delphi里还是被解释成Byte,总体长度256,使用StrPCopy可以给Array String拷贝字符串(内含许多实验测试)
学了好多不了解的知识: procedure TForm1.Button1Click(Sender: TObject); var s1 : String; s2 : String[]; begin s1 ...
- uva 357 Let Me Count The Ways(01背包)
题目连接:357 - Let Me Count The Ways 题目大意:有5种硬币, 面值分别为1.5.10.25.50,现在给出金额,问可以用多少种方式组成该面值. 解题思路:和uva674是一 ...
- 【IOS实例小计】图像移动--可扩展为动态实现图标变化
预备知识: 1.页面切换: 从一个ViewController切换到另一个ViewController有下面几种方法: (1)self.view addSubview:(加载的新页面); 相 ...
- 在iPhoneApp中加载PDF
原文: http://ios.biomsoft.com/2012/02/17/load-a-pdf-file-in-the-iphone-app-smoothly/ 本节将学习如何从服务器加载 pdf ...
- IE6下position:fixed不支持问题及其解决方式
IE6有诸多奇葩,不支持position:fixed就是当中之中的一个.所以在做一些比方固定在顶部或者底部或者固定元素的效果时须要考虑兼容IE6的这个问题.解决方式是用Ie6的hack. *html ...
- wake_lock_timeout的用法
今天实用到用ec43_GPIO的中断来唤醒系统,将系统从深度休眠中唤醒并保证系统wakup 一段时间用过了.方法例如以下.有相同使用的童鞋能够參考一下. 1. 定义一人局部静态变量ec43_wlo ...
- 《Getting Started with WebRTC》第一章 WebRTC介绍
<Getting Started with WebRTC>第一章 WebRTC介绍 本章是对WebRTC做概念性的介绍. 阅读完本章后.你将对下面方面有一个清晰的理解: . 什么 ...