forked from yangfabing/own_jd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
jd_OpenCard.py
1297 lines (1215 loc) · 52 KB
/
jd_OpenCard.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/bin/env python3
# -*- coding: utf-8 -*
'''
项目名称: JD_OpenCard
Author: Curtin
功能:JD入会开卡领取京豆
CreateDate: 2021/5/4 下午1:47
UpdateTime: 2021/6/19
'''
version = 'v1.2.2'
readmes = """
# JD入会领豆小程序
![JD入会领豆小程序](https://raw.githubusercontent.com/curtinlv/JD-Script/main/OpenCrad/resultCount.png)
## 使用方法
#### [手机用户(参考) https://mp.weixin.qq.com/s/ih6aOURXWM-iKrhvMyR3mw](https://mp.weixin.qq.com/s/ih6aOURXWM-iKrhvMyR3mw)
#### [PC用户 (参考) https://mp.weixin.qq.com/s/JmLxAecZAlEc4L2sZWnn1A](https://mp.weixin.qq.com/s/JmLxAecZAlEc4L2sZWnn1A)
#### [v4-bot用户 (参考) https://github.com/curtinlv/JD-Script/pull/12#issue-652134788](https://github.com/curtinlv/JD-Script/pull/12#issue-652134788)
## 目录结构
JD-Script/ #仓库
|-- LICENSE
|-- OpenCard # 主目录
| |-- jd_OpenCard.py # 主代码 (必要)
| |-- log # 临时目录(可删除)
| |-- OpenCardConfig.ini # 只配置文件(必要)
| |-- Readme.md # 说明书
| `-- start.sh # shell脚本(非必要)
`-- README.md
log目录结构、临时目录(可删除):
log
├── memory.json # 记忆、统计功能临时存放参数
├── shopid-2021-05-23.txt # 记录所有送豆的shopid
├── 入会N豆以上的shopid-2021-05-23.txt # 记录满足入会条件的shopid
├── 入会汇总.txt # 记录所有入会店铺送豆的加入、注销链接
├── 可退会账号【账号id】.txt # 记录跑脚本之前已经过入会且目前送豆的注销链接(可优先退会)
### `【兼容环境】`
1.Python3.3+ 环境
2.兼容ios设备软件:Pythonista 3、Pyto(已测试正常跑,其他软件自行测试)
3.Windows exe
安装依赖模块 :
pip3 install requests
执行:
python3 jd_OpenCard.py
start.sh 脚本运行方法:
1.适合定时任务或不想依赖ini配置文件。
2.支持单号跑多开,如
cp start.sh start_2.sh
sh start_2.sh #只跑里面配置的参数,如cookie
3.定时任务(参考):
0 8 * * * sh /home/curtin/JD-Script/OpenCard/start.sh
2 8 * * * sh /home/curtin/JD-Script/OpenCard/start_2.sh
## `【更新记录】`
2021.6.19: (v1.2.2)
* 修复多线程报错
2021.6.14: (v1.2.1)
* 新增单双线程控制
* 修复一些问题,如腾讯云跑异常报错。
2021.5.28:(v1.2.0)
* 新增单或多账号并发
- Concurrent=yes #开启
* 新增企业微信、Bark推送
* 优化一些逻辑
- 如随机账号查询礼包,仅开启单账号时候
- 京豆统计
2021.5.23:(v1.1.1)
* 修复一些问题及优化一些代码
* 修复Env环境读取变量问题
* 新增 start.sh 运行脚本(可Env环境使用)
- 运行方式 sh start.sh
2021.5.21:(v1.1.0)
* 修复一些问题及优化一些代码:
- 修复最后统计显示为0,新增开卡个数统计
- 修复记忆功能一些bug
- 等等一些小问题
* 新增机器人通知
- 开启远程shopid、配合crontab 坐等收豆
2021.5.15:(v1.0.5)
* 新增远程获取shopid功能
- isRemoteSid=yes #开启
* 修改已知Bug
2021.5.9:(v1.0.4 Beta)
* 优化代码逻辑
* 打包exe版本测试
2021.5.8:(v1.0.3)
* 优化记忆功能逻辑:
- cookiek个数检测
- shopid个数检测
- 上一次中断最后记录的账号id检测不存在本次ck里面
- 临时文件log/memory.json是否存在
- 以上任意一条命中则记忆接力功能不生效。
2021.5.7:(v1.0.2)
* 优化代码逻辑
* 修复已知Bug
2021.5.5:(v1.0.1)
* 新增记忆功能,如中断后下次跑会接着力跑(默认开启)
- memory= True
* 新增仅记录shopid,不入会功能(默认关闭)
- onlyRecord = no
* 修复已知Bug
2021.5.4:(v1.0.0)
* 支持多账号
- JD_COOKIE=pt_key=xxx;pt_pin=xxx;&pt_key=xxx;pt_pin=xxx; #多账号&分隔
* 限制京豆数量入会,例如只入50豆以上
- openCardBean = 50
* 双线程运行
- 默认开启,且您没得选择。
* 记录满足条件的shopid 【record= True】默认开启 (./log 目录可删除)
- log/可销卡汇总.txt #记录开卡送豆的店铺销卡链接
- log/shopid-yyyy-mm-dd.txt #记录当天所有入会送豆的shopid
- log/可销卡账号xxx.txt #记录账号可销卡的店铺
### `【账号参数配置说明】`
### 主配置文件[ OpenCardConfig.ini ] 请保持utf-8默认格式
变量 | 值 | 说明
---- | ----- | ------
JD_COOKIE | pt_key=xxx;pt_pin=xxx; | 必要(多账号&分隔)
openCardBean | 30 | int,入会送豆满足此值,否则不入会
record | False或True | 布尔值,是否记录符合条件的shopid(默认True)
onlyRecord | False或True |布尔值, True:仅记录,不入会(默认False)
memory | False或True | 布尔值,开启记忆功能,接力上一次异常中断位置继续。(默认yes)
printlog | False或True | 布尔值,True:只打印部分日志 False:打印所有日志
sleepNum | False或True | Float,限制速度,单位秒,如果请求过快报错适当调整0.5秒以上
isRemoteSid | False或True | 布尔值,True:使用作者远程仓库更新的id,False:使用本地shopid.txt的id
#### 兼容Env环境(如有配置则优先使用,适合AC、云服务环境等)
export JD_COOKIE='pt_key=xxx;pt_pin=xxx;' (多账号&分隔)
export openCardBean=30
export xxx=xxx
#### Ps:您可以到以下途径获取最新的shopid.txt,定期更新:
###### [GitHub仓库 https://github.com/curtinlv/JD-Script](https://github.com/curtinlv/JD-Script)
###### [Gitee仓库 https://gitee.com/curtinlv/JD-Script](https://gitee.com/curtinlv/JD-Script)
###### [TG频道 https://t.me/TopStyle2021](https://t.me/TopStyle2021)
###### [TG群 https://t.me/topStyle996](https://t.me/topStyle996)
###### 关注公众号【TopStyle】回复:shopid
![TopStyle](https://gitee.com/curtinlv/img/raw/master/gzhcode.jpg)
#
@Last Version: %s
@Last Time: 2021-06-19 13:55
@Author: Curtin
#### **仅以学习交流为主,请勿商业用途、禁止违反国家法律 ,转载请留个名字,谢谢!**
# End.
[回到顶部](#readme)
""" % version
################################ 【Main】################################
import time, os, sys, datetime
import requests
import random, string
import re, json, base64
from urllib.parse import unquote, quote_plus
from threading import Thread
from configparser import RawConfigParser
# 定义一些要用到参数
requests.packages.urllib3.disable_warnings()
scriptHeader = """
════════════════════════════════════════
║ ║
║ JD 入 会 领 豆 ║
║ ║
════════════════════════════════════════
@Version: {}""".format(version)
remarks = '\n\n\tTG交流 : https://t.me/topstyle996\n\n\tTG频道 : https://t.me/TopStyle2021\n\n\t公众号 : TopStyle\n\n\t\t\t--By Curtin\n'
timestamp = int(round(time.time() * 1000))
today = datetime.datetime.now().strftime('%Y-%m-%d')
# 获取当前工作目录
pwd = os.path.dirname(os.path.abspath(__file__)) + os.sep
######
openCardBean = 0
sleepNum = 0.0
record = True
onlyRecord = False
memory = True
printlog = True
isRemoteSid = True
Concurrent = True
TG_BOT_TOKEN = ''
TG_USER_ID = ''
PUSH_PLUS_TOKEN = ''
TG_PROXY_IP = ''
TG_PROXY_PORT = ''
TG_API_HOST = ''
QYWX_AM = ''
BARK = ''
DoubleThread = True
# 获取账号参数
try:
configinfo = RawConfigParser()
try:
configinfo.read(pwd + "OpenCardConfig.ini", encoding="UTF-8")
except Exception as e:
with open(pwd + "OpenCardConfig.ini", "r", encoding="UTF-8") as config:
getConfig = config.read().encode('utf-8').decode('utf-8-sig')
with open(pwd + "OpenCardConfig.ini", "w", encoding="UTF-8") as config:
config.write(getConfig)
try:
configinfo.read(pwd + "OpenCardConfig.ini", encoding="UTF-8")
except:
configinfo.read(pwd + "OpenCardConfig.ini", encoding="gbk")
cookies = configinfo.get('main', 'JD_COOKIE')
openCardBean = configinfo.getint('main', 'openCardBean')
sleepNum = configinfo.getfloat('main', 'sleepNum')
record = configinfo.getboolean('main', 'record')
onlyRecord = configinfo.getboolean('main', 'onlyRecord')
memory = configinfo.getboolean('main', 'memory')
printlog = configinfo.getboolean('main', 'printlog')
isRemoteSid = configinfo.getboolean('main', 'isRemoteSid')
TG_BOT_TOKEN = configinfo.get('main', 'TG_BOT_TOKEN')
TG_USER_ID = configinfo.get('main', 'TG_USER_ID')
PUSH_PLUS_TOKEN = configinfo.get('main', 'PUSH_PLUS_TOKEN')
TG_PROXY_IP = configinfo.get('main', 'TG_PROXY_IP')
TG_PROXY_PORT = configinfo.get('main', 'TG_PROXY_PORT')
TG_API_HOST = configinfo.get('main', 'TG_API_HOST')
QYWX_AM = configinfo.get('main', 'QYWX_AM')
Concurrent = configinfo.getboolean('main', 'Concurrent')
DoubleThread = configinfo.getboolean('main', 'DoubleThread')
BARK = configinfo.get('main', 'BARK')
except Exception as e:
OpenCardConfigLabel = 1
print("参数配置有误,请检查OpenCardConfig.ini\nError:", e)
print("尝试从Env环境获取!")
def getBool(label):
try:
if label == 'True' or label == 'yes' or label == 'true' or label == 'Yes':
return True
elif label == 'False' or label == 'no' or label == 'false' or label == 'No':
return False
else:
return True
except Exception as e:
print(e)
# 获取系统ENV环境参数优先使用 适合Ac、云服务等环境
# JD_COOKIE=cookie (多账号&分隔)
if "JD_COOKIE" in os.environ:
if len(os.environ["JD_COOKIE"]) > 10:
cookies = os.environ["JD_COOKIE"]
print("已获取并使用Env环境 Cookie")
# 只入送豆数量大于此值
if "openCardBean" in os.environ:
if len(os.environ["openCardBean"]) > 0:
openCardBean = int(os.environ["openCardBean"])
print("已获取并使用Env环境 openCardBean:", openCardBean)
elif not openCardBean:
openCardBean = 0
# 是否开启双线程
if "DoubleThread" in os.environ:
if len(os.environ["DoubleThread"]) > 1:
DoubleThread = getBool(os.environ["DoubleThread"])
print("已获取并使用Env环境 DoubleThread", DoubleThread)
# 多账号并发
if "Concurrent" in os.environ:
if len(os.environ["Concurrent"]) > 1:
Concurrent = getBool(os.environ["Concurrent"])
print("已获取并使用Env环境 Concurrent", Concurrent)
elif not Concurrent:
Concurrent = True
# 限制速度,单位秒,如果请求过快报错适当调整0.5秒以上
if "sleepNum" in os.environ:
if len(os.environ["sleepNum"]) > 0:
sleepNum = float(os.environ["sleepNum"])
print("已获取并使用Env环境 sleepNum:", sleepNum)
elif not sleepNum:
sleepNum = 0
if "printlog" in os.environ:
if len(os.environ["printlog"]) > 1:
printlog = getBool(os.environ["printlog"])
print("已获取并使用Env环境 printlog:", printlog)
elif not printlog:
printlog = True
# 是否记录符合条件的shopid,输出文件【OpenCardlog/yes_shopid.txt】 False|True
if "record" in os.environ:
if len(os.environ["record"]) > 1:
record = getBool(os.environ["record"])
print("已获取并使用Env环境 record:", record)
elif not record:
record = True
# 仅记录,不入会。入会有豆的shopid输出文件
if "onlyRecord" in os.environ:
if len(os.environ["onlyRecord"]) > 1:
onlyRecord = getBool(os.environ["onlyRecord"])
print("已获取并使用Env环境 onlyRecord:", onlyRecord)
elif not onlyRecord:
onlyRecord = False
# 开启记忆, 需要record=True且 memory= True 才生效
if "memory" in os.environ:
if len(os.environ["memory"]) > 1:
memory = getBool(os.environ["memory"])
print("已获取并使用Env环境 memory:", memory)
elif not memory:
memory = True
# 是否启用远程shopid
if "isRemoteSid" in os.environ:
if len(os.environ["isRemoteSid"]) > 1:
isRemoteSid = getBool(os.environ["isRemoteSid"])
print("已获取并使用Env环境 isRemoteSid:", isRemoteSid)
elif not isRemoteSid:
isRemoteSid = True
# 获取TG_BOT_TOKEN
if "TG_BOT_TOKEN" in os.environ:
if len(os.environ["TG_BOT_TOKEN"]) > 1:
TG_BOT_TOKEN = os.environ["TG_BOT_TOKEN"]
print("已获取并使用Env环境 TG_BOT_TOKEN")
# 获取TG_USER_ID
if "TG_USER_ID" in os.environ:
if len(os.environ["TG_USER_ID"]) > 1:
TG_USER_ID = os.environ["TG_USER_ID"]
print("已获取并使用Env环境 TG_USER_ID")
# 获取代理ip
if "TG_PROXY_IP" in os.environ:
if len(os.environ["TG_PROXY_IP"]) > 1:
TG_PROXY_IP = os.environ["TG_PROXY_IP"]
print("已获取并使用Env环境 TG_PROXY_IP")
# 获取TG 代理端口
if "TG_PROXY_PORT" in os.environ:
if len(os.environ["TG_PROXY_PORT"]) > 1:
TG_PROXY_PORT = os.environ["TG_PROXY_PORT"]
print("已获取并使用Env环境 TG_PROXY_PORT")
elif not TG_PROXY_PORT:
TG_PROXY_PORT = ''
# 获取TG TG_API_HOST
if "TG_API_HOST" in os.environ:
if len(os.environ["TG_API_HOST"]) > 1:
TG_API_HOST = os.environ["TG_API_HOST"]
print("已获取并使用Env环境 TG_API_HOST")
# 获取pushplus+ PUSH_PLUS_TOKEN
if "PUSH_PLUS_TOKEN" in os.environ:
if len(os.environ["PUSH_PLUS_TOKEN"]) > 1:
PUSH_PLUS_TOKEN = os.environ["PUSH_PLUS_TOKEN"]
print("已获取并使用Env环境 PUSH_PLUS_TOKEN")
# 获取企业微信应用推送 QYWX_AM
if "QYWX_AM" in os.environ:
if len(os.environ["QYWX_AM"]) > 1:
QYWX_AM = os.environ["QYWX_AM"]
print("已获取并使用Env环境 QYWX_AM")
# 获取企业微信应用推送 QYWX_AM
if "BARK" in os.environ:
if len(os.environ["BARK"]) > 1:
BARK = os.environ["BARK"]
print("已获取并使用Env环境 BARK")
# 判断参数是否存在
try:
cookies
except NameError as e:
var_exists = False
print("[OpenCardConfig.ini] 和 [Env环境] 都无法获取到您的cookies,请配置!\nError:", e)
time.sleep(60)
exit(1)
else:
var_exists = True
# 创建临时目录
if not os.path.exists(pwd + "log"):
os.mkdir(pwd + "log")
# 记录功能json
memoryJson = {}
message_info = ''
notify_mode = []
################################### Function ################################
class TaskThread(Thread):
"""
处理task相关的线程类
"""
def __init__(self, func, args=()):
super(TaskThread, self).__init__()
self.func = func # 要执行的task类型
self.args = args # 要传入的参数
def run(self):
self.result = self.func(*self.args) # 将任务执行结果赋值给self.result变量
def get_result(self):
# 改方法返回task函数的执行结果,方法名不是非要get_result
try:
return self.result
except Exception as ex:
print(ex)
return "ERROR"
def nowtime():
return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
def printinfo(context, label: bool):
if label == False:
print(context)
def exitCodeFun(code):
try:
if sys.platform == 'win32' or sys.platform == 'cygwin':
print("连按回车键即可退出窗口!")
exitCode = input()
exit(code)
except:
time.sleep(3)
exit(code)
def message(str_msg):
global message_info
print(str_msg)
message_info = "{}\n{}".format(message_info, str_msg)
sys.stdout.flush()
# 获取通知,
if PUSH_PLUS_TOKEN:
notify_mode.append('pushplus')
if TG_BOT_TOKEN and TG_USER_ID:
notify_mode.append('telegram_bot')
if QYWX_AM:
notify_mode.append('wecom_app')
if BARK:
notify_mode.append('bark')
# tg通知
def telegram_bot(title, content):
try:
print("\n")
bot_token = TG_BOT_TOKEN
user_id = TG_USER_ID
if not bot_token or not user_id:
print("tg服务的bot_token或者user_id未设置!!\n取消推送")
return
print("tg服务启动")
if TG_API_HOST:
url = f"{TG_API_HOST}/bot{TG_BOT_TOKEN}/sendMessage"
else:
url = f"https://api.telegram.org/bot{TG_BOT_TOKEN}/sendMessage"
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
payload = {'chat_id': str(TG_USER_ID), 'text': f'{title}\n\n{content}', 'disable_web_page_preview': 'true'}
proxies = None
if TG_PROXY_IP and TG_PROXY_PORT:
proxyStr = "http://{}:{}".format(TG_PROXY_IP, TG_PROXY_PORT)
proxies = {"http": proxyStr, "https": proxyStr}
try:
response = requests.post(url=url, headers=headers, params=payload, proxies=proxies).json()
except:
print('推送失败!')
if response['ok']:
print('推送成功!')
else:
print('推送失败!')
except Exception as e:
print(e)
# push推送
def pushplus_bot(title, content):
try:
print("\n")
if not PUSH_PLUS_TOKEN:
print("PUSHPLUS服务的token未设置!!\n取消推送")
return
print("PUSHPLUS服务启动")
url = 'http://www.pushplus.plus/send'
data = {
"token": PUSH_PLUS_TOKEN,
"title": title,
"content": content
}
body = json.dumps(data).encode(encoding='utf-8')
headers = {'Content-Type': 'application/json'}
response = requests.post(url=url, data=body, headers=headers).json()
if response['code'] == 200:
print('推送成功!')
else:
print('推送失败!')
except Exception as e:
print(e)
# BARK
def bark_push(title, content):
print("\n")
if not BARK:
print("bark服务的bark_token未设置!!\n取消推送")
return
print("bark服务启动")
try:
response = requests.get('''https://api.day.app/{0}/{1}/{2}'''.format(BARK, title, quote_plus(content))).json()
if response['code'] == 200:
print('推送成功!')
else:
print('推送失败!')
except Exception as e:
print(e)
print('Bark推送失败!')
def send(title, content):
"""
使用 bark, telegram bot, dingding bot, serverJ 发送手机推送
:param title:
:param content:
:return:
"""
content = content + "\n\n" + footer
for i in notify_mode:
if i == 'telegram_bot':
if TG_BOT_TOKEN and TG_USER_ID:
telegram_bot(title=title, content=content)
else:
print('未启用 telegram机器人')
continue
elif i == 'pushplus':
if PUSH_PLUS_TOKEN:
pushplus_bot(title=title, content=content)
else:
print('未启用 PUSHPLUS机器人')
continue
elif i == 'wecom_app':
if QYWX_AM:
wecom_app(title=title, content=content)
else:
print('未启用企业微信应用消息推送')
continue
elif i == 'bark':
if BARK:
bark_push(title=title, content=content)
else:
print('未启用Bark APP应用消息推送')
continue
else:
print('此类推送方式不存在')
# 企业微信 APP 推送
def wecom_app(title, content):
try:
if not QYWX_AM:
print("QYWX_AM 并未设置!!\n取消推送")
return
QYWX_AM_AY = re.split(',', QYWX_AM)
if 4 < len(QYWX_AM_AY) > 5:
print("QYWX_AM 设置错误!!\n取消推送")
return
corpid = QYWX_AM_AY[0]
corpsecret = QYWX_AM_AY[1]
touser = QYWX_AM_AY[2]
agentid = QYWX_AM_AY[3]
try:
media_id = QYWX_AM_AY[4]
except:
media_id = ''
wx = WeCom(corpid, corpsecret, agentid)
# 如果没有配置 media_id 默认就以 text 方式发送
if not media_id:
message = title + '\n\n' + content
response = wx.send_text(message, touser)
else:
response = wx.send_mpnews(title, content, media_id, touser)
if response == 'ok':
print('推送成功!')
else:
print('推送失败!错误信息如下:\n', response)
except Exception as e:
print(e)
class WeCom:
def __init__(self, corpid, corpsecret, agentid):
self.CORPID = corpid
self.CORPSECRET = corpsecret
self.AGENTID = agentid
def get_access_token(self):
url = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken'
values = {'corpid': self.CORPID,
'corpsecret': self.CORPSECRET,
}
req = requests.post(url, params=values)
data = json.loads(req.text)
return data["access_token"]
def send_text(self, message, touser="@all"):
send_url = 'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=' + self.get_access_token()
send_values = {
"touser": touser,
"msgtype": "text",
"agentid": self.AGENTID,
"text": {
"content": message
},
"safe": "0"
}
send_msges = (bytes(json.dumps(send_values), 'utf-8'))
respone = requests.post(send_url, send_msges)
respone = respone.json()
return respone["errmsg"]
def send_mpnews(self, title, message, media_id, touser="@all"):
send_url = 'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=' + self.get_access_token()
send_values = {
"touser": touser,
"msgtype": "mpnews",
"agentid": self.AGENTID,
"mpnews": {
"articles": [
{
"title": title,
"thumb_media_id": media_id,
"author": "Author",
"content_source_url": "",
"content": message.replace('\n', '<br/>'),
"digest": message
}
]
}
}
send_msges = (bytes(json.dumps(send_values), 'utf-8'))
respone = requests.post(send_url, send_msges)
respone = respone.json()
return respone["errmsg"]
# 检测cookie格式是否正确
def iscookie():
"""
:return: cookiesList,userNameList,pinNameList
"""
cookiesList = []
userNameList = []
pinNameList = []
if 'pt_key=' in cookies and 'pt_pin=' in cookies:
r = re.compile(r"pt_key=.*?pt_pin=.*?;", re.M | re.S | re.I)
result = r.findall(cookies)
if len(result) >= 1:
message("您已配置{}个账号".format(len(result)))
u = 1
for i in result:
r = re.compile(r"pt_pin=(.*?);")
pinName = r.findall(i)
pinName = unquote(pinName[0])
# 获取账号名
ck, nickname = getUserInfo(i, pinName, u)
if nickname != False:
cookiesList.append(ck)
userNameList.append(nickname)
pinNameList.append(pinName)
else:
u += 1
continue
u += 1
if len(cookiesList) > 0 and len(userNameList) > 0:
return cookiesList, userNameList, pinNameList
else:
message("没有可用Cookie,已退出")
exitCodeFun(3)
else:
message("cookie 格式错误!...本次操作已退出")
exitCodeFun(4)
else:
message("cookie 格式错误!...本次操作已退出")
exitCodeFun(4)
# 检查是否有更新版本
def gettext(url):
try:
resp = requests.get(url, timeout=60).text
if '该内容无法显示' in resp:
return gettext(url)
return resp
except Exception as e:
print(e)
def isUpdate():
global footer, readme1, readme2, readme3, uPversion
url = base64.decodebytes(
b"aHR0cHM6Ly9naXRlZS5jb20vY3VydGlubHYvUHVibGljL3Jhdy9tYXN0ZXIvT3BlbkNhcmQvdXBkYXRlLmpzb24=")
try:
result = gettext(url)
result = json.loads(result)
isEnable = result['isEnable']
uPversion = result['version']
info = result['info']
readme1 = result['readme1']
readme2 = result['readme2']
readme3 = result['readme3']
pError = result['m']
footer = result['footer']
getWait = result['s']
if isEnable > 50 and isEnable < 150:
if version != uPversion:
print(f"\n当前最新版本:【{uPversion}】\n\n{info}\n")
message(f"{readme1}{readme2}{readme3}")
time.sleep(getWait)
else:
message(f"{readme1}{readme2}{readme3}")
time.sleep(getWait)
else:
print(pError)
time.sleep(300)
exit(666)
except:
message("请检查您的环境/版本是否正常!")
time.sleep(10)
exit(666)
def getUserInfo(ck, pinName, userNum):
url = 'https://me-api.jd.com/user_new/info/GetJDUserInfoUnion?orgFlag=JD_PinGou_New&callSource=mainorder&channel=4&isHomewhite=0&sceneval=2&sceneval=2&callback=GetJDUserInfoUnion'
headers = {
'Cookie': ck,
'Accept': '*/*',
'Connection': 'close',
'Referer': 'https://home.m.jd.com/myJd/home.action',
'Accept-Encoding': 'gzip, deflate, br',
'Host': 'me-api.jd.com',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.2 Mobile/15E148 Safari/604.1',
'Accept-Language': 'zh-cn'
}
try:
resp = requests.get(url=url, verify=False, headers=headers, timeout=60).text
r = re.compile(r'GetJDUserInfoUnion.*?\((.*?)\)')
result = r.findall(resp)
userInfo = json.loads(result[0])
nickname = userInfo['data']['userInfo']['baseInfo']['nickname']
return ck, nickname
except Exception:
context = f"账号{userNum}【{pinName}】Cookie 已失效!请重新获取。"
message(context)
send("【JD入会领豆】Cookie 已失效!", context)
return ck, False
# 设置Headers
def setHeaders(cookie, intype):
if intype == 'mall':
headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Host": "mall.jd.com",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.2 Safari/605.1.15",
"Accept-Language": "zh-cn",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "close"
}
return headers
elif intype == 'JDApp':
headers = {
'Cookie': cookie,
'Accept': "*/*",
'Connection': "close",
'Referer': "https://shopmember.m.jd.com/shopcard/?",
'Accept-Encoding': "gzip, deflate, br",
'Host': "api.m.jd.com",
'User-Agent': "jdapp;iPhone;9.4.8;14.3;809409cbd5bb8a0fa8fff41378c1afe91b8075ad;network/wifi;ADID/201EDE7F-5111-49E8-9F0D-CCF9677CD6FE;supportApplePay/0;hasUPPay/0;hasOCPay/0;model/iPhone13,4;addressid/;supportBestPay/0;appBuild/167629;jdSupportDarkMode/0;Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1",
'Accept-Language': "zh-cn"
}
return headers
elif intype == 'mh5':
headers = {
'Cookie': cookie,
'Accept': "*/*",
'Connection': "close",
'Referer': "https://shopmember.m.jd.com/shopcard/?",
'Accept-Encoding': "gzip, deflate, br",
'Host': "api.m.jd.com",
'User-Agent': "Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1",
'Accept-Language': "zh-cn"
}
return headers
# 记录符合件的shopid到本地文件保存 当前目录:OpenCardlog/shopid-yyyy-mm-dd.txt 或 log-yyyy-mm-dd.txt
def outfile(filename, context, iscover):
"""
:param filename: 文件名 默认txt格式
:param context: 写入内容
:param iscover: 是否覆盖 False or True
:return:
"""
if record == True:
try:
if iscover == False:
with open(pwd + "log/{0}".format(filename), "a+", encoding="utf-8") as f1:
f1.write("{}\n".format(context))
f1.close()
elif iscover == True:
with open(pwd + "{0}".format(filename), "w+", encoding="utf-8") as f1:
f1.write("{}".format(context))
f1.close()
except Exception as e:
print(e)
# 记忆功能 默认双线程
def memoryFun(startNum, threadNum, usernameLabel, username, getallbean, userCount):
global memoryJson
if memory == True:
if usernameLabel == True:
memoryJson['allShopidNum'] = endShopidNum
memoryJson['currUser{}'.format(threadNum)] = username
memoryJson['t{}_startNum'.format(threadNum)] = startNum
memoryJson['allUserCount'] = userCount
if usernameLabel == False:
try:
memoryJson['{}'.format(username)]
memoryJson['{}'.format(username)] += getallbean
except:
memoryJson['{}'.format(username)] = getallbean
try:
memoryJson['{}_ok'.format(username)]
memoryJson['{}_ok'.format(username)] += 1
except:
memoryJson['{}_ok'.format(username)] = 1
try:
if os.path.exists(pwd + "log"):
with open(pwd + "log/memory.json", "w+", encoding="utf-8") as f:
json.dump(memoryJson, f, indent=4)
else:
pass
except Exception as e:
print(e)
# 修复记忆功能一些问题,如记录累计京豆统计显示为0等
def isMemoryEnable():
global memoryJson
memoryJson = getMemory()
# 获取记忆配置
def getMemory():
"""
:return: memoryJson
"""
if os.path.exists(pwd + "log/memory.json"):
with open(pwd + "log/memory.json", "r", encoding="utf-8") as f:
memoryJson = json.load(f)
if len(memoryJson) > 0:
return memoryJson
else:
pass
def rmCount():
if os.path.exists(pwd + "log/入会汇总.txt"):
os.remove(pwd + "log/入会汇总.txt")
if os.path.exists(pwd + "log/memory.json"):
os.remove(pwd + "log/memory.json")
# 判断是否启用记忆功能
def isMemory(memorylabel, startNum1, startNum2, midNum, endNum, pinNameList):
"""
:param memorylabel: 记忆标签
:param startNum1: 线程1默认开始位置
:param startNum2: 线程2默认开始位置
:param midNum: 线程1默认结束位置
:param endNum: 线程2默认结束位置
:return: startNum1, startNum2, memorylabel
"""
if memory == True and memorylabel == 0:
try:
memoryJson = getMemory()
if memoryJson['allShopidNum'] == endNum:
currUserLabel = 0
if memoryJson['allUserCount'] == allUserCount:
for u in pinNameList:
if memoryJson['currUser1'] == u:
currUserLabel += 1
elif memoryJson['currUser2'] == u:
currUserLabel += 1
if memoryJson['currUser1'] == memoryJson['currUser2']:
currUserLabel = 2
if currUserLabel < 2:
print("通知:检测到您配置的CK有变更,本次记忆功能不生效。")
rmCount()
return startNum1, startNum2, memorylabel
if memoryJson['t1_startNum'] + 1 == midNum and memoryJson['t2_startNum'] + 1 == endNum:
print(
f"\n上次已完成所有shopid,\n\nPs:您可以关注公众号或TG频道获取最新shopid。\n公众号: TopStyle\n电报TG:https://t.me/TopStyle2021\n\n请输入 0 或 1\n0 : 退出。\n1 : 重新跑一次,以防有漏")
try:
getyourNum = int(input("正在等待您的选择:"))
if getyourNum == 1:
print("Ok,那就重新跑一次~")
rmCount()
memorylabel = 1
return startNum1, startNum2, memorylabel
elif getyourNum == 0:
print("Ok,已退出~")
time.sleep(10)
exit(0)
except:
# print("Error: 您的输入有误!已退出。")
exitCodeFun(3)
else:
isMemoryEnable()
if memoryJson['t1_startNum']:
startNum1 = memoryJson['t1_startNum']
message(f"已启用记忆功能 memory= True,线程1从第【{startNum1}】店铺开始")
if memoryJson['t2_startNum']:
startNum2 = memoryJson['t2_startNum']
message(f"已启用记忆功能 memory= True,线程2从第【{startNum2}】店铺开始")
memorylabel = 1
return startNum1, startNum2, memorylabel
else:
message("通知:检测到您配置的CK有变更,本次记忆功能不生效。")
rmCount()
return startNum1, startNum2, memorylabel
else:
message("通知:检测到shopid有更新,本次记忆功能不生效。")
rmCount()
memorylabel = 1
return startNum1, startNum2, memorylabel
except Exception as e:
memorylabel = 1
return startNum1, startNum2, memorylabel
else:
rmCount()
memorylabel = 1
return startNum1, startNum2, memorylabel
# 获取VenderId
def getVenderId(shopId, headers):
"""
:param shopId:
:param headers
:return: venderId
"""
url = 'https://mall.jd.com/index-{0}.html'.format(shopId)
resp = requests.get(url=url, verify=False, headers=headers, timeout=60)
resulttext = resp.text
r = re.compile(r'shopId=\d+&id=(\d+)"')
venderId = r.findall(resulttext)
return venderId[0]
# 查询礼包
def getShopOpenCardInfo(venderId, headers, shopid, userName, user_num):
"""
:param venderId:
:param headers:
:return: activityId,getBean 或 返回 0:没豆 1:有豆已是会员 2:记录模式(不入会)
"""
num1 = string.digits
v_num1 = ''.join(random.sample(["1", "2", "3", "4", "5", "6", "7", "8", "9"], 1)) + ''.join(
random.sample(num1, 4)) # 随机生成一窜4位数字
url = 'https://api.m.jd.com/client.action?appid=jd_shop_member&functionId=getShopOpenCardInfo&body=%7B%22venderId%22%3A%22{2}%22%2C%22channel%22%3A406%7D&client=H5&clientVersion=9.2.0&uuid=&jsonp=jsonp_{0}_{1}'.format(
timestamp, v_num1, venderId)
resp = requests.get(url=url, verify=False, headers=headers, timeout=60)
time.sleep(sleepNum)
resulttxt = resp.text
r = re.compile(r'jsonp_.*?\((.*?)\)\;', re.M | re.S | re.I)
result = r.findall(resulttxt)
cardInfo = json.loads(result[0])
venderCardName = cardInfo['result']['shopMemberCardInfo']['venderCardName'] # 店铺名称
if user_num == 1:
printinfo(f"\t└查询入会礼包【{venderCardName}】", printlog)
openCardStatus = cardInfo['result']['userInfo']['openCardStatus'] # 是否会员
interestsRuleList = cardInfo['result']['interestsRuleList']
if interestsRuleList == None:
if user_num == 1:
printinfo("\t\t└查询该店入会没有送豆,不入会", printlog)
return 0, 0
try:
if len(interestsRuleList) > 0:
for i in interestsRuleList:
if "京豆" in i['prizeName']:
getBean = int(i['discountString'])
activityId = i['interestsInfo']['activityId']
context = "{0}".format(shopid)
outfile(f"shopid-{today}.txt", context, False) # 记录所有送豆的shopid
in_url = 'https://shop.m.jd.com/?shopId={}'.format(shopid)
url = 'https://shopmember.m.jd.com/member/memberCloseAccount?venderId={}'.format(venderId)
context = "[{0}]:入会{2}豆店铺【{1}】\n\t加入会员:{4}\n\t解绑会员:{3}".format(nowtime(), venderCardName, getBean,
url, in_url) # 记录
if user_num == 1:
outfile("入会汇总.txt", context, False)
if getBean >= openCardBean: # 判断豆是否符合您的需求
print(f"\t└账号{user_num}【{userName}】{venderCardName}:入会赠送【{getBean}豆】,可入会")
context = "{0}".format(shopid)
outfile(f"入会{openCardBean}豆以上的shopid-{today}.txt", context, False)
if onlyRecord == True:
if user_num == 1:
print("已开启仅记录,不入会。")
return 2, 2
if openCardStatus == 1:
url = 'https://shopmember.m.jd.com/member/memberCloseAccount?venderId={}'.format(venderId)
print("\t\t└[账号:{0}]:您已经是本店会员,请注销会员卡24小时后再来~\n注销链接:{1}".format(userName, url))
context = "[{3}]:入会{1}豆,{0}销卡:{2}".format(venderCardName, getBean, url, nowtime())
outfile("可退会账号【{0}】.txt".format(userName), context, False)
return 1, 1