写个Python程序上下班抢个顺风单

2023-05-16

一 程序预览

 

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

二 最近的滴滴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')

 
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

写个Python程序上下班抢个顺风单 的相关文章

随机推荐

  • LSTM一般最多堆叠多少层

    一 LSTM一般最多堆叠多少层 在大规模翻译任务的经验中 简单的堆叠LSTM层最多可以工作4层 很少工作6层 超过8层就很差了 Redisual connection有助于梯度的反向传播 xff0c 能够帮助lstm堆叠更多层 xff0c
  • 华为机试在线训练-牛客网(23)判断两个IP是否属于同一子网

    题目描述 子网掩码是用来判断任意两台计算机的IP地址是否属于同一子网络的根据 子网掩码与IP地址结构相同 xff0c 是32位二进制数 xff0c 其中网络号部分全为 1 和主机号部分全为 0 利用子网掩码可以判断两台主机是否中同一子网中
  • APISIX Dashboard中文文档(二)

    2022年7月6日14 31 51 APISIX Dashboard中文文档 一 APISIX Dashboard中文文档 二 APISIX Dashboard中文文档 三 基本部署 在 Linux 上安装 Apache APISIX Da
  • FreeRTOS 任务调度原理(基于cortexM内核)

    目录 默认FreeRTOS调度策略 xff08 单核 xff09 FreeRTOS调度策略的实现 任务创建 任务调度的4种情景 xff1a 1 第一次启动任务调度器 2 任务主动触发调度 3 SystemTick时钟触发调度 4 因为中断而
  • Centos7命令行安装图形用户界面

    安装完成Centos7后 xff0c 重启后发现是命令行界面 xff0c 于是就想改成图形用户界面 安装了图形用户界面的话 xff1a 1 查看系统里是否已经安装了图形用户界面 使用ctrl 43 alt 43 fx xff0c x为123
  • STM32G070 DMA+SPI+LCD显示

    SPI HandleTypeDef hspi1 DMA HandleTypeDef hdma spi1 tx 描述 xff1a LCD的SPI引脚初始化 参数 xff1a 无 返回 xff1a 无 void LCD SPI Init voi
  • Linux 开启VNCSERVER

    尽管我们可以使用 SSH连接远程通过字符界面来操作Linux xff0c 但是对于更多熟悉图形人来说是很不方便的 xff0c 因此开启Linux的远程桌面还是很有必要的 目前有两种比较流行的方式 xff1a XDM X display ma
  • Ubuntu 代号引发的“崩溃”

    写这篇文章主要是因为在前几天 xff0c 因为向来不关心ubuntu代号的我而引发的一次 崩溃 xff08 人崩溃 xff09 xff0c 正如我们所知Ubuntu 每半年都会更新一个版本 xff0c 每两年都会发布一个TLS xff08
  • Prometheus(二)部署Prometheus和node_exporter

    软件包列表 Prometheus安装 解压部署 rm rf prometheus 2 28 1 linux amd64 tar xvf prometheus 2 28 1 linux amd64 tar gz rm usr local pr
  • Python学习之路_day_02(编程语言介绍及变量)

    一 编程语言介绍 1 机器语言 直接用二进制编程 xff0c 直接控制硬件 xff0c 需要掌握硬件的操作细节 优点 xff1a 执行效率高 缺点 xff1a 开发效率低 2 汇编语言 xff1a 用英文标签取代二进制指令去编写程序 xff
  • 解决linux系统read only system 解决办法

    首先确认系统属于非硬盘物理坏道引起 其次确认是否有root权限 下面我要阐述一个恢复实例 xff1a 一现象 xff1a 1 没有root权限 2 由于磁盘空间满溢导致分区表损坏 xff08 非物理坏道引起 xff09 3 重启后已经无法进
  • 哈希查找效率及应用场景

    数组的特点是 xff1a 寻址容易 xff0c 插入和删除困难 xff1b 而链表的特点是 xff1a 寻址困难 xff0c 插入和删除容易 那么我们能不能综合两者的特性 xff0c 做出一种寻址容易 xff0c 插入删除也容易的数据结构
  • 四位比较器

    四位比较器 一 xff0c 实验目的 通过使用比较四位二进制判断它的相对大小 二 xff0c 实验内容 四位比较器的实验 三 xff0c 实验代码 module Comp 2 str output A gt B A lt B A eq B
  • 程序员玩游戏之三--天天爱消除非暴力脚本

    评论 xff1a 此款游戏成功在其好友排名上 好友的分数超过了你无疑会增加你的斗志 中级策略 xff1a 七手八脚多人一起点 这相当于多个CPU处理一个大任务了 xff0c 哈哈 终极策略 xff1a 自动化 机器总是比人快的多 你两个人一
  • 程序员玩游戏之四--娱网棋牌大连打滚子记牌器

    话说大连人都爱打滚子 xff0c 所以本人就做了一个打滚子记牌器 基本原理同 程序员玩游戏之一 自动对对碰 xff0c 故此处不再赘述 xff0c 只留下一张截图吧 代码请见资源地址 xff1a http download csdn net
  • 为SIGSEGV设置handler有用吗?

    背景 最近几天看到先辈们30年前留下了一块代码 xff0c 为SIGSEGV设置了handler xff0c 所以心中有了两个疑问 xff1a 为SIGSEGV设置handler有没有用 xff1f 能否跳过引起崩溃的那一句指令 xff1f
  • GDB调试技巧实战--为优化版release版本的函数寻找参数值

    在上一篇 GDB调试技巧实战 为release版本的函数寻找参数值 中 xff0c 我们探讨了一种为函数找参数的办法 xff0c 但是 xff0c 那是最理想的情况 编译时没有使用 fomit frame pointer 编译时没有开启优化
  • 通过实例了解uprobe及其对性能的影响

    前言 uprobe是用户空间探针的意思 xff0c 可以用来给用户程序的任何地方下探针 xff0c 不仅仅是函数粒度层级的 所以异常灵活 如果不熟悉ftrace uprobe 可参考以下文档 xff1a https www kernel o
  • bpftrace各维度捕捉SIGKILL信号

    一 问题 Ftrace 几乎适配任何主流内核版本 xff09 和 bpftrace xff08 要求内核版本4 1以上 xff09 中都有两个现成的脚本execsnoop bt killsnoop bt 我经常用他们从外部 xff08 不去
  • 写个Python程序上下班抢个顺风单

    一 程序预览 本程序已经写了多年 很久没用 不过刚运行了下竟然还可以成功运行 先来张运行结果图 二 最近的滴滴APP已经可以支持设置自动抢单功能 这个小程序就没有那么大意义了 在此主要谈一下我当初的想法 1 这个小程序运行在电脑上 人在回家