使用Selenium找出外卖点餐次数最多的10个顾客

发表于:2016-8-01 11:41

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:oceany    来源:51Testing软件测试网采编

  大锅在做外卖,给我说能否统计出这半年点餐次数最多的10个顾客,我不知道APP本身是否有这个功能,想了下最近用selenium较多,就用selenium尝试下吧。
  1、定义一个类,这里先描述需要的属性和方法,后面再依次具体分析:
1 class Order:
2     def __init__(self, url, username, password):
3         # URL以及用户名和密码
4         self.url = url
5         self.username = username
6         self.password = password
7         # webdriver对象
8         self.driver = None
9         # 日期列表
10         self.dateList = list()
11         # 存储订单的dict
12         self.orderDict = dict()
13
14     # 设置订单的时间范围
15     def setDate(self, startdate, enddate):
16         pass
17     # 登录
18     def login(self):
19         pass
20     # 退出
21     def logout(self):
22         pass
23     # 切换到历史订单页面
24     def switchToHistoryOrder(self):
25         pass
26     # 选择一个时间范围
27     def selectDate(self, startDate, endDate):
28         pass
29     # 订单信息存入self.orderDict
30     def saveOrderIntoDict(self, tel, name, address):
31         pass
32     # 处理当前页面的订单
33     def searchOrderListInCurrentPage(self):
34         pass
35     # 判断是否还有下一页
36     def hasNextPage(self):
37         pass
38     # 切换到下一页
39     def enterNextPage(self):
40         pass
41     # 抓取设定日期范围内的所有订单
42     def getAllOrders(self, startdate, enddate):
43         pass
44     # 筛选出点餐次数排名前N的顾客
45     def getTopN(self, n=10):
46         pass
  2、设置欲筛选的订单日期范围
  这里设置的日期格式必须是'yyyy-mm-dd',由于该网站在查询订单的时候,时间范围必须是7天以内,比如直接查询2016-01-01到2016-02-28之间的订单是不行的,因此需要先将这段时间以7天为周期分割为多个时间段,然后再分段处理;
  分割后的时间段存放在self.dateList中,list的元素为tuple,一个tuple表示一个时间段:
1 # 设置订单的时间范围,日期格式必须是'yyyy-mm-dd'
2     # 然后以7天为周期,将日期范围分割成list,list的每个元素为一个tuple,分别存放起止日期
3     # 例如 [('2016-01-01', '2016-01-07'), ('2016-01-08', '2016-01-14')]
4     def setDate(self, startdate, enddate):
5         # 通过正则表达式检查日期格式
6         pdate = re.compile('\d{4}-\d{2}-\d{2}')
7         if pdate.search(startdate) and pdate.search(enddate):
8             # 转换为datetime格式,便于日期计算
9             startdate = datetime.datetime.strptime(startdate, '%Y-%m-%d')
10             enddate = datetime.datetime.strptime(enddate, '%Y-%m-%d')
11
12             # 将日期范围以7天为周期分割
13             days = (enddate - startdate).days + 1
14             cnt = days / 7
15             left = days - 7*cnt
16             for x in range(cnt):
17                 d1 = (startdate + datetime.timedelta(days=7*x))
18                 d2 = (d1 + datetime.timedelta(days=6))
19                 # datetime转换为str,再加入list中
20                 self.dateList.append((d1.strftime('%Y-%m-%d'), d2.strftime('%Y-%m-%d')))
21             if left > 0:
22                 self.dateList.append(((startdate+datetime.timedelta(days=cnt*7)).strftime('%Y-%m-%d'), enddate.strftime('%Y-%m-%d')))
23         else:
24             print u'日期格式错误,必须为yyyy-mm-dd格式'
25             exit(1)
  测试一下:
  1 order = Order('url', 'username', 'password')
  2 order.setDate('2016-01-01', '2016-01-31')
  3 print order.dateList
  4 #输出为
  5 [('2016-01-01', '2016-01-07'), ('2016-01-08', '2016-01-14'), ('2016-01-15', '2016-01-21'), ('2016-01-22', '2016-01-28'), ('2016-01-29', '2016-01-31')]
  3、登录与退出
  登录比较简单,直接过id定位到用户名和密码输入框,然后定位登录按钮点击登录即可,只是定位到输入框后需要先将框内的提示信息清除掉。
  退出就更简单了,直接关闭浏览器即可。
1  # 登录
2     def login(self):
3         # 采用chrome浏览器
4         self.driver = webdriver.Chrome()
5         # 窗口最大化
6         self.driver.maximize_window()
7         # 设置超时时间
8         self.driver.implicitly_wait(10)
9         self.driver.get(self.url)
10
11         # 查找用户名输入框,先清除提示信息,再输入用户名
12         usr = self.driver.find_element_by_id('account-name')
13         usr.clear()
14         usr.send_keys(self.username)
15
16         # 查找密码输入框,先清除提示信息,再输入密码
17         passwd = self.driver.find_element_by_id('account-password')
18         passwd.clear()
19         passwd.send_keys(self.password)
20
21         # 点击登录
22         self.driver.find_element_by_id('account-login-btn').click()
23         return
24
25     # 退出
26     def logout(self):
27         self.driver.close()
28         return
  4、切换到历史订单页面
  登录后点击订单管理,然后点击历史订单,切换到历史订单页面,如下图所示:
  由于“订单管理”和“历史订单”这两个元素都是超链接,因此可以直接用超链接定位:
1     # 切换到历史订单页面
2     def switchToHistoryOrder(self):
3         self.driver.find_element_by_partial_link_text(u'订单管理').click()
4         self.driver.find_element_by_partial_link_text(u'历史订单').click()
5
6         # 切换frame,因为后续的所有处理都是在hashframe中,所有在这里切换
7         self.driver.switch_to.frame('hashframe')
8         return
  注意该方法最后有个切换frame的操作,下一步就知道为什么要添加这句了。
  5、选择订单日期范围,筛选出该日期范围内的订单
  注意这里的日期范围与第二步设置的日期范围不一样,第二步设置的日期范围是我们想要筛选的起止时间,这里的日期范围是第二步分割出来的其中一段。
  与用户名密码框一样,这里的日期输入框也可采用id定位,同样定位后需要先将输入框预置的日期清除:
1     # 在页面上设置订单的时间范围,并筛选出该时间范围内的所有订单
2     # 调用该方法时,参数需从self.dateList中获取,dateList中的每一个tuple对应一组参数
3     def selectDate(self, startDate, endDate):
4         # 设置起始日期
5         s = self.driver.find_element_by_id('J-start')
6         s.clear()
7         s.send_keys(startDate)
8
9         # 设置终止日期
10         e = self.driver.find_element_by_id('J-end')
11         e.clear()
12         e.send_keys(endDate)
13         return
  这里说一下第4步中的切换frame,我们先将切换frame这一句注释掉,然后来测试下选择日期:
  1  order.login()
  2  order.switchToHistoryOrder()
  3  order.selectDate('2016-07-01', '2016-07-02')
  4 # 输出
  5 selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"id","selector":"J-start"}
  可以看到出错了,提示没有需要定位的元素,为什么呢?通过HTML代码可以看到,这里采用了框架frame,所定位的元素在frame里面,如下所示:
  因此需要先切换到该frame里面,然后才能定位到frame里面的元素;由于后续所有的订单操作都在该frame里面,因此在上一步切换到历史订单页面后,就先切换到该frame,便于后续操作。
  6、将订单信息存入self.orderDict
  该方法是下一步需要调用的,因此这里先实现。每一个订单我们只需3个信息:姓名、电话、地址,然后将这三个元素表示的订单存入orderDict,但是由于我们要统计出点餐次数最多的10个顾客,
  因此还要保存每个顾客的点餐次数。这里dict的元素格式为{'tel': ['name', 'address', cnt]},由于姓名可能重复,因此采用了电话作为key值。如果某个顾客第一次点餐,保存时将点餐次数cnt初始化为1;
  如果不是第一次点餐,则将该顾客对应的cnt值加1。
1     # 将tel, name, address表示的订单信息存入self.orderDict
2     # self.orderDict元素的形式为 {'tel': ['name', 'address', cnt]}
3     # 以电话号码为key,以姓名、地址、点餐次数组成的list为value
4     # 当要添加的key不存在时,就将此订单加入orderDict,并且cnt初始化为1
5     # 当要添加的key已经存在时,直接将该key对应的cnt加1
6     def saveOrderIntoDict(self, tel, name, address):
7         if self.orderDict.has_key(tel):
8             self.orderDict[tel][2] += 1
9         else:
10             self.orderDict[tel] = [name, address, 1]
11         return
21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号