为了媳妇的一张号,我与百度医生杠上了

  需求是催生项目和推进项目的不竭动力。

背景:

  最近,因为媳妇要做个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的驱动

System.setProperty ( "webdriver.chrome.driver" , "C:\\Users\\Administrator\\Downloads\\chromedriver_win32\\chromedriver.exe" );
WebDriver driver = new ChromeDriver();

 

2.定位元素执行动作

  如定位百度页面的登录按钮,并执行点击操作

WebElement loginLink = driver.findElement(By.xpath(".//*[@id=‘u1‘]/a[7]"));
loginLink.click();

  

3.等待页面加载完成

  有时候在driver.get()到某个页面时,如果页面没有加载完成,这时候去定位元素容易抛出异常,所以需要加入等待页面加载完成的功能。这里将其封装在一个函数中:

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对象,从而保证程序正常执行,提高了程序的健壮性。

        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破解;
  • 最好做成一个客户端,提供给用户自定义输入医院和科室乃至指定时间段或医生

写此程序,纯属需求催生,仅为一乐,勿动邪念^^。

如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。

  
时间: 2024-11-05 18:31:30

为了媳妇的一张号,我与百度医生杠上了的相关文章

百度Ueditor 图片上传无反应,显示上传0张,不能点确定

解决办法: \Data\Ueditor\php\Uploader.class.php 190行左右 /** * 获取文件扩展名 * @return string */ private function getFileExt() { date_default_timezone_set("PRC"); return strtolower( strrchr( $this->file[ "name" ] , '.' ) ); } 添加了date_default_tim

cordova 社交张号插件设计

近来接触到cordova这个好东西,才知道原来web app可以这样用.用HTML5 APP开发神器 设计好了app之后,为了增加用户粘度想着把社交登陆加进去,刚好cordova支持第三方插件云编译功能. 如果是本地APP集成SNS登陆功能,都有相应的文档可以参考,QQ有客服人员,微信开放平台功能也比较单一,微博还有开发者QQ群可以互相交流学习.网上找了下SNS第三方登陆的插件还是比较欠缺,只能自己造轮子.按照文档,一步一步推测加调试.加上没有android开发经验,弄的有点焦头烂额.还好学习了

网上哪里可以买微信号详情查看百度快照

曾经在某一个瞬间,我们以为自己长大了,有一天,我们终于发现,长大的含义除了欲望还有勇气和坚强,以及某种必须的牺牲.在生活的面前我们还都是孩子,其实我们从未长大还不懂得爱和被爱.网上哪里可以买微信号我不知道是不是真的有这么巧,只能说有太多的话都说不清楚.大量实名微信号出售一生至少该有一次,为了某人而忘记自己,不求有结果,不求同行,不求曾经拥有,甚至不求你爱我.只求在我最美的年华里,遇到你.微信号5元一个出售平台 微信号5元一个出售平台 原文地址:https://www.cnblogs.com/we

24小时私人借钱微信号详情查看百度快照

有人说,爱上一座城,是因为城中住着某个喜欢的人.其实不然,爱上一座城,也许是为城里的一道生动风景,为一段青梅往事,为一座熟悉老宅.或许,仅仅为的只是这座城.就像爱上一个人,有时候不需要任何理由,没有前因,无关风月,只是爱了.24小时私人借钱微信号坐公交车的时候,看到一美女提着大包小包上来了,没多余的手抓扶手这样很危险,于是我果断的起来给美女让座,美女欣然接受,没想到美女和我同一站下车,下车的时候美女对我说:能不能和我一起帮我把东西提回家?我毫不犹豫的答应了.我想说好人是有好报的!微信私人账号你曾

再现9月20号今天的百度笔试题

一  简答题 1.进程和线程有什么区别?(到处都在问这个问题) 2.简诉数据库的存储过程及其优点.(我实习的时候就是一直在写存储过程,所以) 3.全局static变量和普通全局变量区别?static局部变量和普通局部变量的区别?static函数和普通函数的区别? 二 算法与程序设计题 1.编码实现函数 void* memcpy(void* des, void* src, int len) 2.有这样一个二维矩阵A[N][N],满足j < k时, 1)a[i][j] < a[i][k]; 2)a

PHP用反撇号(`,也就是键盘上ESC键下面的那个,和~在同一个上面)执行外部命令

例如: echo `whoami`; // 导出数据库,要导入的文件夹必须要有可写权限, -u -p之后的内容必须要紧挨着写 echo `mysqldump -h localhost -u$DbUser -p$DbPwd --default-character-set=utf8 $DbName > /var/$dumpFileName`;

主要的核心思想是取cookie然后发查询请求,不需要浏览器做代理(转)

需求是催生项目和推进项目的不竭动力. 背景: 最近,因为媳妇要做个B超检查,想着去大医院查查应该更放心,所以就把目标瞄准在A医院.早已耳闻A院一号难求万人空巷,所以把所有能接触到的机会都看了一遍,线下听传闻说早上徐亚5点左右去排队还未必能排上,线上主要有以下两个来源: 1.支付宝 在支付宝的城市服务中,定位到指定城市,是能够看一些医院提供了预约挂号接口的,显然A医院当之无愧也在其中. 简便易用的支付宝用户体验,即便是第一次来也好像是经常使用这项服务般熟练.找到A院,搜索妇产科,在list中有若干

张小龙做微信公众号APP,对自媒体是祸还是福?

1月15日,2018微信公开课PRO版在广州举行,腾讯高级副总裁.微信创始人张小龙现身现场并发表演讲,他宣布了下一步的微信战略:即将推出微信公众号APP,以及恢复赞赏功能,并倾向于赞赏作者等等.此外,张小龙还表示不会做信息流. 一时之间,人们不禁感慨,微信微信"情怀"不在. 有人问何玺,对张小龙做公众号APP,不做信息流有什么看法?何玺的观点是: 一,内容分发(信息流)是门大生意,腾讯必须卡位 5年完成5轮融资,最新估值达300亿美金.7亿用户,每月净增1000万以上用户.2016年广

先做一个“小程序”——关于微信应用号的六大猜想

先做一个“小程序”——关于微信应用号的六大猜想 9月 21 日,苦等了9个多月的时间,应用号终于与我们见面了,命名为「小程序」. 01 为什么推出小程序? 考虑到小程序对整个APP市场的影响,毫无疑问会对现有的APP生态带来一定的冲击.但是,之所以推出小程序,最直接的原因可能是为了构建和扩充微信生态链,让微信更具开放性. 如我们所知,目前微信公众号分为三类: • 服务号,连接人和商品,目前很多电商企业,以及在微信端提供产品和服务的企业都用服务号. • 订阅号,微信官方的定位是阅读,连接人和资讯的