画布 1
main.py
  jd_seckill = JdSeckill()
  jd_seckill.reserve()
  jd_seckill.seckill_by_proc_pool()
  jd_spider_requests.py
    SpiderSession类
      __init__方法
        self.cookies_dir_path = "./cookies/"
        self.user_agent = global_config.getRaw('config', 'DEFAULT_USER_AGENT')
          得到config.ini中[config]下定义的DEFAULT_USER_AGENT对应的值赋值给user_agent
        self.session = self._init_session()
      __init__session方法
        session = requests.session()
          实例化一个session，为之后使用它做http请求准备
        session.headers = self.get_headers()
          为session添加请求头
        return session
      get_headers方法
        return {"User-Agent": self.user_agent,
"Accept": "balabala****bala",
"Connection": "keep-alive"}
          这里的user_agent使用的就是上面2号标记的user_agent
      get_user_agent方法
      get_session方法
        return self.session
      get_cookies方法
        return self.get_session().cookies
      set_cookies方法
      load_cookies_from_local方法
        cookies_file = ''
if not os.path.exists(self.cookies_dir_path):
return False
        for name in os.listdir(self.cookies_dir_path):
if name.endswith(".cookies"):
cookies_file = '{}{}'.format(self.cookies_dir_path, name)
break
        if cookies_file == '':
return False
        with open(cookies_file, 'rb') as f:
local_cookies = pickle.load(f)
        self.set_cookies(local_cookies)
      save_cookies_to_local方法
        os.makedirs(directory)
          创建目录./cookies/
        pickle.dump(self.get_cookies(), f)
          将cookie保存到文件，文件名为传入的sickname
      session相关操作
    QrLogin类
      __init__方法
        self.qrcode_img_file = 'qr_code.png'
        self.spider_session = spider_session
        self.session = self.spider_session.get_session()
          创建一个session对象
        self.is_login = False
        self.refresh_login_status()
      refresh_login_status方法
        self.is_login = self._validate_cookies()
      _validate_cookies方法
        验证cookies是否有效（是否登陆）
通过访问用户订单列表页进行判断：若未登录，将会重定向到登陆页面。若登陆self.is_login=True
若登陆返回True，没有登陆返回False
        url = 'https://order.jd.com/center/list.action'
payload = {
'rid': str(int(time.time() * 1000)),
}
        resp = self.session.get(url=url, params=payload, allow_redirects=False)
if resp.status_code == requests.codes.OK:
return True
return False
      _get_login_page方法
        url = "https://passport.jd.com/new/login.aspx"
page = self.session.get(url, headers=self.spider_session.get_headers())
return page
      _get_qrcode方法
        if not response_status(resp):
logger.info('获取二维码失败')
return False
        save_image(resp, self.qrcode_img_file)
          下载登录二维码并保存在本地
        open_image(self.qrcode_img_file)
        return True
      _get_qrcode_ticket方法
        url = 'https://qr.m.jd.com/check'
payload = {****balabala****
}
headers = {****balabala****
}
        resp = self.session.get(url=url, headers=headers, params=payload)
        resp_json = parse_json(resp.text)
        return resp_json['ticket']
          调用util.py中的resp_json函数进行处理，并取ticket key对应的值
      _validate_qrcode_ticket方法
        url = 'https://passport.jd.com/uc/qrCodeTicketValidation'
headers = {
'User-Agent': ****,
'Referer': ****
}
        resp = self.session.get(url=url, headers=headers, params={'t': ticket})
        resp_json = json.loads(resp.text)
if resp_json['returnCode'] == 0:
return True
          验证ticket是否可用，可用返回True
      login_by_qrcode方法
        self._get_login_page()
          获取登录首页信息
        if not self._get_qrcode():
raise SKException('二维码下载失败')
        ticket = self._get_qrcode_ticket()
if ticket:
break
          如果得到票据，则退出循环
        if not self._validate_qrcode_ticket(ticket):
raise SKException('二维码信息校验失败')
        self.refresh_login_status()
      扫码登陆
    JdSeckill类
      __init__方法
        self.spider_session = SpiderSession()
        self.spider_session.load_cookies_from_local()
          因为第一次初始化过程中之定义了cookies_dir_path的值而没有创建这个目录所以返回值为False,执行第3步
        self.qrlogin = QrLogin(self.spider_session)
          得到上面判断的是否已经登陆的True或False
        self.sku_id = global_config.getRaw('config', 'sku_id')
          得到茅台商品id
        self.session = self.spider_session.get_session()
          给jd_seckill添加session对象
        self.user_agent = self.spider_session.user_agent
          给新建的session对象添加user_agent
并且main.py中的jd_seckill = JdSeckill()执行结束
接着根据用户的输入选择执行jd_seckill.reserve()或者jd_seckill.seckill_by_proc_pool()
      login_by_qrcode方法
        if self.qrlogin.is_login:
logger.info('登录成功')
return
        self.qrlogin.login_by_qrcode()
        if self.qrlogin.is_login:
self.nick_name = self.get_username()
        self.spider_session.save_cookies_to_local(self.nick_name)
      check_login方法
        if not self.qrlogin.is_login:
logger.info("{0} 需登陆后调用，开始扫码登陆".format(func.__name__))
self.login_by_qrcode()
        func(self, *args, **kwargs)
          执行使用了check_login的func
      @check_login
reserve方法
        self._reserve()
      @check_login
seckill方法
        self._seckill()
      @check_login
seckill_by_proc_pool方法
        with ProcessPoolExecutor(work_count) as pool:
for i in range(work_count):
pool.submit(self.seckill)
          5个进程同步执行
      _reserve方法
        self.make_reserve()
          url='https://yushou.jd.com/youshouinfo.action?'
payload = {****balabala****}
headers = {****balabala****}
resp = self.session.get(url=url, params=payload, headers=headers)
resp_json = parse_json(resp.text)
reserve_url = resp_json.get('url')
            得到预约请求url-->reserve_url
          self.timers.start()
            预约执行时间
          while True:
try:
self.session.get(url='https:' + reserve_url)
            无限循环执行预约指令，需要手动结束control+c
      _seckill方法
        self.request_seckill_url()
        self.request_seckill_checkout_page()
        self.submit_seckill_order()
        wait_some_time()
          util.py中对应函数，暂停0.1-0.3秒，继续抢购秒杀
        不停循环执行，手动暂停
      make_reserve方法
        url = 'https://yushou.jd.com/youshouinfo.action?'
payload = { ****balabala****}
headers = {****balabala**** }
        resp = self.session.get(url=url, params=payload, headers=headers)
resp_json = parse_json(resp.text)
reserve_url = resp_json.get('url')
          得到预约url
        self.timers.start()
        while True:
try:
self.session.get(url='https:' + reserve_url)
          不停进行预约
      get_username方法
        url = 'https://passport.jd.com/user/petName/getUserInfoForMiniJd.action'
resp = self.session.get(url=url, params=payload, headers=headers)
        parse_json(resp.text).get('nickName')
      get_sku_title方法
      get_seckill_url方法
        url = 'https://itemko.jd.com/itemShowBtn'
payload = {****balabala****}
headers = {****balabala**** }
resp = self.session.get(url=url, headers=headers, params=payload)
resp_json = parse_json(resp.text)
        if resp_json.get('url'):
router_url = 'https:' + resp_json.get('url')
seckill_url = router_url.replace(
'divide', 'marathon').replace(
'user_routing', 'captcha.html')
return seckill_url
        获取点击抢购按钮后的url
      request_seckill_url方法
        self.timers.start()
          设置的抢购时间到点或超过自动执行，否者一直等待
        self.seckill_url[self.sku_id] = self.get_seckill_url()
        self.session.get(
url=self.seckill_url.get(
self.sku_id),
headers=headers,
allow_redirects=False)
          获取第二次跳转页面
      request_seckill_checkout_page方法
        url = 'https://marathon.jd.com/seckill/seckill.action'
payload = {****balabala****}
headers = {****balabala****}}
self.session.get(url=url, params=payload, headers=headers, allow_redirects=False)
        获取提交订单页面
      _get_seckill_init_info方法
        url = 'https://marathon.jd.com/seckillnew/orderService/pc/init.action'
data={****balabala****}
headers={****balabala****}
resp = self.session.post(url=url, data=data, headers=headers)
resp_json = parse_json(resp.text)
return resp_json
      _get_seckill_order_data方法
        self.seckill_init_info[self.sku_id] = self._get_seckill_init_info()
init_info = self.seckill_init_info.get(self.sku_id)
default_address = init_info['addressList'][0]
invoice_info = init_info.get('invoiceInfo', {})
token = init_info['token']
data={****balabala****}
return data
        获取订单数据并返回数据
      submit_seckill_order方法
        url = 'https://marathon.jd.com/seckillnew/orderService/pc/submitOrder.action'
payload = {'skuId': self.sku_id,}
        self.seckill_order_data[self.sku_id] = self._get_seckill_order_data()
        resp = self.session.post(
url=url,
params=payload,
data=self.seckill_order_data.get(
self.sku_id),
headers=headers)
        resp_json = parse_json(resp.text)
if resp_json.get('success'):
order_id = resp_json.get('orderId')
total_money = resp_json.get('totalMoney')
pay_url = 'https:' + resp_json.get('pcUrl')
logger.info('抢购成功，订单号:{}, 总价:{}, 电脑端付款链接:{}'.format(order_id, total_money, pay_url))
  config.py
    Config类
      __init__方法
        self._path = os.path.join(os.getcwd(), config_file)
        self._config = configparser.ConfigParser()
        self._config.read(self._path, encoding='utf-8-sig')
        self._configRaw = configparser.RawConfigParser()
        self._configRaw.read(self._path, encoding='utf-8-sig')
      get方法
        self._config.get(section, name)
      getRaw方法
        self._configRaw.get(section, name)
    global_config = Config()
  util.py
    parse_json函数
      begin = s.find('{')
end = s.rfind('}') + 1
return json.loads(s[begin:end])
      将传进来的json对象转换成
python dict对象
    get_random_useragent函数
    wait_some_time函数
    send_wechat函数
    response_status函数
      if resp.status_code != requests.codes.OK:
print('Status: %u, Url: %s' % (resp.status_code, resp.url))
return False
return True
    open_image函数
      os.system('start ' + image_file)
      os.system("deepin-image-viewer " + image_file)
      os.system("eog " + image_file)
      os.system("open " + image_file)
      打开二维码图片，不同系统调用的指令不一样
    save_image函数
      with open(image_file, 'wb') as f:
for chunk in resp.iter_content(chunk_size=1024):
f.write(chunk)
  timer.py
    Timer类
      __init__方法
        self.buy_time = datetime.strptime(global_config.getRaw('config','buy_time'), "%Y-%m-%d %H:%M:%S.%f")
          将设定时间转换成struct_time格式
        self.buy_time_ms = int(time.mktime(self.buy_time.timetuple()) * 1000.0 + self.buy_time.microsecond / 1000)
          将设定的购买时间设定为至1970年1月1日00:00:00起到现在经历的毫秒数
        self.sleep_interval = sleep_interval
        self.diff_time = self.local_jd_time_diff()
          得到和京东服务器的时间差
      jd_time方法
        url='https://a.jd.com//ajax/queryServerData.html'
ret = requests.get(url).text
js = json.loads(ret)
return int(js["serverTime"])
      local_time方法
        return int(round(time.time() * 1000))
      local_jd_time_diff方法
        return self.local_time() - self.jd_time()
      start方法
        while True:
if self.local_time() - self.diff_time >= self.buy_time_ms:
logger.info('时间到达，开始执行……')
break
else:
time.sleep(self.sleep_interval)
        根据设定的抢购时间执行命令
  jd_logger.py
    set_logger函数
  exception.py
    SKException类
      __init__方法