Browse Source

增加余票监控

liuyuqi-dellpc 9 months ago
parent
commit
2b9a89445f

+ 27 - 0
.dockerignore

@@ -0,0 +1,27 @@
+**/__pycache__
+**/.venv
+**/.classpath
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.project
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/*.*proj.user
+**/*.dbmdl
+**/*.jfm
+**/bin
+**/charts
+**/docker-compose*
+**/compose*
+**/Dockerfile*
+**/node_modules
+**/npm-debug.log
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
+LICENSE
+README.md

+ 63 - 0
.gitignore

@@ -0,0 +1,63 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+env/
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.cache
+nosetests.xml
+coverage.xml
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+*.jpg
+*.png
+*.npy
+*.log
+*.npz
+*.pkl
+*.h5
+data/texts.txt

+ 19 - 0
.vscode/launch.json

@@ -0,0 +1,19 @@
+{
+    "configurations": [
+        {
+            "name": "Docker: Python - General",
+            "type": "docker",
+            "request": "launch",
+            "preLaunchTask": "docker-run: debug",
+            "python": {
+                "pathMappings": [
+                    {
+                        "localRoot": "${workspaceFolder}",
+                        "remoteRoot": "/app"
+                    }
+                ],
+                "projectType": "general"
+            }
+        }
+    ]
+}

+ 26 - 0
.vscode/tasks.json

@@ -0,0 +1,26 @@
+{
+	"version": "2.0.0",
+	"tasks": [
+		{
+			"type": "docker-build",
+			"label": "docker-build",
+			"platform": "python",
+			"dockerBuild": {
+				"tag": "fuck12306:latest",
+				"dockerfile": "${workspaceFolder}/Dockerfile",
+				"context": "${workspaceFolder}",
+				"pull": true
+			}
+		},
+		{
+			"type": "docker-run",
+			"label": "docker-run: debug",
+			"dependsOn": [
+				"docker-build"
+			],
+			"python": {
+				"file": "main.py"
+			}
+		}
+	]
+}

+ 23 - 0
Dockerfile

@@ -0,0 +1,23 @@
+# For more information, please refer to https://aka.ms/vscode-docker-python
+FROM python:3.10-slim
+
+# Keeps Python from generating .pyc files in the container
+ENV PYTHONDONTWRITEBYTECODE=1
+
+# Turns off buffering for easier container logging
+ENV PYTHONUNBUFFERED=1
+
+# Install pip requirements
+COPY requirements.txt .
+RUN python -m pip install -r requirements.txt
+
+WORKDIR /app
+COPY . /app
+
+# Creates a non-root user with an explicit UID and adds permission to access the /app folder
+# For more info, please refer to https://aka.ms/vscode-docker-python-configure-containers
+RUN adduser -u 5678 --disabled-password --gecos "" appuser && chown -R appuser /app
+USER appuser
+
+# During debugging, this entry point will be overridden. For more information, please refer to https://aka.ms/vscode-docker-python-debug
+CMD ["python", "main.py"]

+ 14 - 1
README.md

@@ -1,3 +1,16 @@
 # fuck12306
 
-12306 抢票
+12306 抢票助手
+
+## Develop
+
+打开 conf/config.ini 配置邮件提醒。
+
+监控余票,有余票时自动邮件推送:
+```
+    crawl12306=Crawl12306()
+    crawl12306.monitor()
+```
+
+## Licenses
+

+ 10 - 0
conf/config.ini

@@ -0,0 +1,10 @@
+[mail]
+host = smtp.qq.com
+user = xx@qq.com
+password = 12346
+sender = xx@qq.com
+receviers = xx@qq.com;xx@qq.com
+
+[db]
+db_port = 3307
+

+ 0 - 0
data/pic/.gitkeep


+ 11 - 0
docker-compose.debug.yml

@@ -0,0 +1,11 @@
+version: '3.4'
+
+services:
+  fuck12306:
+    image: fuck12306
+    build:
+      context: .
+      dockerfile: ./Dockerfile
+    command: ["sh", "-c", "pip install debugpy -t /tmp && python /tmp/debugpy --wait-for-client --listen 0.0.0.0:5678 main.py "]
+    ports:
+      - 5678:5678

+ 8 - 0
docker-compose.yml

@@ -0,0 +1,8 @@
+version: '3.4'
+
+services:
+  fuck12306:
+    image: fuck12306
+    build:
+      context: .
+      dockerfile: ./Dockerfile

+ 5 - 0
fuck12306/__init__.py

@@ -0,0 +1,5 @@
+
+from fuck12306.crawl_12306 import Crawl12306
+
+def main():
+    pass

+ 7 - 0
fuck12306/api.py

@@ -0,0 +1,7 @@
+
+
+# 验证码图片
+pic_url = "https://kyfw.12306.cn/otn/passcodeNew/getPassCodeNew?module=login&rand=sjrand&0.21191171556711197"
+
+# 余票查询接口
+remain = "https://kyfw.12306.cn/otn/leftTicket/queryA?leftTicketDTO.train_date=2018-09-30&leftTicketDTO.from_station=IZQ&leftTicketDTO.to_station=CBQ&purpose_codes=ADULT"

+ 10 - 5
crack_chapter.py → fuck12306/crack_chapter.py

@@ -1,14 +1,19 @@
-# coding: utf-8
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@Contact :   liuyuqi.gov@msn.cn
+@Time    :   2023/07/11 18:52:28
+@License :   Copyright © 2017-2022 liuyuqi. All Rights Reserved.
+@Desc    :  验证码识别 
+'''
+
 import sys
- 
 import cv2
 import numpy as np
 from keras import models
- 
 import pretreatment
 from mlearn_for_image import preprocess_input
- 
- 
+
 def get_text(img, offset=0):
     text = pretreatment.get_text(img, offset)
     text = cv2.cvtColor(text, cv2.COLOR_BGR2GRAY)

+ 105 - 0
fuck12306/crawl_12306.py

@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@Contact :   liuyuqi.gov@msn.cn
+@Time    :   2023/07/11 20:25:17
+@License :   Copyright © 2017-2022 liuyuqi. All Rights Reserved.
+@Desc    :   
+
+'''
+import argparse,time,json
+from email.mime.text import MIMEText
+from email.header import Header
+import os,sys,re,configparser,logging,requests
+import smtplib,random
+from fuck12306 import api
+
+class Crawl12306:
+    ''' 12306 抢票助手 '''
+    def __init__(self):
+        self.sess=requests.Session()
+        self.args=self.get_args()
+        self.conf=self.get_conf()
+
+    def get_conf(self)->dict:
+        ''' read config.ini and return a dict'''
+        cf = configparser.ConfigParser()
+        cf.read("conf/config.ini")
+        return cf
+    
+    def get_args(self):
+        parser=argparse.ArgumentParser(description='12306 抢票助手')
+        parser.add_argument('-d','--date',help='出发日期')
+        parser.add_argument('-f','--from',help='出发地')
+        parser.add_argument('-t','--to',help='目的地')
+        parser.add_argument('-m','--mail',help='接收通知的邮箱')
+        parser.add_argument('-c','--config',help='配置文件')
+        return parser.parse_args()
+
+    def get_code_pic(self, number=100):
+        ''' get code picture '''
+        print("............... get code  pic ...........")
+        for i in range(number):
+            res= self.sess.get(api.pic_url)
+            time.sleep(random.randint(3,5))
+            if res.status_code == 200:
+                with open("data/pic/pic_%s%s.png" % (int(time.time(),i),), "wb") as file:
+                        file.write(res.content)
+
+    # 监控余票
+    def monitor(self):
+        print("余票监控中...")
+        while True:
+            try:
+                res=self.sess.get(self.conf["url"]["left_ticket_url"])
+                if res.status_code == 200:
+                    j    = json.loads(r.text)
+                    k    = j['data']
+                    str1 = ""
+                    strData = ["G6305","D7501","G6325","D7521","D7533","D7529","D2381","G6337","D7525","G6321","D7513","G6313","G1607","G6309","D7533","D7517","G6329","D7505","G6345","G6341"]
+
+                    for r in k['result']:
+                        for cs in strData:
+                            if "|" + cs+"|" in r:
+                                if r.split('|')[-7] != '无': #二等座
+                                    str1 = str1 + cs + ',有票啦~~\n'
+                    if len(str1)>5:
+                        print(str1)
+                        self.send_mail(str1)
+
+
+                    sys.stdout.write('\r')
+                    sys.stdout.write('已查询%d次~' % self.num)
+                    sys.stdout.flush()
+                    self.num+=1
+                else:
+                    self.send_mail("获取车票信息失败~~")
+            except Exception as e:
+                pass
+            finally:
+                pass
+            time.sleep(5,10)
+            self.send_mail('有票了')
+
+    def send_mail(self,content:str):
+        message = MIMEText(content, 'plain', 'utf-8')
+        message['From'] = Header("肥肥", 'utf-8') 
+        message['To'] = Header("圆圆", 'utf-8')
+        message['Subject'] = Header("余票提醒", 'utf-8')
+        try:
+            smtpObj = smtplib.SMTP()
+            smtpObj.connect(self.conf["mail"]["host"], 25)  # 25 为 SMTP 端口号
+            smtpObj.login(self.conf["mail"]["user"], self.conf["mail"]["password"])
+            smtpObj.sendmail(self.conf["mail"]["sender"], self.conf["mail"]["receiver"], message.as_string())
+            print("邮件发送成功")
+        except Exception as e:
+            print("Error: 无法发送邮件")
+        finally:
+            pass
+
+    @staticmethod
+    def check_update():
+        ''' check application update '''
+        pass
+
+        

+ 1 - 15
fuck12306.py → fuck12306/fuck12306.py

@@ -1,17 +1,7 @@
-#!/usr/bin/python
-# #  FileName    : fuck12306.py
-# #  Author      : MaoMao Wang <andelf@gmail.com>
-# #  Created     : Mon Mar 16 22:08:41 2015 by ShuYu Wang
-# #  Copyright   : Feather (c) 2015
-# #  Description : fuck fuck 12306
-# #  Time-stamp: <2016-04-10 16:28:41 andelf>
 
 import re
-# hack CERTIFICATE_VERIFY_FAILED
-# https://github.com/mtschirs/quizduellapi/issues/2
 import ssl
 import urllib
-
 import requests
 from PIL import Image
 from PIL import ImageFilter
@@ -23,8 +13,8 @@ UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML,
 
 pic_url = "https://kyfw.12306.cn/otn/passcodeNew/getPassCodeNew?module=login&rand=sjrand&0.21191171556711197"
 
-
 def get_img():
+    ''' 获取验证码图片 '''
     resp = urllib.urlopen(pic_url)
     raw = resp.read()
     with open("./tmp.jpg", 'wb') as fp:
@@ -47,7 +37,6 @@ def get_sub_img(im, x, y):
 
 def baidu_image_upload(im):
     url = "http://image.baidu.com/pictureup/uploadshitu?fr=flash&fm=index&pos=upload"
-
     im.save("./query_temp_img.png")
     raw = open("./query_temp_img.png", 'rb').read()
 
@@ -105,7 +94,6 @@ def ocr_question_extract(im):
         return
     im = im.crop((127, 3, 260, 22))
     im = pre_ocr_processing(im)
-    # im.show()
     return pytesseract.image_to_string(im, lang='chi_sim').strip()
 
 
@@ -145,7 +133,6 @@ def binarize(im, thresh=120):
 
 if __name__ == '__main__':
     im = get_img()
-    # im = Image.open("./tmp.jpg")
     try:
         print
         'OCR Question:', ocr_question_extract(im)
@@ -155,6 +142,5 @@ if __name__ == '__main__':
     for y in range(2):
         for x in range(4):
             im2 = get_sub_img(im, x, y)
-
             result = baidu_stu_lookup(im2)
             print(y, x), result

+ 2 - 1
test.py → fuck12306/splinter_12306.py

@@ -12,7 +12,8 @@ from splinter.browser import Browser
 # options.add_experimental_option("excludeSwitches",["ignore-certificate-errors"])
 # driver = webdriver.Chrome(chrome_options=options)
 
-executable_path = {'executable_path': 'C:\Program Files (x86)\Google\Chrome\Application'}
+executable_path = {
+    'executable_path': 'C:/Program Files (x86)/Google/Chrome/Application'}
 
 username = u"979315539@qq.com"
 passwd = u""

+ 0 - 80
listen_12306.py

@@ -1,80 +0,0 @@
-#!/usr/bin/env python
-# -*- encoding: utf-8 -*-
-'''
-@Author  :   liuyuqi
-@Contact :   liuyuqi.gov@msn.cn
-@Time    :   2019/11/18 03:21:04
-@Version :   1.0
-@License :   (C)Copyright 2019
-@Desc    :   12306余票查询
-'''
-
-import requests
-import json
-import smtplib
-import sys
-import time
-from random import randint
-from email.mime.text import MIMEText
-from email.header import Header
-class tl12306:
-    def __init__(self):
-        self.num = 1
-        # 替换为你要查询的url地址
-        self.url = 'https://kyfw.12306.cn/otn/leftTicket/queryA?leftTicketDTO.train_date=2018-09-30&leftTicketDTO.from_station=IZQ&leftTicketDTO.to_station=CBQ&purpose_codes=ADULT'
-    def getlist(self):
-        try:
-            r = requests.get(self.url)
-            if r.status_code == 200:
-                j    = json.loads(r.text)
-                k    = j['data']
-                str1 = ""
-
-                strData = ["G6305","D7501","G6325","D7521","D7533","D7529","D2381","G6337","D7525","G6321","D7513","G6313","G1607","G6309","D7533","D7517","G6329","D7505","G6345","G6341"]
-
-                for r in k['result']:
-                    for cs in strData:
-                        if "|" + cs+"|" in r:
-                            if r.split('|')[-7] != '无': #二等座
-                                str1 = str1 + cs + ',有票啦~~\n'
-                if len(str1)>5:
-                    print(str1)
-                    self.send_mail(str1)
-
-
-                sys.stdout.write('\r')
-                sys.stdout.write('已查询%d次~' % self.num)
-                sys.stdout.flush()
-                self.num+=1
-            else:
-                msg = '获取车票信息失败~~'
-                print(msg)
-                self.send_mail(msg)
-        except Exception as e:
-            print(e)
-    def send_mail(self,str):
-        # 第三方 SMTP 服务
-        mail_host = "smtp.qq.com"  # 设置服务器
-        mail_user = "********@qq.com"  # 用户名 发送者的邮箱
-        mail_pass = "****************"  # 口令 登录邮箱开启POP3/SMTP服务,输入授权码
-        sender = '********@qq.com' #  发送者的邮箱
-        receivers = ['********@qq.com']  # 接收邮件,可设置为你的QQ邮箱或者其他邮箱
-        message = MIMEText(str, 'plain', 'utf-8')
-        message['From'] = Header("肥肥", 'utf-8') 
-        message['To'] = Header("圆圆", 'utf-8')
-        message['Subject'] = Header("余票提醒", 'utf-8')
-        try:
-            smtpObj = smtplib.SMTP()
-            smtpObj.connect(mail_host, 25)  # 25 为 SMTP 端口号
-            smtpObj.login(mail_user, mail_pass)
-            smtpObj.sendmail(sender, receivers, message.as_string())
-            print("邮件发送成功")
-        except smtplib.SMTPException:
-            print("Error: 无法发送邮件")
-
-if __name__ == '__main__':
-    c = tl12306()
-    print('监控中~')
-    while True:
-        c.getlist()
-        time.sleep(randint(5,10))

+ 17 - 0
main.py

@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@Contact :   liuyuqi.gov@msn.cn
+@Time    :   2023/07/11 20:26:23
+@License :   Copyright © 2017-2022 liuyuqi. All Rights Reserved.
+@Desc    :   
+'''
+
+import os,sys,re,argparse,logging
+from fuck12306 import Crawl12306
+
+if __name__=='__main__':
+    print("fuck12306")
+    crawl12306=Crawl12306()
+    # crawl12306.monitor()
+    crawl12306.get_code_pic(299)

+ 13 - 0
requirements.txt

@@ -0,0 +1,13 @@
+numpy
+python-opencv
+keras
+pretreatment
+mlearn_for_image
+requests
+sklearn
+opencv-python
+keras>=2.2.4
+tensorflow
+matplotlib>=3.0.2
+numpy>=1.14.6
+scipy>=1.1.0

+ 46 - 0
test/conf.py

@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+'''
+@Contact :   liuyuqi.gov@msn.cn
+@Time    :   2023/07/11 20:18:28
+@License :   Copyright © 2017-2022 liuyuqi. All Rights Reserved.
+@Desc    :   read and write config.ini
+'''
+import os,sys,re,configparser
+
+file_path = "../conf/config.ini"
+
+def write():
+    cf = configparser.ConfigParser()
+    cf.read(file_path)
+    if not cf.has_section("mail"):
+        cf.add_section("mail")
+    cf.set("mail", "host", "smtp.qq.com")
+    cf.set("mail", "user", "xx@qq.com")
+    cf.set("mail", "password", "12346")
+    cf.set("mail", "sender", "xx@qq.com")
+    cf.set("mail", "receviers", "xx@qq.com;xx@qq.com")
+
+    if not cf.has_section("db"):
+        cf.add_section("db")
+    cf.set("db", "db_port", "3307")
+    cf.write(open(file_path, "w"))
+
+    if not cf.has_section("account"):
+        cf.add_section("account")
+    cf.set("account", "db_port", "3307")
+    cf.write(open(file_path, "w"))
+
+def read():
+    cf = configparser.ConfigParser()
+    cf.read(file_path)
+    opt_val = cf.get("db", "db_port")
+    print(opt_val)
+    kvs = cf.items("db")
+    print(kvs)
+
+if __name__=='__main__':
+    # read()
+    import time
+    # 打印时间戳,整形
+    print(int(time.time()))

+ 0 - 20
test2.py

@@ -1,20 +0,0 @@
-# coding: utf-8
-'''
-Created on 2016年9月9日
-@author: liuyuqi
-'''
-from splinter.browser import Browser
-
-executable_path = {
-    'executable_path': 'C:/Program Files (x86)/Google/Chrome/Application'}
-
-username = u"979315539@qq.com"
-passwd = u""
-ticket_url = "https://kyfw.12306.cn/otn/leftTicket/init"
-login_url = "https://kyfw.12306.cn/otn/login/init"
-initmy_url = "https://kyfw.12306.cn/otn/index/initMy12306"
-
-chromedriver = "C:/Program Files (x86)/Google/Chrome/Application/chromedriver.exe"
-
-b = Browser()
-b.visit("http://www.qq.com")