侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

解决Python3 抓取微信账单信息问题

Python  /  管理员 发布于 7年前   240

这段时间有个朋友想导出微信里面的账单信息,后来发现微信的反爬虫还是很厉害的,花了点时间去分析。

一、采用传统模拟http抓取

抓取的主要URL:https://wx.tenpay.com/userroll/userrolllist,其中后面带上三个参数,具体参数见代码,其中exportkey这参数是会过期的,userroll_encryption和userroll_pass_ticket 这两个参数需要从cookie中获得,应该是作为获取数据的标识,通过抓包也看不出端倪,应该是微信程序内部生成的,如果使用微信开发着工具登录后直接访问网址有的时候可以访问返回数据,但是只是在较短的时间内有效,而且当返回会话超时后,继续使用网页访问就会被限制,一直提示会话超时,应该是在网页和移动端中exportkey有不同的时间和访问次数的限制。

之后想通过破解seesion的方式,研究了一下,发现这是不可能的,想要破解session需要搞定wx.login,而wx.login是微信提供的,想要破解难度应该不用我说了。

二、解决exportkey 这个key和Cookie的获取

需要的工具:

1、安卓/苹果手机

2、Fiddler(抓包工具)

搞过爬虫的都知道Fiddler,具体操作就不多说了,设置好代理和开启Fiddler后,抓取url中的exportkey和相应的Cookie,用于接下来的数据抓取。

三、上代码

代码写的不是很好,若有错误还望各位大大指正。

# coding:utf-8import datetimeimport timeimport urllibimport urllib.requestimport jsonimport sysimport ioimport sslfrom DBController import DBController   #数据库#设置系统编码格式sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='gb18030')#解决访问Https时不受信任SSL证书问题ssl._create_default_https_context = ssl._create_unverified_contextclass MainCode:  def __init__(self, url=""):    self.url = url    self.dbController = DBController() # 数据库控制    self.userroll_encryption = "uoxQXsCenowxj0G0ppRKBg8iHRPZwZKaUZB0ka1Y5apUuQnKkZTsA/2RMhBPGyMdiHS8QXk8y2JeLgqTPqZPU9fkrCUp+TIQPkHH/uExAwKeBFLute0ztdHaC6GJUJ2+/R8NGWGe16hSKc6L1+LvAw=="    self.userroll_pass_ticket = "V7oum4glDbdaAwibC8mcuTizGIKmC9A/Y/V12qASuDALdRMveHcRHv1QXamFk27Z"    # self.last_bill_id = ""    # self.last_bill_type = ""    # self.last_create_time = ""    # self.last_trans_id = ""    self.last_item = {}    self.num= 0  #获取网页信息  def get_html(self, url, maxTryNum=5):    goon = True # 网络中断标记    obj = {}    for tryNum in range(maxTryNum):      try:        # print(self.token)        header = {          "Accept": 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',          "Accept-Encoding":'gzip, deflate, br',          "Accept-Language":'zh-CN,zh;q=0.8',          "Cache-Control":'max-age=0',          "Connection": "keep-alive",          "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 10_2 like Mac OS X) AppleWebKit/602.3.12 (KHTML, like Gecko) Mobile/14C92 Safari/601.1 wechatdevtools/1.02.1810240 MicroMessenger/6.5.7 Language/zh_CN webview/15415760070117398 webdebugger port/32594",          "Cookie":"userroll_encryption="+self.userroll_encryption+"; userroll_pass_ticket="+self.userroll_pass_ticket,          "Host":"wx.tenpay.com",          "Upgrade-Insecure-Requests":"1",        }        req = urllib.request.Request(url=url, headers=header)        # 访问网址        result = urllib.request.urlopen(req, timeout=5).read()        break      except urllib.error.HTTPError as e:        if tryNum < (maxTryNum - 1):          print("尝试连接请求" + str(tryNum + 1))          # host = self.host2          time.sleep(5)        else:          print('Internet Connect Error!', "Error URL:" + url)          goon = False          break    if goon:      page = result.decode('utf-8')      obj = json.loads(page)      #print(obj)      #print(page)    else:      print("--------------------------")    return obj  #保存到数据库  def save_info_to_db(self, item):    select_sql = "SELECT count(*)as num FROM wx_order2 where trans_id = '%s'" % (item["trans_id"])    results = self.dbController.ExecuteSQL_Select(select_sql)    if int(results[0][0]) == 0:      sql = "INSERT INTO wx_order2 (bill_id, bill_type, classify_type, fee, fee_type, out_trade_no, pay_bank_name, payer_remark, remark, order_time, title, total_refund_fee, trans_id,fee_attr) VALUES ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s','%s','%s')" % (        str(item['bill_id']),        str(item['bill_type']),        str(item['classify_type']),        str(item['fee']),        str(item['fee_type']) ,        str(item['out_trade_no']),        str(item['pay_bank_name']),        str(item['payer_remark']),        str(item['remark']),        str(item['order_time']),        str(item['title']),        str(item['total_refund_fee']),        str(item['trans_id']),        str(item['fee_attr'])      )      # print(sql)      try:        self.dbController.ExecuteSQL_Insert(sql)        # self.log.info("插入数据成功")      except Exception as e:        print("save_info_to_db:",e)    return  #从获取的网页信息中过滤所需要的信息  def get_data(self,url):    res_obj = self.get_html(url)    this_page_num = 0    #若返回的ret_code== 0 则说明获取数据成功    if res_obj['ret_code'] == 0:      record_list = res_obj['record']      self.last_bill_id = res_obj['last_bill_id']      self.last_bill_type = res_obj['last_bill_type']      self.last_create_time = res_obj['last_create_time']      self.last_trans_id = res_obj['last_trans_id']      num = 1      this_page_num = len(record_list)      #  order = record_list[i]      for order in record_list:        bill_id = order['bill_id']        bill_type = order['bill_type']        classify_type = order['classify_type']        fee = order['fee'] #账单金额        fee = fee * 0.01        fee = round(fee, 2) #对金额保留两位小数        fee_type = order['fee_type'] #金额类型        out_trade_no = order['out_trade_no'] #账单编号        pay_bank_name = order['pay_bank_name'] #支付的银行        payer_remark =order['payer_remark'] #支付说明        remark = order['remark'] #账单说明        order_time = datetime.datetime.fromtimestamp(order['timestamp']) #将时间戳转为时间        title = order['title'] #账单标题        title = title.replace(',','').replace('.','').replace("'",'') #去除英文逗号和单引号        total_refund_fee = "0"        trans_id = order['trans_id']        fee_attr = order['fee_attr']        #title = self.remove_emoji(title)        fee_attr = order['fee_attr']        pay_type = ""        if bill_type == 1:          pay_type= "支付"        elif bill_type == 2:          pay_type = "充值"        elif bill_type == 4:          pay_type = "转账"        elif bill_type == 6:          pay_type="红包"        else:          pay_type = str(bill_type)        if fee_attr == "positive":          fee_attr = "收入"        elif fee_attr == "negtive":          fee_attr = "支出"        elif fee_attr == "neutral":          fee_attr = "提现"        item = {}        item['bill_id'] = bill_id        item['bill_type'] =bill_type        item['classify_type'] = classify_type        item['fee'] = fee        item['fee_type'] = fee_type        item['out_trade_no'] = out_trade_no        item['pay_bank_name'] = pay_bank_name        item['payer_remark'] = payer_remark        item['remark'] = remark        item['order_time'] = order_time        item['title'] = title        item['total_refund_fee'] = total_refund_fee        item['trans_id'] = trans_id        item['fee_attr'] = fee_attr        # title = self.remove_emoji(title)        if bill_id != '':          self.last_item['last_bill_id'] = bill_id        self.last_item['last_bill_type'] = bill_type        self.last_item['last_create_time'] = order['timestamp']        self.last_item['last_trans_id'] = trans_id        try:          print(str(self.num),self.last_item,end='\n')          self.num += 1          time.sleep(0.2)          self.save_info_to_db(item)          #print(str(num)+" 时间:" + str(order_time) + " 账单标题:" + title + " 说明:"+ str(remark)+ "  " +str(pay_type) +"金额:" + str(fee) + "  支付方式:"+ str(pay_bank_name)+"  类型:" + str(pay_type) +" fee_attr:"+str(fee_attr)+ '\n',end='')        except Exception as e:          print(e,end='\n')        num = num+1    else:#若获取数据不成功,打印原因      print(res_obj)    return this_page_num#实例化maincode = MainCode();#设置Cookie参数maincode.userroll_encryption = "6Ow68aKrAz70mEczqeevA2gOXbr9H2a7+2ite6uuyWFdB6j1+SLhlaCNpYA6RjmaOI7IfCi9PXjQsrZPFIs1SMn38Uxr04GJsxMuSO/9wG+eBFLute0ztdHaC6GJUJ2+vmo+JIw351su8RiFxSagwA=="maincode.userroll_pass_ticket = "i0Co+55KSEjmFjfFZqMG14hasW4qtKFtbj0FiErcSzHY0afkFqHGib3YfsAZWcaG"#用于非第一页的数据抓取#maincode.last_item['last_bill_id'] = "2ce3d65b20a10700b2048d68"#maincode.last_item['last_bill_type'] = "4"#maincode.last_item['last_create_time'] = "1540809516"#maincode.last_item['last_trans_id'] = "1000050201201810290100731805325"#设置每次返回的数量count = "20"#exportkey 需要从Fiddler 抓包获取,有一定的时间限制exportkey ="A%2BsIJaTGZksgZWPLtSKiyos%3D"#抓取的URLurl ="https://wx.tenpay.com/userroll/userrolllist?classify_type=0&count="+count+"&exportkey="+exportkey+"&sort_type=1"for page in range(0,10):  #记录当前页返回的数据数量  this_page_num = 0  #第一页  if page == 0:    this_page_num = maincode.get_data(url)  #从第二页开始需要增加上一页最后一个item的部分参数,进行下一页的数据的抓取  else:    url = "https://wx.tenpay.com/userroll/userrolllist?classify_type=0&count="+count+"&exportkey="+exportkey+"&sort_type=1"+"&last_bill_id="+str(maincode.last_item['last_bill_id'])+"&last_bill_type="+str(maincode.last_item['last_bill_type'])+"&last_create_time="+str(maincode.last_item['last_create_time'])+"&last_trans_id="+str(maincode.last_item['last_trans_id'] + "&start_time="+str(maincode.last_item['last_create_time']))    print(url)    this_page_num = maincode.get_data(url)  #如果数量少于20个则跳出循环,抓取结束  if this_page_num < 20:    break  time.sleep(0.5)print(maincode.last_item)

因为是帮朋友抓取的,能实现就可以了。之后若有需要再继续优化代码吧!

总结

以上所述是小编给大家介绍的Python3 抓取微信账单信息,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!


  • 上一条:
    python中将两组数据放在一起按照某一固定顺序shuffle的实例
    下一条:
    python中列表的切片与修改知识点总结
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客