Python实现上下班抢个顺风单脚本

yipeiwu_com5年前Python基础

一 程序预览

本程序已经写了多年, 很久没用, 不过刚运行了下竟然还可以成功运行. 先来张运行结果图.

二 最近的滴滴APP已经可以支持设置自动抢单功能, 这个小程序就没有那么大意义了. 在此主要谈一下我当初的想法:

1. 这个小程序运行在电脑上, 人在回家的路上, 有时不想接单了也不好控制. 于是我把一些参数都写到坚果云下的一个文本文件里, 手机上也装一个坚果云, 如果不想接单就把参数改一下就可以了.  详见函数loadTimeConfig.

2. 这个程序一直用urllib2给服务器发请求模拟手机操作以查找单子, 所以对滴滴服务器有一定的压力. 如果频率太快, 滴滴能发现.

3. 参数的抓取我用的是Charles, 具体请百度Google之.

4. 程序中的一些参数现在应该还有效, 便于大家试验. 但一段时间后我会使其无效. 运行前, 请把striveOrder(order)注释掉, 不然是有可能出其不意给我抢个单子的惊恐

5. 本程序只用于实验研究, 请勿乱用. 谢谢.

三 下面是代码+解释, 可以在上面的链接中下载.

程序下载链接

最佳体验所需环境:

Python2.6/7, Python3.x没试
手机电脑上都安装坚果云, 并创建ditime2.txt
手机端有邮件接收APP.

#!/usr/bin/python 
# -*- coding: gb2312 -*- 
 
######################################################################### 
#2015-12-11 09:47:46 
#author: 358275018@qq.com 
#使用Python2.6/7 
######################################################################## 
 
# 有些库没用, 请自行删除 
import urllib2, urllib, traceback, smtplib, datetime 
import os, sys, time,zlib,json,ConfigParser,codecs 
from email.mime.text import MIMEText 
from email.mime.image import MIMEImage 
 
import email.MIMEMultipart 
import email.MIMEText 
import email.MIMEBase 
 
from utility import getPyLogger,debug,info 
 
#mail_host="smtp.qq.com"  #设置服务器 
mail_host='smtp.qq.com' 
mail_user="358275018@qq.com" #用户名 
mail_pass="xxxxxxxxx"  #口令, 请修改!!! 
 
MORNING_START="08:30"  #上班, 截获从8:30到8:40的顺风单 
MORNING_END="08:40" 
AFTERNOON_START="18:05"  #下班, 截获从18:05到18:20的顺风单 
AFTERNOON_END="18:20" 
last_modify_time = 0 
 
TOKEN='JPXq-mw6-YPhBnegPQ6pdbwJvXMOw5SnLfWW6-gl1pVUjDsOwkAMRO8ytQvb62wc34Y_FAiJFVW0d2faVCO9N3o7TihAcEZ5WqyLbov3toYKrmQuuKF2jPdAWfRwN9dNMD6_74VKp-B-VA8mrXkSZMvO-pNEuS8e5z8AAP__' 
 
# 手机和电脑上都安装坚果云, 创建文本文件ditime2.txt, 在手机上修改参数就可以控制正在电脑上运行的本程序 
def loadTimeConfig(): 
 global last_modify_time,MORNING_START,MORNING_END,AFTERNOON_START,AFTERNOON_END 
 file_name = r"C:\ddrive\mynutstore\ditime2.txt" 
 if(not os.path.exists(file_name)): 
 return 
 statinfo=os.stat(file_name) 
 if(statinfo.st_mtime>last_modify_time): 
 last_modify_time = statinfo.st_mtime 
 config = ConfigParser.ConfigParser() 
 try: 
  config.readfp(codecs.open(file_name, "r", "utf_16")) 
 except Exception, e: 
  config.read(file_name) 
 try: 
  MORNING_START=config.get('TIME_INFO', 'MORNING_START').strip() 
 except Exception, e: 
  pass 
 try: 
  MORNING_END=config.get('TIME_INFO', 'MORNING_END').strip() 
  print 'MORNING_END=',MORNING_END 
 except Exception, e: 
  pass 
 try: 
  AFTERNOON_START=config.get('TIME_INFO', 'AFTERNOON_START').strip() 
 except Exception, e: 
  pass 
 try: 
  AFTERNOON_END=config.get('TIME_INFO', 'AFTERNOON_END').strip() 
 except Exception, e: 
  pass 
  
def getHtmlContent(respInfo): 
 htmlContent = '' 
 try: 
 respHtml = respInfo.read() 
 if( ("Content-Encoding" in respInfo.headers) and (respInfo.headers['Content-Encoding'] == "gzip")): 
  htmlContent = zlib.decompress(respHtml, 16+zlib.MAX_WBITS); 
 else: 
  htmlContent = respHtml 
 except BaseException, e: 
 debug(logger, traceback.format_exc()) 
 return htmlContent 
 
def send_mail(to_list,sub,content): 
 me="358275018@qq.com" 
 msg = MIMEText(content,_subtype='plain',_charset='gb2312') 
 msg['Subject'] = sub 
 msg['From'] = me 
 msg['To'] = ";".join(to_list) 
 try: 
 server = smtplib.SMTP() 
 server.connect(mail_host) 
 server.login(mail_user,mail_pass) 
 server.sendmail(me, to_list, msg.as_string()) 
 server.close() 
 return True 
 except Exception, e: 
 print str(e) 
 return False 
  
 
 
 
headers = { 
 'Host': 'api.didialift.com' 
 ,'Accept-Encoding': 'gzip' 
 ,'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 6.0.1; MI 4LTE MIUI/V7.2.11.0.MXDCNDB)' 
} 
common_headers = { 
 'Host': 'common.diditaxi.com.cn' 
 ,'Accept-Encoding': 'gzip' 
 ,'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 6.0.1; MI 4LTE MIUI/V7.2.11.0.MXDCNDB)' 
} 
xiaojukeji_headers = { 
 'Host': 'pay.xiaojukeji.com' 
 ,'Accept-Encoding': 'gzip, deflate' 
 ,'Accept': '*/*' 
 ,'Accept-Language': 'zh-Hans;q=1, en;q=0.9, fr;q=0.8, de;q=0.7, zh-Hant;q=0.6, ja;q=0.5' 
 ,'User-Agent': 'OneTravel/4.1.4.3 (iPhone; iOS 7.1.2; Scale/2.00)' 
} 
 
 
ROUTE_ID_MORNING1='12132747' #家->办公室 
ROUTE_ID_AFTERNOON1='109950277' #办公室->家 
one_way_map = { 
 'android_id':'2227d1a93826902' 
 ,'appversion':'4.4.10' 
 ,'at_mb_cid':'19771395' 
 ,'at_mb_lac':'16836' 
 ,'at_mb_mcc':'460' 
 ,'at_mb_mnc':'01' 
 ,'at_net_st':'1' 
 ,'at_wf_bssid':'8c:be:be:16:b5:74' 
 ,'at_wf_ssid':'"zzzzzz"' 
 ,'channel':'0' 
 ,'city_id':'14' 
 ,'cpu':'Processor : ARMv8 Processor rev 1 (v8l)' 
 ,'datatype':'1' 
 ,'date_id':'1477584000' 
 ,'dviceid':'bf39e245983e7ce8b96ec5cb468f4b9e' 
 ,'filter':'0' 
 ,'imei':'8659310207085419EFC357283F3AFD66688CC444C08403A' ################ 
 ,'lat':'38.844252869870736' 
 ,'lng':'121.51104529558397' 
 ,'locatePerm':'1' 
 ,'locateTime':'1462240824' 
 ,'mac':'74:51:ba:55:a6:8f' 
 ,'maptype':'soso' 
 ,'model':'MI 4LTE' 
 ,'networkType':'WIFI' 
 ,'os':'6.0.1' 
 ,'route_id':'12132747' 
 #,'sig':'2cdde9c6ac1b653c19a31a535b1959acf0c61156' 
 ,'suuid':'F759479A0C2CCDE83BE5EA8D5F6EC05E_15' 
 ,'token':TOKEN 
 ,'uuid':'D85C052433285BB365875F9F3AA28EFE'############### 
 ,'vcode':'162' 
 ,'wsgsig':'sign error' 
} 
 
#抢单参数 
strive_para_map = { 
 'android_id':'2227d1a93826902' #'_t':'1449818404' 
 ,'appversion':'4.4.10' 
 ,'at_mb_cid':'18589187' 
 ,'at_mb_lac':'16838' 
 ,'at_mb_mcc':'460' 
 ,'at_mb_mnc':'01' 
 ,'at_net_st':'1' 
 ,'at_wf_bssid':'8c:be:be:16:b5:74' 
 ,'at_wf_ssid':'zzzzzz' 
 ,'channel':'0' 
 ,'city_id':'14' 
 ,'cpu':'Processor : ARMv8 Processor rev 1 (v8l)' 
 ,'datatype':'1' 
 ,'dviceid':'bf39e245983e7ce8b96ec5cb468f4b9e' 
 ,'imei':'8659310207085419EFC357283F3AFD66688CC444C08403A' 
 ,'lat':'38.849033' 
 ,'lng':'121.518660' 
 ,'locatePerm':'1' 
 ,'locateTime':'1449818399' 
 ,'mac':'74:51:ba:55:a6:8f' 
 ,'maptype':'soso' 
 ,'model':'MI 4LTE' 
 ,'networkType':'WIFI' 
 ,'order_id':'3635506508184237070' 
 ,'order_level':'1' 
 ,'os':'6.0.1' 
 ,'route_id':'4338899913' 
 ,'serial':'1462283172995' 
 #,'sig':'82d12c28338ca223876af1242cf341e6a334cc50' 
 ,'source':'0' 
 ,'suuid':'F759479A0C2CCDE83BE5EA8D5F6EC05E_15' 
 ,'token':TOKEN 
 ,'uuid':'D85C052433285BB365875F9F3AA28EFE' 
 ,'vcode':'162' 
 ,'view_sort':'0c' 
} 
 
# 此函数用来计算sig - 用来加入请求参数中. 这个SIG参数一般是APP用来防止你通过模拟作弊的. 
def getSig(map): 
 from operator import itemgetter 
 params = sorted(map.iteritems(), key=itemgetter(0), reverse=False) 
 newList = [] 
 PREFIX = "didiwuxiankejiyouxian2013" 
 newList.append(PREFIX) 
 for parm in params: 
 newList.append(parm[0]+parm[1]) 
 newList.append(PREFIX) 
 data = ''.join(newList) 
 import hashlib 
 sig = hashlib.sha1(data).hexdigest(); 
 return sig 
 
POINT_HOME = set([u'万科溪之谷',u'依云溪谷']) 
POINT_OFFICE = set([u'大连软件园腾飞',u'腾飞软件园',u'谷歌里',u'东软软件园B区']) 
 
#挑选合适的单子,条件包括: 
#  a. 起点终点在POINT_HOME和POINT_OFFICE中; 
# b. 时间在[MORNING_START,MORNING_END], 或[AFTERNOON_START,AFTERNOON_END] 
def filter(order): 
 departure_time = order["trip_info"]['text_setup_time'] 
 #route_id = order['route_id'] 
 order_id = order["order_info"]['order_id'] 
 from_name = order["trip_info"]['from_name'] 
 from_address = order["trip_info"]['from_address'] 
 to_name = order["trip_info"]['to_name'] 
 to_address = order["trip_info"]['to_address'] 
 price = order["trip_info"]['price'] 
 
 global MORNING_START,MORNING_END,AFTERNOON_START,AFTERNOON_END 
 #上班 
 if(departure_time[-5:]>=MORNING_START and departure_time[-5:]<=MORNING_END): 
 #测试起点 
 start = False; 
 for oneArea in POINT_HOME: 
  if from_name.find(oneArea)>-1: 
  start = True; 
  break; 
 if(start == False): 
  return False;  
  
 #测试终点 
 end = False; 
 for oneArea in POINT_OFFICE: 
  if to_name.find(oneArea)>-1: 
  end = True; 
  break; 
 return end; 
 
 #下班 
 if(departure_time[-5:]>=AFTERNOON_START and departure_time[-5:]<=AFTERNOON_END): 
 #测试起点 
 start = False; 
 for oneArea in POINT_OFFICE: 
  if from_name.find(oneArea)>-1: 
  start = True; 
  break; 
 if(start == False): 
  return False;  
  
 #测试终点 
 end = False; 
 for oneArea in POINT_HOME: 
  if to_name.find(oneArea)>-1: 
  end = True; 
  break; 
 return end; 
  
 return False; #其它一律视为不符合条件 
 
HOME_at_wf_bssid = 'ec:88:8f:2b:a1:84' 
HOME_at_wf_ssid = '"MERCURY_2BA184"' 
HOME_lat='38.814874403212' 
HOME_lng='121.577924262153' 
HOME_at_mb_cid='68630454' 
HOME_at_mb_lac='49441' 
# 
OFFICE_at_wf_bssid = '8c:be:be:16:b5:74' 
OFFICE_at_wf_ssid = '"zzzzzz"' 
OFFICE_lat='38.949033203125' 
OFFICE_lng='121.418660753038' 
OFFICE_at_mb_cid='18538497' 
OFFICE_at_mb_lac='16836' 
 
#修改参数 
def updateParmsMap(map): 
 localtime = time.localtime(time.time()) 
 hour = str(localtime.tm_hour) 
 min = str(localtime.tm_min) 
 if(len(hour)==1): hour='0'+hour 
 if(len(min)==1): min='0'+min 
 hm = hour+':'+min 
 if( hm>'09:00' and hm<'18:30'):#OFFICE 
 if(map.has_key('at_wf_bssid')): map['at_wf_bssid']=OFFICE_at_wf_bssid 
 if(map.has_key('at_wf_ssid')): map['at_wf_ssid']=OFFICE_at_wf_ssid 
 if(map.has_key('lat')): map['lat']=OFFICE_lat 
 if(map.has_key('lng')): map['lng']=OFFICE_lng 
 if(map.has_key('at_mb_cid')): map['at_mb_cid']=OFFICE_at_mb_cid 
 if(map.has_key('at_mb_lac')): map['at_mb_lac']=OFFICE_at_mb_lac 
 else:#HOME 
 if(map.has_key('at_wf_bssid')): map['at_wf_bssid']=HOME_at_wf_bssid 
 if(map.has_key('at_wf_ssid')): map['at_wf_ssid']=HOME_at_wf_ssid 
 if(map.has_key('lat')): map['lat']=HOME_lat 
 if(map.has_key('lng')): map['lng']=HOME_lng 
 if(map.has_key('at_mb_cid')): map['at_mb_cid']=HOME_at_mb_cid 
 if(map.has_key('at_mb_lac')): map['at_mb_lac']=HOME_at_mb_lac 
 now = int(time.time()) 
 #map['_t']=str(now) 
 map['locateTime']=str(now+10) 
 if(map.has_key('app_time')): map['app_time']=str(now+10) 
 date_id = int(time.mktime(datetime.date.today().timetuple())) 
 map['date_id']=str(date_id) 
 sig = getSig(map) 
 map['sig']=sig 
  
def getOrdersViaUrl(url): 
 req = urllib2.Request(url,headers=headers) 
 respInfo = urllib2.urlopen(req,timeout=15) 
 html = getHtmlContent(respInfo) 
 #debug(logger,html) 
 
 json_data = json.loads(html) 
 orders=[] 
 section_list = [] 
 if(json_data.has_key('section_list')): 
 section_list=json_data['section_list'] 
 for section in section_list: 
 type = section["type"] 
 if(type=="byway_order_info"): 
  orders = section["list"] 
  break 
 return orders 
 
# 获得线路route_id上所有的单子 
def getOrders_432(): 
 localtime = time.localtime(time.time()) 
 hour = localtime.tm_hour 
 if(hour>=10 and hour<=19): 
 one_way_map['route_id']=ROUTE_ID_AFTERNOON1 
 updateParmsMap(one_way_map) 
 paraStr = urllib.urlencode(one_way_map) 
 url = "http://api.didialift.com/beatles/api/route/driver/info?"+paraStr 
 orders = getOrdersViaUrl(url) 
 return orders 
 else: 
 one_way_map['route_id']=ROUTE_ID_MORNING1 
 updateParmsMap(one_way_map) 
 paraStr = urllib.urlencode(one_way_map) 
 url = "http://api.didialift.com/beatles/api/route/driver/info?"+paraStr 
 orders = getOrdersViaUrl(url) 
 return orders 
 
# 抢单 
def striveOrder(order): 
 route_id = order['route_id'] 
 order_id = order['order_id'] 
 
 # put time and sig params 
 updateParmsMap(strive_para_map) 
 strive_para_map['route_id']=route_id 
 strive_para_map['order_id']=order_id 
 sig = getSig(strive_para_map) 
 strive_para_map['sig']=sig 
 
 paraStr = urllib.urlencode(strive_para_map) 
 url = "http://api.didialift.com/beatles/api/driver/order/strive?"+paraStr 
 req = urllib2.Request(url,headers=headers) 
 respInfo = urllib2.urlopen(req,timeout=15) 
 html = getHtmlContent(respInfo) 
 #debug(logger,html) 
 map = json.loads(html) 
 return map['errno']=='0' and map['errmsg']=='OK' 
 
 
if __name__ == '__main__': 
 try: 
 # 发邮件通知你服务启动了 
 send_mail(['358275018@qq.com'],'didi catcher starts','didi catcher starts') 
 except Exception,e: 
 pass 
 
 log_path = os.path.dirname(os.path.realpath(__file__)) 
 if not os.path.exists(log_path): 
 os.makedirs(log_path) 
 logger = getPyLogger('didi','debug',os.path.join(log_path,os.path.basename(__file__)+'.log'),'d',1,99999) 
 
 debug(logger,'start to work...') 
 while(1): 
 try: 
  #从坚果云中LOAD最新的参数 
  loadTimeConfig() 
 
  debug(logger,'FLOW: get my orders') 
  orders = getOrders_432() 
  debug(logger,'FLOW: GOT ================='+str(len(orders))+' ==================orders') 
  for order in orders: # 所有单子 
  departure_time = order["trip_info"]['text_setup_time'] 
  #route_id = order['route_id'] 
  order_id = order["order_info"]['order_id'] 
  from_name = order["trip_info"]['from_name'] 
  from_address = order["trip_info"]['from_address'] 
  to_name = order["trip_info"]['to_name'] 
  to_address = order["trip_info"]['to_address'] 
  price = order["trip_info"]['price'] 
  passenger_id = order['user_info']['user_id'] 
  nick_name = order['user_info']['nick_name'] 
   
  debug(logger,'FLOW: filter orders') 
  debug_content = '%s (%s->%s) price=%s'%(departure_time,from_name,to_name,price) #nick_name 
  debug(logger,debug_content) 
   
  if(filter(order)): #过滤单子 
   debug(logger,'FLOW: strive order') 
   striveOrder(order) #抢合适的单子 
   #print 'FOUND **************************************** FOUND' 
   content = departure_time.encode('utf8')+' '+from_name.encode('utf8')+' '+to_name.encode('utf8') 
   # 抢到合适的单子, 给自己发邮件. 
   send_mail(['358275018@qq.com'],content,content) 
   break; 
  time.sleep(10) 
 except Exception,e: 
  debug(logger,str(e)) 
  time.sleep(10) 
 # 退出, 发邮件通知. 
 send_mail(['358275018@qq.com'],'didi chatcher exits','didi chatcher exits') 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持【听图阁-专注于Python设计】。

相关文章

Python中字典和集合学习小结

映射类型:     表示一个任意对象的集合,且可以通过另一个几乎是任意键值的集合进行索引     与序列不同,映射是无序的,通...

Python cookbook(数据结构与算法)从字典中提取子集的方法示例

本文实例讲述了Python从字典中提取子集的方法。分享给大家供大家参考,具体如下: 问题:想创建一个字典,其本身是另一个字典的子集 解决方案:利用字典推导式(dictionary com...

在Python的列表中利用remove()方法删除元素的教程

 remove()方法从列表中删除第一个obj。 语法 以下是remove()方法的语法: list.remove(obj) 参数   &n...

python使用__slots__让你的代码更加节省内存

python使用__slots__让你的代码更加节省内存

前言 在默认情况下,Python的新类和旧类的实例都有一个字典来存储属性值。这对于那些没有实例属性的对象来说太浪费空间了,当需要创建大量实例的时候,这个问题变得尤为突出。 因此这种默认的...

Python提取支付宝和微信支付二维码的示例代码

Python提取支付宝和微信支付二维码的示例代码

支付宝或者微信支付导出的收款二维码,除了二维码部分,还有很大一块背景图案,例如下面就是微信支付的收款二维码: 有时候我们仅仅只想要图片中间的方形二维码部分,为了提取出中间部分,我们可以...