好长时间没有更新博客了,哈哈。

今天公司给了这么一个需求,现在我们需要去淘宝获取上一天的订单号,然后再根据订单号去另一个接口去获取订单详情,然后再给我展示到web!

中间涉及到的技术点有:

  • 模拟登陆
  • 模拟下载
  • 解析exal文件数据流
  • 读取exal文件,拿出订单号
  • 还有最后一点请求接口

下面就给大家挨个说一下,刚拿到需求其实还是很模糊的,因为一个都没做过,等静下心来去理解的时候,发现并没有那么难,反而很简单

模拟登陆

一、分析页面请求头

本次登陆地址是https://huoche.alitrip.com/hello.htm

1、先登陆了一遍查看了一下请求头,发现就携带了三个东西,隐藏token,用户名,密码

一看一目了然,就一个后台页面,可想而知相对来说还是很简单,哈哈,下一步我只需要封装一下cookie,然后带上tocken,username,passwd去登陆咯

给大家说下,python的requests模块可以忽略cookie,自己创建一个session对象,他自己去给咱们匹配cookie,不用去挨个试cookie,这样就节省了好多代码和时间

2、代码如下

  1. class TbTomas(object):
  2. def __init__(self):
  3. # 配置初始化
  4. self.session_obj = requests.session()
  5.  
  6. def download_file(self,thomas_username,thomas_password,):
  7. hello_url = 'https://huoche.alitrip.com/hello.htm'
  8. # 获取原文
  9. hello_response = self.session_obj.get(hello_url)
  10. # 正则匹配原文
  11. h_u_s = re_search('<input type="hidden" id="h_u_s" name="h_u_s" value="(.*?)">', hello_response.text)
  12.  
  13. h_u_s = base64.b64encode(h_u_s)
  14. headers = {
  15. 'Accept': 'text/html, application/xhtml+xml, image/jxr, */*',
  16. 'Referer': 'https://huoche.alitrip.com/hello.htm',
  17. 'Accept-Language': 'zh-CN',
  18.  
  19. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586',
  20. 'Content-Type': 'application/x-www-form-urlencoded',
  21.  
  22. 'Accept-Encoding': 'gzip, deflate',
  23. 'Host': 'huoche.alitrip.com',
  24. 'Content-Length': '',
  25. 'Connection': 'Keep-Alive',
  26. 'Cache-Control': 'no-cache'
  27. }
  28.  
  29. post_data = {
  30. 'h_u_s': base64.b64encode(h_u_s),
  31. 'h_u_n': thomas_username,
  32. 'h_u_p': base64.b64encode(thomas_password)
  33. }
  34. index_url = 'https://huoche.alitrip.com/index.htm'
  35. index_response = self.session_obj.post(index_url, headers=headers, data=post_data)

最后一提交post请求,就可以判断有没有登录成功了,是不是很简单,哈哈!

数据下载

下载也是和登录是一样的道理,下载的时候肯定也是像网页发一个post请求,然后就回去下载exal文件咯,python有这么一个模块xlrd,可以去操作exal文件,非常方便

1、原文是让我们输入时间看,下载那一天的数据,领导给的任务是下载前一天的,所以上一天时间要写几行代码来实现

代码如下:

  1. today = datetime.datetime.now()
  2. yesterday = today + datetime.timedelta(days=-1)
  3. trade_date = yesterday.strftime('%Y-%m-%d')

2、查看下载文件请求的url,以及提交的数据,一张图一切都明白了

从图中可以看到,该文发送的url,请求方式,请求头,和返回的数据

3、模拟请求下载,只需用提交一下日期就OK搞定,文件下载完毕,接下开要读文件拿自己想要的东西啦

  1. post_data = {
  2. 'orderExportDate': trade_date
  3. }
  4. sheet_content = ""
  5. for _ in xrange(3):
  6. try:
  7. # 得到exal文件流
  8. download_response = self.session_obj.post(download_url, data=post_data)
  9. # 打开exal文件
  10. xls_content = xlrd.open_workbook(file_contents=download_response.content)
  11. sheet_content = xls_content.sheets()[0]
  12. break
  13. except Exception as e:
  14. continue

4、这个就众所周知,和读取文件一样,for循环一行一行读取,然后把订单号挨个添加给一个列表啥啦乱七八糟的

  1. order_item = []
  2. for line_num in range(sheet_content.nrows):
  3. line_item = sheet_content.row_values(line_num)
  4. if line_item[2]:
  5. order_item.append(line_item[2], ) # 订单号 order_no
  6. # 获取到所有订单号
  7. order_item = order_item[1:]

拿到订单号要去获取订单详情了,但是领导给我说这个已经有同事写好代码了,只需要调用那个接口就好,所以别人的代码我就不往上面展示了,原理很简单

requests模块,请求url,get传入订单号,发送请求,就可以返回数据咯,web页面展示,那个需求,每个公司都不一样,存入数据库,自己取自己想要的吧。

本文就到这里吧,学到一点东西的请点赞,哈哈

最后附带源码,用户名和密码就不告诉大家啦,啊哈哈

  1. #!/usr/bin/python
  2. # coding:utf-8
  3. import sys
  4. import os
  5. import django
  6.  
  7. reload(sys)
  8. sys.setdefaultencoding('utf8')
  9. sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # 把manage.py所在目录添加到系统目录
  10. os.environ['DJANGO_SETTINGS_MODULE'] = 'business.settings' # 设置setting文件
  11. django.setup() # 初始化Django环境
  12.  
  13. import requests
  14. import re
  15. import logging
  16. import base64
  17. import xlrd
  18. import datetime
  19. import time
  20. import MySQLdb
  21. import threadpool
  22. from business import settings
  23. from train.depends.platform import Platform
  24. from train.models import TbTomasOrder,TbTomasEpay,TtTicketThomas,TbTomasLinkman
  25. from train import utils
  26. from train.status import OrderStatus
  27. from django.core.mail import EmailMultiAlternatives
  28. from train.busi import insert_order,insert_ticket,insert_epay,insert_linkman
  29.  
  30. logger = logging.getLogger('django')
  31.  
  32. class TbTomas(object):
  33.  
  34. succ_number = 0
  35. fail_number = 0
  36. fail_order = []
  37. def __init__(self,thread_num = 3):
  38. # 配置初始化
  39. self.session_obj = requests.session()
  40. self.fail_order = []
  41. self.succ_number = 0
  42. self.fail_number = 0
  43. self.thread_num = thread_num
  44. self.start_date = ""
  45. self.end_date = ""
  46. self.trade_date = utils.now()
  47.  
  48. def login_thomas(self,thomas_username,thomas_password):
  49. hello_url = 'https://huoche.alitrip.com/hello.htm'
  50. hello_response = self.session_obj.get(hello_url)
  51. h_u_s = re_search('<input type="hidden" id="h_u_s" name="h_u_s" value="(.*?)">', hello_response.text)
  52. h_u_s = base64.b64encode(h_u_s)
  53. headers = {
  54. 'Accept': 'text/html, application/xhtml+xml, image/jxr, */*',
  55. 'Referer': 'https://huoche.alitrip.com/hello.htm',
  56. 'Accept-Language': 'zh-CN',
  57.  
  58. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586',
  59. 'Content-Type': 'application/x-www-form-urlencoded',
  60.  
  61. 'Accept-Encoding': 'gzip, deflate',
  62. 'Host': 'huoche.alitrip.com',
  63. 'Content-Length': '',
  64. 'Connection': 'Keep-Alive',
  65. 'Cache-Control': 'no-cache'
  66. }
  67.  
  68. post_data = {
  69. 'h_u_s': base64.b64encode(h_u_s),
  70. 'h_u_n': thomas_username,
  71. 'h_u_p': base64.b64encode(thomas_password)
  72. }
  73. index_url = 'https://huoche.alitrip.com/index.htm'
  74. index_response = self.session_obj.post(index_url, headers=headers, data=post_data)
  75. logger.info(u"登陆成功,等待下载文件...")
  76.  
  77. def download_file(self,thomas_username,thomas_password,args):
  78. for _ in xrange(3):
  79. try:
  80. self.login_thomas(thomas_username,thomas_password)
  81. break
  82. except Exception as e:
  83. logger.error(e)
  84. continue
  85.  
  86. # 处理时间
  87. all_time = self.date_time_handle(args)
  88. if not all_time:
  89. logger.error(u"日期格式错误!!")
  90. return
  91. for trade_date in all_time:
  92. try:
  93. self.trade_date = trade_date
  94. post_data = {
  95. 'orderExportDate': trade_date
  96. }
  97. download_url = 'https://huoche.alitrip.com/orderlistexp.do'
  98. sheet_content = ""
  99. for _ in xrange(3):
  100. try:
  101. # 得到exal文件流
  102. download_response = self.session_obj.post(download_url, data=post_data)
  103. # 打开exal文件
  104. xls_content = xlrd.open_workbook(file_contents=download_response.content)
  105. sheet_content = xls_content.sheets()[0]
  106. logger.info(u"下载文件成功,正在拿取订单号")
  107. break
  108. except Exception as e:
  109. logger.error(u"下载文件超时,正在等待重新登录后下载...")
  110. self.login_thomas(thomas_username, thomas_password)
  111. continue
  112. order_item = []
  113. if not sheet_content:
  114. logger.error(u'下载文件失败,正在重新登录...')
  115. continue
  116. for line_num in range(sheet_content.nrows):
  117. line_item = sheet_content.row_values(line_num)
  118. if line_item[2] and line_item[2] not in order_item:
  119. order_item.append(line_item[2], ) # 订单号 order_no
  120.  
  121. # 获取到所有订单号
  122. order_item = order_item[1:]
  123. # 根据订单号去拿订单详情
  124. logger.info(u"正在写入数据库")
  125.  
  126. # 多线程去执行
  127. pool = threadpool.ThreadPool(self.thread_num)
  128. reqs = threadpool.makeRequests(self.create_order_info, order_item)
  129. [pool.putRequest(req) for req in reqs]
  130. pool.wait()
  131. logger.info(u'写入完成,完成时间为:%s'% self.trade_date)
  132.  
  133. content = self.add_content(len(order_item), self.succ_number, self.fail_number, self.fail_order)
  134. self.send_mail(content=content)
  135. self.succ_number,self.fail_order = 0,0
  136. self.fail_order = []
  137. # self.create_order_info(order_item)
  138. except Exception as e:
  139. logger.error(e)
  140. def date_time_handle(self,args):
  141. all_time = []
  142. if args:
  143. if len(args) == 1:
  144. self.start_date = datetime.datetime.strptime(args[0], "%Y-%m-%d").date()
  145. self.end_date = datetime.datetime.strptime(datetime.datetime.now().strftime("%Y-%m-%d"), "%Y-%m-%d").date()
  146. elif len(args) == 2:
  147. self.start_date = datetime.datetime.strptime(args[0], "%Y-%m-%d").date()
  148. self.end_date = datetime.datetime.strptime(args[1], "%Y-%m-%d").date()
  149. elif len(args) == 3:
  150. self.start_date = datetime.datetime.strptime(args[0], "%Y-%m-%d").date()
  151. self.end_date = datetime.datetime.strptime(args[1], "%Y-%m-%d").date()
  152. self.thread_num = int(args[2])
  153. else:
  154. logger.error(u"传入参数错误,请重新执行")
  155. return
  156. i = 0
  157. while True:
  158. tomoary = self.start_date + datetime.timedelta(days=i)
  159. trade_date = tomoary.strftime('%Y-%m-%d')
  160. all_time.append(trade_date)
  161. i += 1
  162. if tomoary == self.end_date:
  163. break
  164. else:
  165. today = datetime.datetime.now()
  166. yesterday = today + datetime.timedelta(days=-1)
  167. trade_date = yesterday.strftime('%Y-%m-%d')
  168. all_time.append(trade_date)
  169. return all_time
  170.  
  171. def create_order_info(self, order):
  172. platform_obj = Platform()
  173.  
  174. order_info = platform_obj.get_order(order)
  175. if not order_info:
  176. self.fail_order.append(order)
  177. self.fail_number += 1
  178. logger.error('获取订单号:[%s]失败'%order)
  179. return
  180.  
  181. try:
  182. # 插入order表
  183. if TbTomasOrder.objects.filter(order_no=order).exists():
  184. logger.error('订单号:[%s]已经存在于TbTomasOrder'%order)
  185. self.fail_order.append(order)
  186. self.fail_number += 1
  187. return
  188. else:
  189. insert_order(order_info,order,self.trade_date)
  190. self.succ_number += 1
  191.  
  192. # 插入ticket表
  193. insert_ticket(order_info,order,self.trade_date)
  194.  
  195. # 插入联系人
  196. if TbTomasLinkman.objects.filter(order_no=order).exists():
  197. logger.error('订单号:[%s]已经存在于TbTomasLinkman'%order)
  198. else:
  199. insert_linkman(order_info,order,self.trade_date)
  200.  
  201. # 插入epay表
  202. if TbTomasEpay.objects.filter(order_no=order).exists():
  203. logger.error('订单号:[%s]已经存在于TbTomasEpay'%order)
  204. else:
  205. insert_epay(order_info,order,self.trade_date)
  206.  
  207. except Exception as e:
  208. logger.error(e)
  209. self.fail_number +=1
  210.  
  211. def add_content(self,total,succ_number,fail_number,fail_order):
  212. content = u'''
  213. <h3>托马斯导入订单报表</h3>
  214. <div class="col-xs-12">
  215. <table border="1" cellpadding="3" cellspacing="1">
  216. <tr>
  217. <td>日期</td>
  218. <td>总单数</td>
  219. <td>成功单数</td>
  220. <td>失败单数</td>
  221. <td>失败订单号</td>
  222. </tr>
  223. <tr>
  224. <td>%s</td>
  225. <td>%s</td>
  226. <td>%s</td>
  227. <td>%s</td>
  228. <td>%s</td>
  229. </tr>
  230. </table>
  231. </div>
  232. '''%(datetime.datetime.now().strftime("%Y-%m-%d %H:%M"),total,succ_number,fail_number,fail_order)
  233. return content
  234.  
  235. def send_mail(self, content):
  236. time_target = self.trade_date
  237. subject = u'托马斯数据抓取邮件 %s' % (time_target)
  238.  
  239. logger.info(u'准备发送邮件....%s', subject)
  240. mail_address = settings.mail_address_thomas
  241.  
  242. to_addr = []
  243.  
  244. if isinstance(mail_address, list):
  245. to_addr += mail_address
  246. elif isinstance(mail_address, str):
  247. to_addr.append(mail_address)
  248.  
  249. logger.debug(to_addr)
  250.  
  251. from_email = settings.DEFAULT_FROM_EMAIL
  252. msg = EmailMultiAlternatives(subject, 'result', from_email, to_addr)
  253. msg.attach_alternative(content, "text/html")
  254. flag = msg.send()
  255. if flag:
  256. logger.info(u'%s发送成功', subject)
  257. else:
  258. logger.error(u'%s发送失败', subject)
  259. return
  260.  
  261. def run(self, username,passwd,args):
  262. # 登陆托马斯后台
  263. for _ in xrange(3):
  264. try:
  265. self.download_file(username,passwd,args)
  266. break
  267. except Exception as e:
  268. logger.error(e)
  269. continue
  270.  
  271. def re_search(regex, subject):
  272. subject = str(subject)
  273. obj = re.compile(regex)
  274. match = obj.search(subject)
  275. if match:
  276. result = match.group(1)
  277. else:
  278. result = ''
  279. return result
  280.  
  281. def main():
  282. username = base64.b64decode(settings.THOMAS_USERNAME)
  283. passwd = base64.b64decode(settings.THOMAS_PASSWORD)
  284. args = sys.argv[1:] if sys.argv[1:] else ""
  285. TbTomas().run(username,passwd,args)
  286.  
  287. if __name__ == "__main__":
  288. main()

thread_code

python模拟登陆之下载的更多相关文章

  1. Python模拟登陆万能法-微博|知乎

    Python模拟登陆让不少人伤透脑筋,今天奉上一种万能登陆方法.你无须精通HTML,甚至也无须精通Python,但却能让你成功的进行模拟登陆.本文讲的是登陆所有网站的一种方法,并不局限于微博与知乎,仅 ...

  2. Python模拟登陆新浪微博

    上篇介绍了新浪微博的登陆过程,这节使用Python编写一个模拟登陆的程序.讲解与程序如下: 1.主函数(WeiboMain.py): import urllib2 import cookielib i ...

  3. Python模拟登陆TAPD

    因为在wiki中未找到需要的数据,查询也很迷,打算用python登录tapd抓取所需项目下的wiki数据,方便查找. 2018-9-30 19:12:44 几步走 模拟登录tapd 抓取wiki页左侧 ...

  4. Python模拟登陆淘宝并统计淘宝消费情况的代码实例分享

    Python模拟登陆淘宝并统计淘宝消费情况的代码实例分享 支付宝十年账单上的数字有点吓人,但它统计的项目太多,只是想看看到底单纯在淘宝上支出了多少,于是写了段脚本,统计任意时间段淘宝订单的消费情况,看 ...

  5. python模拟登陆知乎并爬取数据

    一些废话 看了一眼上一篇日志的时间 已然是5个月前的事情了 不禁感叹光阴荏苒其实就是我懒 几周前心血来潮想到用爬虫爬些东西 于是先后先重写了以前写过的求绩点代码 爬了草榴贴图,妹子图网,后来想爬婚恋网 ...

  6. python 模拟登陆,请求包含cookie信息

    需求: 1.通过GET方法,访问URL地址一,传入cookie参数 2.根据地址一返回的uuid,通过POST方法,传入cooki参数 实现思路: 1.理解http的GET和POST差别 (网上有很多 ...

  7. python模拟登陆豆瓣——简单方法

    学爬虫有一段时间了,前面没有总结又重装了系统,导致之前的代码和思考都没了..所以还是要及时整理总结备份.下面记录我模拟登陆豆瓣的方法,方法一登上了豆瓣,方法二重定向到了豆瓣中“我的喜欢”列表,获取了第 ...

  8. 使用python模拟登陆百度

    #!/usr/bin/python # -*- coding: utf- -*- """ Function: Used to demostrate how to use ...

  9. Python模拟登陆某网教师教育网

    本文转载自看雪论坛[作者]rdsnow 不得不说,最近的 Python 蛮火的,我也稍稍了解了下,并试着用 Python 爬取网站上的数据 不过有些数据是要登陆后才能获取的,我们每年都要到某教师教育网 ...

随机推荐

  1. sql server 查询表某个字段不重复数据

    SELECT TOP (500) ID, Personname, Personcode, Telphone, Fraction into temp3 FROM Records AS a WHERE ( ...

  2. Windows命令行下pip安装python whl包

    因为做网页爬虫,需要用到一个爬新闻的BeautifulSoup 的包,然后再关网上下的是whl包,第一次装,虽然花了点时间,最后还是装上去了,记录一下,方便下次. 先发一下官方文档地址.http:// ...

  3. 64位Win7下编译Python3的计算机视觉库:OpenCV

    注:本文全原创,作者:Noah Zhang  (http://www.cnblogs.com/noahzn/) OpenCV目前最新版是3.0.0 rc1,官方给出了编译好的Python2可以直接使用 ...

  4. [译]36 Days of Web Testing(二)

    Day 7: Http 和 Https Why? 当在网络上传输一些私人,敏感信息时,应该采用加密的手段来保证这些信息在传输的过程中不被侦测到.Https协议正是这种实现机制. Https是一种广泛使 ...

  5. JSON和XML的比较

    整理日: 2015/4/5 ◆可读性 JSON和XML的可读性可谓不相上下,一边是简易的语法,一边是规范的标签形式,很难分出胜负. ◆可扩展性 XML天生有很好的扩展性,JSON当然也有,没有什么是X ...

  6. ibatis动态的传入表名、字段名

    ibatis动态的传入表名.字段名,主要传入表名和字段名的不一致. Java代码: Map<String,Object> params = new HashMap<String,Ob ...

  7. QT事件过滤器(QT事件处理的5个层次:自己覆盖或过滤,父窗口过滤,Application过滤与通知)

    Qt事件模型一个真正强大的特色是一个QObject 的实例能够管理另一个QObject 实例的事件. 让我们试着设想已经有了一个CustomerInfoDialog的小部件.CustomerInfoD ...

  8. VARCHAR2字段关联

    SQL> create table a1(id int,name varchar2(10)); Table created. SQL> create table a2(id int,nam ...

  9. JavaScript高级程序设计8.pdf

    基本包装类型 为了便于操作基本类型值,ECMAScript定义了3个特殊的引用类型Boolean,Number和String.这些类型与本章介绍的其他用类型相似,同时也具备与各自的基本类型相应的特殊行 ...

  10. JavaScript高级程序设计5.pdf

    队列方法访问规则是FIFO(First-In-First-Out,先进先出),数组方法shift()能够移除数组中第一个项并返回该项,同时将数组长度减1,结合使用shift()和push(),可以像队 ...