├── .gitignore
├── 0001
└── verification_code_generator.py
├── 0002
└── counter.py
├── 0003
└── codestat.py
├── 0004
└── MIS.py
├── 0005
└── ReName.py
├── 0006
├── duote_asyncio.py
├── duote_multithread.py
└── duote_nothread.py
├── 0007
└── cube3.py
├── 0008
├── .gitignore
├── README.md
├── TodoList
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── manage.py
├── mylist
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── temp_img
│ └── show.png
└── templates
│ ├── base.html
│ ├── index.html
│ └── registration
│ └── login.html
├── 0009
└── login.py
├── 0010
└── youdao.py
├── 0011
├── LogOperator.py
├── README.md
└── chrom2000.log
├── 0012
├── .gitignore
├── BMI
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── forms.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── README.md
├── commonstatic
│ ├── health_home
│ │ ├── 1.png
│ │ ├── 2.png
│ │ ├── 3.png
│ │ └── 4.png
│ └── home
│ │ ├── css
│ │ ├── bootstrap.css
│ │ ├── flexslider.css
│ │ └── style.css
│ │ ├── fonts
│ │ ├── glyphicons-halflings-regular.woff
│ │ └── glyphicons-halflings-regular.woff2
│ │ ├── images
│ │ ├── banner.jpg
│ │ └── move-up.png
│ │ └── js
│ │ ├── bootstrap.js
│ │ ├── easing.js
│ │ ├── jquery-1.11.1.min.js
│ │ └── move-top.js
├── healthweb
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ ├── views.py
│ └── wsgi.py
├── imgtemp
│ ├── admin.png
│ ├── bmi.png
│ ├── health.png
│ └── statistics.png
├── manage.py
└── templates
│ ├── BMI.html
│ ├── base.html
│ ├── health_home.html
│ ├── index.html
│ └── statistics.html
├── 0013
└── GradeSpyder.py
├── 0014
├── accounts_manager.py
└── source.txt
├── 0015
├── user_agent.py
└── vehicle_trace_crawler.py
├── 0016
└── markdown.py
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | *.pyc
3 | *.swp
4 | .DS_Store
5 |
--------------------------------------------------------------------------------
/0001/verification_code_generator.py:
--------------------------------------------------------------------------------
1 | #coding:utf8
2 |
3 | from string import ascii_uppercase, ascii_lowercase, digits
4 | import random
5 |
6 | def get_check_code(len_, mode = (True, True, True)):
7 | '''check code creater.
8 |
9 | len_ : length of check code.
10 | mode : tuple type, default (upper=True, lower=True, digit=True).
11 | example:
12 | >>> get_check_code(6)
13 | mCX90t
14 | >>> get_check_code(4, (False, False, True))
15 | 4820
16 | >>> get_check_code(4, (True, False, False))
17 | XMDK
18 | '''
19 |
20 | if not isinstance(len_, int) or len(mode) != 3:
21 | raise ValueError
22 |
23 | mode = (True, True, True) if set(mode) == {False} else mode
24 | chars = ''
25 | for m, c in zip(mode, (ascii_uppercase, ascii_lowercase, digits)):
26 | if m:
27 | chars += c
28 | return ''.join([random.choice(chars) for i in range(len_)])
29 |
30 | if __name__ == '__main__':
31 |
32 | print(get_check_code(4, (True, True, False)))
33 | print(get_check_code(4, (False, False, True)))
34 | print(get_check_code(6))
35 |
--------------------------------------------------------------------------------
/0002/counter.py:
--------------------------------------------------------------------------------
1 | from collections import Counter
2 |
3 |
4 | def main(filename):
5 | symbols = list('.,-\\/"\'![]()“”')
6 | with open(filename, 'r') as f:
7 | context = f.read().lower()
8 | for s in symbols:
9 | context = context.replace(s, ' ')
10 | lines = context.count('\n')
11 | words = []
12 | for line in context.strip().split('\n'):
13 | words.extend([w for w in line.strip().split(' ') if w.isalpha()])
14 | counter = Counter(words)
15 | for k, v in counter.items():
16 | print('%s : %s' % (k, v))
17 | print('lines : %d' % lines)
18 | print('words : %d' % len(counter))
19 |
20 |
21 | if __name__ == '__main__':
22 |
23 | main('car-child-soldiers.txt')
24 |
--------------------------------------------------------------------------------
/0003/codestat.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 | '''
3 | by Jeffy
4 | '''
5 |
6 | import os
7 |
8 | def findfile(path):
9 | filelist = []
10 | for filename in os.listdir(path):
11 | filelist.append(filename)
12 | #print (filelist)
13 | return filelist
14 |
15 | def stat(path):
16 | filelist = findfile(path)
17 | line_total = 0
18 | for i in filelist:
19 | emptyline_count = 0
20 | noteline_count = 0
21 | line_count = 0
22 | with open(path + '\\' + i, 'r') as f:
23 | noteflag = 0
24 | for line in f:
25 | temp = line.split()
26 | if noteflag:
27 | if temp[-1].endswith('*/'):
28 | noteflag = 0
29 | noteline_count += 1
30 | continue
31 | if not temp:
32 | emptyline_count += 1
33 | continue
34 | elif temp[0].startswith('/'):
35 | if temp[0].startswith('//'):
36 | noteline_count += 1
37 | continue
38 | else:
39 | noteflag = 1
40 | noteline_count += 1
41 | else:
42 | line_count += 1
43 |
44 | print ("filename:%s lines:%d notelines:%d emptylines:%d" % \
45 | (i, line_count, noteline_count, emptyline_count))
46 | line_total += line_count + noteline_count + emptyline_count
47 | print ("total lines:%d" % line_total)
48 |
49 | if __name__ == '__main__':
50 | stat('./code')
51 |
--------------------------------------------------------------------------------
/0004/MIS.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 | '''
3 | by Jeffy
4 | '''
5 |
6 | import re
7 | import os
8 |
9 | class MIS(object):
10 |
11 | #initial
12 | def __init__(self):
13 | self.information = []
14 | self.menuid = ''
15 | self.filename = 'records.db'
16 |
17 | #file operator
18 | def fileop(self, typeid, keyword = ''):
19 | with open(self.filename, 'a+') as f:
20 |
21 | #add
22 | if typeid == 1:
23 | f.write(self.information[0])
24 | for i in self.information[1:]:
25 | f.write(',' + i)
26 | f.write('\n')
27 | return True
28 |
29 | #get all
30 | elif typeid == 21 or typeid == 22:
31 | count = 0
32 | f.seek(0)
33 | for line in f:
34 | temp = line.strip('\n').split(',')
35 | if typeid == 21:
36 | count += 1
37 | print(str(count) + '. ', end = '')
38 | for i in temp:
39 | print(i + '\t', end = '')
40 | print()
41 | continue
42 | if len(temp) > 2:
43 | count += 1
44 | print(str(count) + '. ' + temp[2] + '\t' + temp[1])
45 | return count
46 |
47 | #search
48 | else:
49 | pattern = keyword
50 | regex = re.compile(pattern)
51 | f.seek(0)
52 | count = 0
53 | for line in f:
54 | match = regex.search(line)
55 | if match:
56 | count += 1
57 | print(str(count) + '. ' + line, end = '')
58 | return count
59 |
60 | def print1(self):
61 | print('\n*****results*****')
62 | print('total:%d\n' % self.fileop(21))
63 |
64 | def print2(self):
65 | print('\n*****results*****')
66 | print('total:%d\n' % self.fileop(22))
67 |
68 | def search(self):
69 | keyword = input('input key word:')
70 | print('\n*****results*****')
71 | print('total:%d\n' % self.fileop(23, keyword))
72 |
73 | def add(self):
74 | print('\n*****input information*****')
75 | self.information.append(input('employee payroll number:'))
76 | self.information.append(input('telephone number:'))
77 | self.information.append(input('name:'))
78 | self.information.append(input('department number:'))
79 | self.information.append(input('job title:'))
80 | self.information.append(input('date of hiring:'))
81 | if self.fileop(1):
82 | print('successful!')
83 |
84 | def delete(self):
85 | uid = input('employee payroll number to del:')
86 | with open(self.filename, 'r') as f:
87 | with open(self.filename + '.bak', 'w') as fb:
88 | for line in f:
89 | if line.startswith(uid):
90 | continue
91 | fb.write(line)
92 | os.rename(self.filename, 'temp')
93 | os.rename(self.filename + '.bak', self.filename)
94 | os.rename('temp', self.filename + '.bak')
95 |
96 | def menu(self):
97 | print ('''Adfaith Consulting - Employee Information - Main Menu
98 | =====================================================
99 |
100 | 1 - Print All Current Records
101 | 2 – Print Names and Phone Numbers
102 | 3 - Search for specific Record(s)
103 | 4 - Add New Records
104 | 5 – Delete Records
105 |
106 | q - Quit\n''')
107 | self.menuid = input("Your Selection:")
108 | if not(self.menuid >= '1' and self.menuid <= '7' or self.menuid == 'q'):
109 | print ('input error!')
110 | self.menu()
111 | if self.menuid == '1':
112 | self.print1()
113 | elif self.menuid == '2':
114 | self.print2()
115 | elif self.menuid == '3':
116 | self.search()
117 | elif self.menuid == '4':
118 | self.add()
119 | else:
120 | self.delete()
121 |
122 | def run(self):
123 | while self.menuid != 'q':
124 | self.menu()
125 |
126 |
127 | if __name__ == '__main__':
128 |
129 | mis = MIS()
130 | mis.run()
131 |
132 |
--------------------------------------------------------------------------------
/0005/ReName.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 | '''
3 | by Jeffy
4 | '''
5 |
6 | import os
7 | import sys
8 |
9 | class ReName(object):
10 | def __init__(self):
11 | self.path = '.'
12 | self.filetype = ''
13 | self.newfiletype = ''
14 | self.errorlist = []
15 |
16 | #input filetype && path
17 | def input(self, flag = True):
18 | print('current directory:' + os.getcwd())
19 | while flag:
20 | self.path = input('input path(pardir ..|curdir .):')
21 | if os.path.exists(self.path):
22 | flag = False
23 | os.chdir(self.path)
24 | while not(self.filetype.startswith('.') and \
25 | self.filetype[1:].isalnum()):
26 | self.filetype = input('input filetype(like .jpg):')
27 | self.newfiletype = input("input newfiletype('enter' to del filetype):")
28 | print('\ncurrent working directory: %s\nfiletype: *%s\nnewfiletype: *%s'\
29 | % (os.getcwd(), self.filetype, self.newfiletype))
30 |
31 | #confirm information
32 | def confirm(self):
33 | print('\nchanging *%s to *%s\nare you sure?' % (self.filetype, self.newfiletype))
34 | print('Y to continue, N to input again, Q to quit:')
35 | while True:
36 | temp = input('Y|N|Q :').lower()
37 | if temp == 'y':
38 | return True
39 | elif temp == 'n':
40 | os.chdir(sys.path[0])
41 | self.__init__()
42 | return False
43 | elif temp == 'q':
44 | os._exit(0)
45 | else:
46 | print('input error!')
47 |
48 | #rename
49 | def rename(self):
50 | count = 0
51 | for file in os.listdir():
52 | if file.endswith(self.filetype):
53 | try:
54 | count += 1
55 | newfile = file[:-len(self.filetype)] + self.newfiletype
56 | os.rename(file, newfile)
57 | print("%d. %s --> %s done" % (count, file, newfile))
58 | except:
59 | print("%d. %s --> %s error" % (count, file, newfile))
60 | self.errorlist.append(file)
61 | continue
62 | print('statistic:\ntotal:%d succeed:%d error:%d' \
63 | % (count, count - len(self.errorlist), len(self.errorlist)))
64 | while self.errorlist:
65 | temp = input("input 'S' to show error list 'Q' to quit:").lower()
66 | if temp == 's':
67 | count = 0
68 | for i in self.errorlist:
69 | count += 1
70 | print('%d. %s' % (count, i))
71 | elif temp == 'q':
72 | os._exit(0)
73 | else:
74 | print('input error!')
75 |
76 | def run(self):
77 | self.input(1)
78 | while not self.confirm():
79 | self.input(1)
80 | self.rename()
81 | os.system('pause')
82 |
83 | if __name__ == '__main__':
84 |
85 | runner = ReName()
86 | runner.run()
87 |
--------------------------------------------------------------------------------
/0006/duote_asyncio.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 |
3 | import re
4 | import requests
5 | import aiohttp
6 | import asyncio
7 | import time
8 |
9 |
10 |
11 | url = "http://www.duote.com/sort/50_0_wdow_0_%d_.html"
12 |
13 | async def get_body(url):
14 | response = await aiohttp.request('GET', url)
15 | return await response.read()
16 |
17 | async def handle_task(task_id, work_queue):
18 | while not work_queue.empty():
19 | status = False
20 | try:
21 | p = await work_queue.get()
22 | body = await get_body(url % p)
23 | parser(body.decode('gbk', errors = 'ignore'))
24 | status = True
25 | except Exception as e:
26 | print(e)
27 | finally:
28 | print('{} 爬取第{}页\t{}'.format(task_id, p, status))
29 |
30 | def parser(content):
31 | pattern = re.compile(
32 | r'''>(人气.*?)<.*?>(好评率.*?)<.*?title="(.*?)".*?>(大小.*?)<''',
33 | re.S
34 | )
35 | info = re.findall(pattern, content)
36 | with open('duote.txt', 'a') as f:
37 | for i in info:
38 | app = '{0[2]}\t{0[3]}\t{0[0]}\t{0[1]}'.format(i)
39 | f.write(app + '\n')
40 |
41 | def main():
42 | start = time.time()
43 | q = asyncio.Queue()
44 |
45 | response = requests.get(url % 1)
46 | counts = re.findall(r'第\d/(.*?)页 共有:(.*?)条', response.text)
47 | pages, apps = map(int, counts[0])
48 |
49 | [q.put_nowait(p) for p in range(1, pages + 1)]
50 | loop = asyncio.get_event_loop()
51 | tasks = [handle_task(task_id, q) for task_id in range(8)]
52 | print('本站包含{}个软件, 共有{}页'.format(apps, pages))
53 | loop.run_until_complete(asyncio.wait(tasks))
54 | loop.close()
55 | print(time.time()-start)
56 |
57 |
58 | if __name__ == "__main__":
59 |
60 | main()
61 |
--------------------------------------------------------------------------------
/0006/duote_multithread.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 |
3 | import re
4 | import time
5 | import queue
6 | import threading
7 | import urllib.request
8 |
9 | class ThreadSpyder(threading.Thread):
10 |
11 | def __init__(self, name, url, queue):
12 | threading.Thread.__init__(self)
13 | self.setName(name)
14 | self.url = url
15 | self.queue = queue
16 |
17 | def run(self):
18 | while not self.queue.empty():
19 | page = self.queue.get()
20 | status = self.get_apps(page)
21 | self.queue.task_done()
22 | print('{} 爬取第{}页\t{}'.format(self.getName(), page, status))
23 |
24 | def get_apps(self, page):
25 | try:
26 | response = urllib.request.urlopen(self.url % page, timeout=10)
27 | content = response.read().decode('gbk')
28 | except:
29 | return False
30 |
31 | info = self.__filter(content)
32 | with open('duote.txt', 'a') as f:
33 | for i in info:
34 | app = '{0[2]}\t{0[3]}\t{0[0]}\t{0[1]}'.format(i)
35 | f.write(app + '\n')
36 | return True
37 |
38 | def __filter(self, content):
39 | pattern = re.compile(
40 | r'''>(人气.*?)<.*?>(好评率.*?)<.*?title="(.*?)".*?>(大小.*?)<''',
41 | re.S
42 | )
43 | info = re.findall(pattern, content)
44 | return info
45 |
46 |
47 | class DuoteSpyder:
48 |
49 | def __init__(self, url):
50 | self.url = url
51 | self.pages = 0
52 | self.apps = 0
53 | self.count_pages_and_apps()
54 |
55 | def count_pages_and_apps(self):
56 | response = urllib.request.urlopen(self.url % 1)
57 | content = response.read().decode('gbk')
58 | counts = re.findall(r'第\d/(.*?)页 共有:(.*?)条', content)
59 | try:
60 | self.pages, self.apps = map(int, counts[0])
61 | except Exception as e:
62 | print(e)
63 |
64 | print('本站包含{}个软件, 共有{}页'.format(self.apps, self.pages))
65 |
66 | def run_spyder(self):
67 | start_time = time.time()
68 |
69 | q = queue.Queue()
70 | for page in range(1, self.pages+1):
71 | q.put(page)
72 |
73 | threads = []
74 | for i in range(4):
75 | thread = ThreadSpyder(i, self.url, q)
76 | thread.daemon = True
77 | thread.start()
78 | threads.append(thread)
79 | for t in threads:
80 | t.join()
81 |
82 | print(time.time() - start_time)
83 |
84 | if __name__ == '__main__':
85 |
86 | url = 'http://www.duote.com/sort/50_0_wdow_0_%d_.html'
87 | spyder = DuoteSpyder(url)
88 | spyder.run_spyder()
89 |
--------------------------------------------------------------------------------
/0006/duote_nothread.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 |
3 | import re
4 | import urllib.request
5 |
6 | class DuoteSpyder:
7 |
8 | def __init__(self, url):
9 | self.url = url
10 | self.pages = 0
11 | self.apps = 0
12 | self.status = ''
13 | self.count_pages_and_apps()
14 |
15 | def count_pages_and_apps(self):
16 | response = urllib.request.urlopen(url % 1)
17 | content = response.read().decode('gbk')
18 | counts = re.findall(r'第\d/(.*?)页 共有:(.*?)条', content)
19 | try:
20 | self.pages, self.apps = map(int, counts[0])
21 | except Exception as e:
22 | print(e)
23 |
24 | print('本站包含{}个软件, 共有{}页'.format(self.apps, self.pages))
25 |
26 | def get_apps(self):
27 | for page in range(1, self.pages+1):
28 | try:
29 | response = urllib.request.urlopen(url % page, timeout=10)
30 | content = response.read().decode('gbk')
31 | self.status = '连接成功!'
32 | except:
33 | self.status = '连接失败!'
34 |
35 | info = self.__filter(content)
36 | with open('duote.txt', 'a') as f:
37 | for i in info:
38 | app = '{0[2]}\t{0[3]}\t{0[0]}\t{0[1]}'.format(i)
39 | #print(app)
40 | f.write(app + '\n')
41 |
42 | print('爬取第{}页\t{}'.format(page, self.status))
43 |
44 |
45 | def __filter(self, content):
46 | pattern = re.compile(
47 | r'''>(人气.*?)<.*?>(好评率.*?)<.*?title="(.*?)".*?>(大小.*?)<''',
48 | re.S
49 | )
50 | info = re.findall(pattern, content)
51 | return info
52 |
53 | def run_spyder(self):
54 | self.get_apps()
55 |
56 | if __name__ == '__main__':
57 |
58 | url = 'http://www.duote.com/sort/50_0_wdow_0_%d_.html'
59 | spyder = DuoteSpyder(url)
60 | spyder.run_spyder()
61 |
--------------------------------------------------------------------------------
/0007/cube3.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | '''
4 | by Jeffy
5 | '''
6 |
7 | import itertools
8 | import time
9 |
10 | def cube3(i):
11 | a = i[0] + i[1] + i[2]
12 | b = i[3] + i[4] + i[5]
13 | if a == b:
14 | b = i[6] + i[7] + i[8]
15 | else:
16 | return False
17 | if a == b:
18 | b = i[0] + i[3] + i[6]
19 | else:
20 | return False
21 | if a == b:
22 | b = i[1] + i[4] + i[7]
23 | else:
24 | return False
25 | if a == b:
26 | b = i[2] + i[5] + i[8]
27 | else:
28 | return False
29 | if a == b:
30 | b = i[0] + i[4] + i[8]
31 | else:
32 | return False
33 | if a == b:
34 | b = i[2] + i[4] + i[6]
35 | else:
36 | return False
37 | return True
38 |
39 | def main():
40 | count = 0
41 | start = time.time()
42 | for i in itertools.permutations(range(1, 10), 9):
43 | if cube3(i):
44 | count += 1
45 | flag = 1
46 | print('result %d:' % (count))
47 | for k in i:
48 | print('%d ' % (k), end = '')
49 | if not(flag % 3):
50 | print()
51 | flag += 1
52 | end = time.time()
53 | print('time:', end - start)
54 | print('total:', count)
55 |
56 | if __name__ == '__main__':
57 |
58 | main()
59 |
--------------------------------------------------------------------------------
/0008/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | *.pyc
3 | *.swp
4 | *.sqlite3
5 | __pycache__/
6 |
--------------------------------------------------------------------------------
/0008/README.md:
--------------------------------------------------------------------------------
1 | # TodoList
2 |
3 | ##### 基于Django的待办事项管理应用,本应用暂时仅供自己使用,所以功能并未完善。有兴趣的可以戳这里 >>> [TodoList](http://jeffylu.pythonanywhere.com/)
4 | ##### 帐号:Test
5 | ##### 密码:123456--==
6 | 
--------------------------------------------------------------------------------
/0008/TodoList/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0008/TodoList/__init__.py
--------------------------------------------------------------------------------
/0008/TodoList/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for TodoList project.
3 |
4 | Generated by 'django-admin startproject' using Django 1.10.1.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/1.10/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/1.10/ref/settings/
11 | """
12 |
13 | import os
14 |
15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17 |
18 |
19 | # Quick-start development settings - unsuitable for production
20 | # See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
21 |
22 | # SECURITY WARNING: keep the secret key used in production secret!
23 | SECRET_KEY = 'a8q2+&)=x_)zw)6)ihl$3bt!%0@6k_9s%&920ki3y-_^o-!w!5'
24 |
25 | # SECURITY WARNING: don't run with debug turned on in production!
26 | DEBUG = True
27 |
28 | ALLOWED_HOSTS = []
29 |
30 |
31 | # Application definition
32 |
33 | INSTALLED_APPS = [
34 | 'django.contrib.admin',
35 | 'django.contrib.auth',
36 | 'django.contrib.contenttypes',
37 | 'django.contrib.sessions',
38 | 'django.contrib.messages',
39 | 'django.contrib.staticfiles',
40 | 'mylist',
41 | ]
42 |
43 | MIDDLEWARE = [
44 | 'django.middleware.security.SecurityMiddleware',
45 | 'django.contrib.sessions.middleware.SessionMiddleware',
46 | 'django.middleware.common.CommonMiddleware',
47 | 'django.middleware.csrf.CsrfViewMiddleware',
48 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
49 | 'django.contrib.messages.middleware.MessageMiddleware',
50 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
51 | ]
52 |
53 | ROOT_URLCONF = 'TodoList.urls'
54 |
55 | TEMPLATES = [
56 | {
57 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
58 | 'DIRS': [
59 | os.path.join(BASE_DIR, 'templates'),
60 | ],
61 | 'APP_DIRS': True,
62 | 'OPTIONS': {
63 | 'context_processors': [
64 | 'django.template.context_processors.debug',
65 | 'django.template.context_processors.request',
66 | 'django.contrib.auth.context_processors.auth',
67 | 'django.contrib.messages.context_processors.messages',
68 | ],
69 | },
70 | },
71 | ]
72 |
73 | WSGI_APPLICATION = 'TodoList.wsgi.application'
74 |
75 |
76 | # Database
77 | # https://docs.djangoproject.com/en/1.10/ref/settings/#databases
78 |
79 | DATABASES = {
80 | 'default': {
81 | 'ENGINE': 'django.db.backends.sqlite3',
82 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
83 | }
84 | }
85 |
86 |
87 | # Password validation
88 | # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
89 |
90 | AUTH_PASSWORD_VALIDATORS = [
91 | {
92 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
93 | },
94 | {
95 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
96 | },
97 | {
98 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
99 | },
100 | {
101 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
102 | },
103 | ]
104 |
105 |
106 | # Internationalization
107 | # https://docs.djangoproject.com/en/1.10/topics/i18n/
108 |
109 | LANGUAGE_CODE = 'zh-hans'
110 |
111 | TIME_ZONE = 'Asia/Shanghai'
112 |
113 | USE_I18N = True
114 |
115 | USE_L10N = True
116 |
117 | USE_TZ = True
118 |
119 |
120 | # Static files (CSS, JavaScript, Images)
121 | # https://docs.djangoproject.com/en/1.10/howto/static-files/
122 |
123 | #STATICFILES_DIRS = (
124 | # os.path.join(BASE_DIR, 'commonstatic'),
125 | #)
126 |
127 | STATICFILES_FINDERS = (
128 | 'django.contrib.staticfiles.finders.FileSystemFinder',
129 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
130 | )
131 |
132 | STATIC_URL = '/static/'
133 | STATIC_ROOT = os.path.join(BASE_DIR, 'static')
134 |
--------------------------------------------------------------------------------
/0008/TodoList/urls.py:
--------------------------------------------------------------------------------
1 | """TodoList URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/1.10/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.conf.urls import url, include
14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
15 | """
16 | from django.conf.urls import url, include
17 | from django.contrib.auth.views import login
18 | from django.contrib import admin
19 |
20 | urlpatterns = [
21 | url(r'^admin/', admin.site.urls),
22 | url(r'^accounts/login', login),
23 | url(r'^', include('mylist.urls')),
24 | ]
25 |
--------------------------------------------------------------------------------
/0008/TodoList/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for TodoList project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "TodoList.settings")
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/0008/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 | if __name__ == "__main__":
6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "TodoList.settings")
7 | try:
8 | from django.core.management import execute_from_command_line
9 | except ImportError:
10 | # The above import may fail for some other reason. Ensure that the
11 | # issue is really that Django is missing to avoid masking other
12 | # exceptions on Python 2.
13 | try:
14 | import django
15 | except ImportError:
16 | raise ImportError(
17 | "Couldn't import Django. Are you sure it's installed and "
18 | "available on your PYTHONPATH environment variable? Did you "
19 | "forget to activate a virtual environment?"
20 | )
21 | raise
22 | execute_from_command_line(sys.argv)
23 |
--------------------------------------------------------------------------------
/0008/mylist/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0008/mylist/__init__.py
--------------------------------------------------------------------------------
/0008/mylist/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from mylist.models import *
3 | # Register your models here.
4 |
5 | class MylistAdmin(admin.ModelAdmin):
6 |
7 | list_display = [
8 | 'user',
9 | 'item',
10 | 'status',
11 | ]
12 |
13 | admin.site.register(Mylist, MylistAdmin)
14 |
--------------------------------------------------------------------------------
/0008/mylist/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class MylistConfig(AppConfig):
5 | name = 'mylist'
6 |
--------------------------------------------------------------------------------
/0008/mylist/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0008/mylist/migrations/__init__.py
--------------------------------------------------------------------------------
/0008/mylist/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from django.conf import settings
3 | # Create your models here.
4 |
5 | class Mylist(models.Model):
6 |
7 | user = models.ForeignKey(
8 | settings.AUTH_USER_MODEL,
9 | on_delete = models.CASCADE,
10 | )
11 |
12 | item = models.TextField(
13 | max_length = 200,
14 | )
15 |
16 | status = models.BooleanField(
17 | default = False,
18 | )
19 |
20 | class Meta:
21 |
22 | verbose_name = 'To Do List'
23 | verbose_name_plural = 'To Do List'
24 |
25 | def __str__(self):
26 |
27 | return self.user.username + self.item[:20]
28 |
--------------------------------------------------------------------------------
/0008/mylist/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/0008/mylist/urls.py:
--------------------------------------------------------------------------------
1 | """TodoList URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/1.10/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.conf.urls import url, include
14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
15 | """
16 | from django.conf.urls import url
17 | from mylist.views import *
18 |
19 | urlpatterns = [
20 | url(r'^$', view_of_item_list, name='index'),
21 | ]
22 |
--------------------------------------------------------------------------------
/0008/mylist/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render
2 | from django.http import HttpResponse, HttpResponseRedirect
3 | from django.contrib.auth.decorators import login_required
4 | from mylist.models import Mylist
5 | # Create your views here.
6 |
7 | @login_required
8 | def change_item_status(request):
9 | choice = request.POST['choice']
10 | item_id = request.POST['item_id']
11 | item = Mylist.objects.get(id = item_id)
12 |
13 | if choice == 'done':
14 | item.status = True
15 | item.save()
16 | elif choice == 'redo':
17 | item.status = False
18 | item.save()
19 | elif choice == 'remove':
20 | item.delete()
21 | else:
22 | return HttpResponse('ERROR!')
23 | return HttpResponseRedirect('/')
24 |
25 |
26 | @login_required
27 | def add_item(request):
28 | item = request.POST['item']
29 | if item:
30 | Mylist.objects.create(
31 | user = request.user,
32 | item = item[:200],
33 | )
34 | return HttpResponseRedirect('/')
35 |
36 |
37 | @login_required
38 | def view_of_item_list(request):
39 | if request.method == 'POST':
40 | #return HttpResponse(request.POST)
41 | if 'ok' in request.POST and 'choice' in request.POST:
42 | #return HttpResponse(request.POST)
43 | return change_item_status(request)
44 | if 'add' in request.POST:
45 | #return HttpResponse(request.POST)
46 | return add_item(request)
47 |
48 | items = Mylist.objects.filter(
49 | user = request.user,
50 | status = False,
51 | )
52 |
53 | done_items = Mylist.objects.filter(
54 | user = request.user,
55 | status = True,
56 | )
57 |
58 | context = {
59 | 'items' : items,
60 | 'done_items' : done_items,
61 | }
62 |
63 | return render(request, 'index.html', context)
64 |
--------------------------------------------------------------------------------
/0008/temp_img/show.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0008/temp_img/show.png
--------------------------------------------------------------------------------
/0008/templates/base.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
3 |
4 |
5 | {% block title %}{% endblock %}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
To Do List
14 |
15 |
16 |
17 |
23 |
24 |
25 |
26 |
27 |
28 |
Welcome {{ user.username }}.
29 |
30 |
31 |
32 |
33 |
34 | {% block body %}{% endblock %}
35 |
36 |
37 |
38 |
Copyright © 2016.JeffyLu All rights reserved.
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/0008/templates/index.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% block title %}TodoList{% endblock %}
4 |
5 | {% block body %}
6 | {% if items %}
7 |
8 |
9 |
10 |
11 | Item
12 | Done
13 | Remove
14 | Option
15 |
16 |
17 |
18 | {% for item in items %}
19 |
20 | {{ item.item }}
21 |
34 |
35 | {% endfor %}
36 |
37 |
38 |
39 | {% endif %}
40 |
41 | {% if done_items %}
42 |
43 |
Done
44 |
45 |
46 |
47 | Item
48 | Redo
49 | Remove
50 | Option
51 |
52 |
53 |
54 | {% for item in done_items %}
55 |
56 | {{ item.item }}
57 |
70 |
71 | {% endfor %}
72 |
73 |
74 |
75 | {% endif %}
76 |
77 | {% endblock%}
78 |
79 |
--------------------------------------------------------------------------------
/0008/templates/registration/login.html:
--------------------------------------------------------------------------------
1 | {% extends "admin/base_site.html" %}
2 | {% load i18n static %}
3 |
4 | {% block extrastyle %}{{ block.super }}
5 | {{ form.media }}
6 | {% endblock %}
7 |
8 | {% block bodyclass %}{{ block.super }} login{% endblock %}
9 |
10 | {% block branding %}
11 | TodoList
12 | {% endblock%}
13 |
14 | {% block usertools %}{% endblock %}
15 |
16 | {% block nav-global %}{% endblock %}
17 |
18 | {% block content_title %}{% endblock %}
19 |
20 | {% block breadcrumbs %}{% endblock %}
21 |
22 | {% block content %}
23 | {% if form.errors and not form.non_field_errors %}
24 |
25 | {% if form.errors.items|length == 1 %}{% trans "Please correct the error below." %}{% else %}{% trans "Please correct the errors below." %}{% endif %}
26 |
27 | {% endif %}
28 |
29 | {% if form.non_field_errors %}
30 | {% for error in form.non_field_errors %}
31 |
32 | {{ error }}
33 |
34 | {% endfor %}
35 | {% endif %}
36 |
37 |
38 |
39 | {% if user.is_authenticated %}
40 |
41 | {% blocktrans trimmed %}
42 | You are authenticated as {{ username }}, but are not authorized to
43 | access this page. Would you like to login to a different account?
44 | {% endblocktrans %}
45 |
46 | {% endif %}
47 |
48 |
68 |
69 |
70 | {% endblock %}
71 |
--------------------------------------------------------------------------------
/0009/login.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 |
3 | import urllib.request
4 | import urllib.parse
5 | import http.cookiejar
6 | import json
7 |
8 | cj = http.cookiejar.CookieJar()
9 | handler = urllib.request.HTTPCookieProcessor(cj)
10 | opener = urllib.request.build_opener(handler)
11 | urllib.request.install_opener(opener)
12 |
13 | url = "https://passport.weibo.cn/sso/login"
14 |
15 | postdata = {
16 | "username":"username",
17 | "password":"password",
18 | "savestate":"1",
19 | "r":"http://m.weibo.cn/",
20 | "ec":"0",
21 | "pagerefer":"https://passport.weibo.cn/signin/welcome?entry=mweibo&r=http%3A%2F%2Fm.weibo.cn%2F",
22 | "entry":"mweibo",
23 | "wentry":"",
24 | "loginfrom":"",
25 | "client_id":"",
26 | "code":"",
27 | "qq":"",
28 | "mainpageflag":"1",
29 | "hff":"",
30 | "hfp":"",
31 | }
32 |
33 | headers = {
34 | "Accept":"application/json, text/plain, */*",
35 | #"Accept-Encoding":"gzip, deflate, br",
36 | "Accept-Language":"en-US,en;q=0.8",
37 | "Connection":"keep-alive",
38 | # "Content-Length":"288",
39 | "Content-Type":"application/x-www-form-urlencoded",
40 | "Cookie":"_T_WM=629886d58ed30fd4036432e275322a29",
41 | "Host":"passport.weibo.cn",
42 | "Origin":"https://passport.weibo.cn",
43 | "Referer":"https://passport.weibo.cn/signin/login?entry=mweibo&res=wel&wm=3349&r=http%3A%2F%2Fm.weibo.cn%2F",
44 | "User-Agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/57.0.2987.74 Safari/537.36",
45 | }
46 |
47 | request = urllib.request.Request(
48 | url,
49 | urllib.parse.urlencode(postdata).encode(),
50 | headers,
51 | )
52 |
53 | response = urllib.request.urlopen(request)
54 |
55 | if json.loads(response.read().decode())['retcode'] == 20000000:
56 | print('登录成功')
57 | else:
58 | print('登录失败')
59 |
60 |
61 | cookies = [c.name + "=" + c.value for c in cj]
62 | cookies.append(headers['Cookie'])
63 | headers['Cookie'] = ";".join(cookies)
64 | #print(headers['Cookie'])
65 | headers["Host"] = "m.weibo.cn"
66 |
67 | url = "http://m.weibo.cn/container/getIndex?uid=1643971635&luicode=20000174&type=uid&value=1643971635&containerid=1076031643971635&page=1"
68 | request = urllib.request.Request(
69 | url,
70 | None,
71 | headers,
72 | )
73 | response = urllib.request.urlopen(request)
74 | print(json.loads(response.read().decode()))
75 |
--------------------------------------------------------------------------------
/0010/youdao.py:
--------------------------------------------------------------------------------
1 | #-*- utf-8 -*-
2 | '''
3 | by Jeffy
4 | '''
5 |
6 | from urllib.request import urlopen
7 | from urllib.parse import urlencode
8 | import json
9 |
10 | class Youdao():
11 |
12 | def __init__(self):
13 | self.url = r'http://fanyi.youdao.com/openapi.do?'
14 | self.explain = {
15 | 'translation' : None,
16 | 'phonetic' : None,
17 | 'us-phonetic' : None,
18 | 'uk-phonetic' : None,
19 | 'explains' : None,
20 | 'web' : None,
21 | }
22 | self.postdata = {
23 | 'keyfrom' : 'your keyfrom',
24 | 'key' : 'your key',
25 | 'type' : 'data',
26 | 'doctype' : 'json',
27 | 'version' : '1.1',
28 | 'q' : None,
29 | }
30 |
31 | def parser(self, data):
32 | if 'translation' in data:
33 | self.explain['translation'] = data['translation']
34 |
35 | if 'basic' in data:
36 | for k, v in data['basic'].items():
37 | if k in self.explain:
38 | self.explain[k] = v
39 | if 'web' in data:
40 | self.explain['web'] = data['web']
41 |
42 | print('\n------发 音------\n')
43 | print('%s US: %s UK: %s' % (
44 | self.explain['phonetic'],
45 | self.explain['us-phonetic'],
46 | self.explain['uk-phonetic'],
47 | ))
48 | if self.explain['translation']:
49 | print('\n------翻 译------\n')
50 | for i in self.explain['translation']:
51 | print(i + '; ', end = '')
52 | print()
53 | if self.explain['explains']:
54 | print('\n------基础解释------\n')
55 | for exp in self.explain['explains']:
56 | print(exp + '; ')
57 | if self.explain['web']:
58 | print('\n------网络解释------\n')
59 | for dicts in self.explain['web']:
60 | print(dicts['key'] + ' : ', end = '')
61 | for i in dicts['value']:
62 | print(i, end = '; ')
63 | print()
64 |
65 | def main(self, word):
66 | self.postdata['q'] = word
67 | response = urlopen(self.url, urlencode(self.postdata).encode()).read()
68 | data = json.loads(response.decode('utf-8'))
69 | if data['errorCode']:
70 | print('error!')
71 | return False
72 | self.parser(data)
73 |
74 | if __name__ == '__main__':
75 |
76 | app = Youdao()
77 | while(True):
78 | try:
79 | word = input("\n输入翻译内容(';'退出):\n\n")
80 | if word.endswith(';') or word.endswith(';'):
81 | break
82 | app.main(word)
83 | except:
84 | break
85 |
--------------------------------------------------------------------------------
/0011/LogOperator.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | import re
4 | import os
5 | from struct import pack, unpack
6 | import datetime
7 |
8 | class Operate():
9 | """日志操作类"""
10 |
11 | _filename = ''
12 | _count = 0
13 | _logs = []
14 |
15 | #载入日志
16 | def __init__(self, filename):
17 | self._filename = filename
18 | self._load()
19 |
20 | def _pack_byte(self, log):
21 | """字节流打包"""
22 |
23 | btype = pack('i', log['type'])
24 | buser = pack('i', log['user']['length'])
25 | buser += log['user']['user'].encode('gbk')
26 | bdate = pack('i', log['date']['length'])
27 | bdate += log['date']['date'].encode('gbk')
28 | btext = pack('i', log['text']['length'])
29 | btext += log['text']['text'].encode('gbk')
30 | return btype + buser + bdate + btext
31 |
32 | def _unpack_byte(self, t, f, length = 0):
33 | """字节流解包"""
34 |
35 | #4个字节解析为int型整数
36 | if t == 'int':
37 | return unpack('i', f.read(4))[0]
38 |
39 | #length长度字符串解码('gbk')
40 | elif t == 'string':
41 | return unpack('%ds' % length, f.read(length))[0].decode('gbk')
42 | else:
43 | return None
44 |
45 | def _load(self):
46 | """载入日志"""
47 |
48 | with open(self._filename, 'rb') as f:
49 |
50 | #读取记录总数
51 | self._count = self._unpack_byte('int', f)
52 |
53 | #按格式解析并保存所有记录
54 | for i in range(self._count):
55 |
56 | #单条记录格式
57 | log = {'type':'', 'user':{}, 'date':{}, 'text':{}}
58 | #类型
59 | log['type'] = self._unpack_byte('int', f)
60 | #用户名以及长度
61 | log['user']['length'] = self._unpack_byte('int', f)
62 | log['user']['user'] = self._unpack_byte(
63 | 'string',
64 | f,
65 | log['user']['length']
66 | )
67 | #日期以及长度
68 | log['date']['length'] = self._unpack_byte('int', f)
69 | log['date']['date'] = self._unpack_byte(
70 | 'string',
71 | f,
72 | log['date']['length']
73 | )
74 | #内容信息以及长度
75 | log['text']['length'] = self._unpack_byte('int', f)
76 | log['text']['text'] = self._unpack_byte(
77 | 'string',
78 | f,
79 | log['text']['length']
80 | )
81 | self._logs.append(log)
82 |
83 | def _input_index(self, string, mflag = False):
84 | """输入区间"""
85 |
86 | index = str(input(string))
87 | while(not re.match(r'[1-9]+\d* [1-9]+\d*', index)):
88 | index = input('输入无效, 请重新输入:')
89 | index = list(map(int, index.split(' ')))
90 |
91 | #移动操作左右区间不排序
92 | if mflag:
93 | return index
94 |
95 | #左右区间排序
96 | index.sort()
97 | l = index[0] if index[0] <= self._count else self._count
98 | r = index[1] if index[1] <= self._count else self._count
99 | return l, r
100 |
101 | def _get_log(self, index):
102 | """按下标取出记录"""
103 |
104 | log = self._logs[index]
105 | #格式化
106 | format_log = str.format("%d %s%s %s" % (
107 | log['type'],
108 | log['user']['user'],
109 | log['date']['date'],
110 | log['text']['text'],
111 | ))
112 | return format_log
113 |
114 | def read(self):
115 | """读取日志"""
116 |
117 | print('共有%d条记录.' % self._count)
118 | l, r = self._input_index('输入查询区间, 如:10 20\n')
119 | print('查询区间为%d-%d.' % (l, r))
120 | for i in range(l-1, r):
121 | print(i+1, self._get_log(i))
122 |
123 | def delete(self):
124 | """删除日志"""
125 |
126 | l, r = self._input_index('输入删除区间, 如:10 20\n')
127 | confirm = input('是否删除记录%d-%d\n确认(y),任意键取消.\n' % (l, r))
128 | if confirm != 'y':
129 | print('已放弃删除!')
130 | return
131 |
132 | for i in range(r-l+1):
133 | print('成功删除:', l+i, self._get_log(l-1))
134 | self._logs.pop(l-1)
135 | self._count -= 1
136 |
137 | self._save()
138 |
139 | def add(self):
140 | """添加日志"""
141 |
142 | log = {'type':'', 'user':{}, 'date':{}, 'text':{}}
143 |
144 | #输入新记录
145 | while(True):
146 | try:
147 | log['type'] = int(input('输入记录类型:'))
148 | break
149 | except:
150 | print('输入无效, 请输入一个整数!')
151 |
152 | log['user']['user'] = input('输入用户名:')
153 | log['date']['date'] = datetime.datetime.now().strftime(' %Y-%m-%d, %H:%M')
154 | log['text']['text'] = input('输入记录信息:')
155 |
156 | #计算长度
157 | log['user']['length'] = len(log['user']['user'].encode('gbk'))
158 | log['date']['length'] = len(log['date']['date'].encode('gbk'))
159 | log['text']['length'] = len(log['text']['text'].encode('gbk'))
160 |
161 | #添加并保存
162 | self._logs.append(log)
163 | self._count += 1
164 | print('成功添加:', self._count, self._get_log(self._count-1))
165 | self._save()
166 |
167 | def change(self):
168 | """修改日志"""
169 |
170 | #取出带修改记录
171 | while True:
172 | try:
173 | index = int(input('输入待修改记录序号, 如:10\n'))
174 | if index < 1 or index > self._count:
175 | raise
176 | break
177 | except:
178 | print('输入无效, 请输入1-%d内的整数!' % self._count)
179 | print('待修改的记录:', index, self._get_log(index-1))
180 | log = self._logs[index-1]
181 |
182 | #输入修改数据
183 | while True:
184 | temp_type = input('输入新类型(回车跳过):')
185 | try:
186 | if temp_type:
187 | temp_type = int(temp_type)
188 | else:
189 | temp_type = log['type']
190 | break
191 | except:
192 | print('输入无效, 请输入一个整数!')
193 | temp_user = input('输入新用户(回车跳过):')
194 | if not temp_user:
195 | temp_user = log['user']['user']
196 | temp_date = datetime.datetime.now().strftime(' %Y-%m-%d, %H:%M')
197 | temp_text = input('输入新记录信息(回车跳过):')
198 | if not temp_text:
199 | temp_text = log['text']['text']
200 |
201 | #修改并保存
202 | print('修改后的记录: %d %d %s%s %s' % (
203 | index, temp_type, temp_user, temp_date, temp_text))
204 | confirm = input('是否修改该记录?\n确认(y),任意键取消.\n')
205 | if confirm != 'y':
206 | print('已取消修改!')
207 | return
208 |
209 | log['type'] = temp_type
210 | log['user']['user'] = temp_user
211 | log['user']['length'] = len(temp_user.encode('gbk'))
212 | log['date']['date'] = temp_date
213 | log['date']['length'] = len(temp_date.encode('gbk'))
214 | log['text']['text'] = temp_text
215 | log['text']['length'] = len(temp_text.encode('gbk'))
216 | self._logs[index-1] = log
217 | print('修改成功!')
218 | self._save()
219 |
220 | def move(self):
221 | """移动日志"""
222 |
223 | current_position, target_position = self._input_index(
224 | '输入待移动日志位置和目标位置, 如:10 20\n',
225 | mflag = True
226 | )
227 |
228 | #移动并保存
229 | print('成功移动\n%d %s' % (
230 | current_position, self._get_log(current_position-1)))
231 | log = self._logs.pop(current_position-1)
232 | self._logs.insert(target_position-1, log)
233 | print('至\n%d %s' % (
234 | target_position, self._get_log(target_position-1)))
235 | self._save()
236 |
237 | def _save(self):
238 | """保存文件"""
239 |
240 | with open('chrom2000.log', 'wb') as f:
241 | f.write(pack('i', self._count))
242 | for log in self._logs:
243 | f.write(self._pack_byte(log))
244 |
245 | def main():
246 | """操作日志文件
247 |
248 | 选项:
249 | a --> 添加日志
250 | c --> 修改日志
251 | d --> 删除日志
252 | m --> 移动日志
253 | r --> 读取日志
254 | q --> 退出
255 |
256 | 学号:105032014029 姓名:卢键辉
257 | """
258 |
259 | #创建对象
260 | FILE_NAME = 'chrom2000.log'
261 | log = Operate(FILE_NAME)
262 |
263 | #主程序
264 | while(True):
265 | choice = input('输入选项:')
266 | if choice == 'r':
267 | log.read()
268 |
269 | elif choice == 'd':
270 | log.delete()
271 |
272 | elif choice == 'a':
273 | log.add()
274 |
275 | elif choice == 'c':
276 | log.change()
277 |
278 | elif choice == 'm':
279 | log.move()
280 |
281 | elif choice == 'q':
282 | print('goodbye!')
283 | break
284 |
285 | else:
286 | print('输入无效!')
287 |
288 | if __name__ == '__main__':
289 |
290 | print(main.__doc__)
291 | main()
292 |
--------------------------------------------------------------------------------
/0011/README.md:
--------------------------------------------------------------------------------
1 | # 日志文件操作
2 |
3 | 假定有个gbk编码的日志文件chrom2000,该文件的格式为:首先是日志头,包含日志头:四个字节unsigned int32来表示该日志中的记录个数;接着日志记录一个接一个,直到文件末尾。每一个日志记录的格式为:记录类型,四个字节,UInt32;用户名长度,四个字节,UInt32;用户名,其长度由用户名长度决定;时间长度,四个字节,UInt32,例如时间“ 2016-12-09, 12:23",起始有空格;信息长度,四个字节,UInt32;信息,长度由信息长度决定。
4 | 现要编写程序对日志进行操作如,增加、删除、修改、查询、移动。
5 |
6 |
7 | 十六进制打开后显示如下:
8 | ```
9 | 00000000 5B 20 00 00 00 00 00 00 0D 00 00 00 41 64 6D 69 [ ..........Admi
10 | 00000010 6E 69 73 74 72 61 74 6F 72 12 00 00 00 20 32 30 nistrator.... 20
11 | 00000020 31 34 2D 31 30 2D 30 39 2C 20 31 31 3A 30 38 1A 14-10-09, 11:08.
12 | 00000030 00 00 00 B8 C3 D3 C3 BB A7 B5 C7 C2 BC B2 A2 BF ................
13 | 00000040 AA CA BC CA B9 D3 C3 CF B5 CD B3 A1 A3 06 00 00 ................
14 | 00000050 00 0D 00 00 00 41 64 6D 69 6E 69 73 74 72 61 74 .....Administrat
15 | 00000060 6F 72 12 00 00 00 20 32 30 31 34 2D 31 30 2D 30 or.... 2014-10-0
16 | 00000070 39 2C 20 31 31 3A 30 39 0C 00 00 00 D0 DE B8 C4 9, 11:09........
17 | 00000080 CF B5 CD B3 C5 E4 D6 C3 07 00 00 00 0D 00 00 00 ................
18 | 00000090 41 64 6D 69 6E 69 73 74 72 61 74 6F 72 12 00 00 Administrator...
19 | 000000A0 00 20 32 30 31 34 2D 31 30 2D 30 39 2C 20 31 31 . 2014-10-09, 11
20 | 000000B0 3A 31 31 10 00 00 00 D0 DE B8 C4 D2 C7 C6 F7 BF :11.............
21 | 000000C0 D8 D6 C6 B7 BD B7 A8 07 00 00 00 0D 00 00 00 41 ...............A
22 | 000000D0 64 6D 69 6E 69 73 74 72 61 74 6F 72 12 00 00 00 dministrator....
23 | 000000E0 20 32 30 31 34 2D 31 30 2D 30 39 2C 20 31 31 3A 2014-10-09, 11:
24 | 000000F0 31 31 10 00 00 00 D0 DE B8 C4 D2 C7 C6 F7 BF D8 11..............
25 | 00000100 D6 C6 B7 BD B7 A8 02 00 00 00 0D 00 00 00 41 64 ..............Ad
26 | 00000110 6D 69 6E 69 73 74 72 61 74 6F 72 12 00 00 00 20 ministrator....
27 | 00000120 32 30 31 34 2D 31 30 2D 30 39 2C 20 31 31 3A 31 2014-10-09, 11:1
28 | 00000130 31 28 00 00 00 D3 C3 BB A7 B4 E6 B4 A2 CE C4 BC 1(..............
29 | 00000140 FE 3A 20 64 65 66 61 75 6C 74 2E 2A 3A 20 2A 2E .: default.*: *.
30 | 00000150 6D 74 68 20 61 6E 64 20 2A 2E 69 66 6F 06 00 00 mth and *.ifo...
31 | 00000160 00 0D 00 00 00 41 64 6D 69 6E 69 73 74 72 61 74 .....Administrat
32 | ```
33 |
34 | * * *
35 |
36 | ***[java版](https://github.com/JeffyLu/useless-but-powerful/tree/master/Java/%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C)***
--------------------------------------------------------------------------------
/0011/chrom2000.log:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0011/chrom2000.log
--------------------------------------------------------------------------------
/0012/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | *.pyc
3 | *.sqlite3
4 | *.swp
5 | __pycache__/
6 | commonstatic/statistics/
7 |
--------------------------------------------------------------------------------
/0012/BMI/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0012/BMI/__init__.py
--------------------------------------------------------------------------------
/0012/BMI/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from BMI.models import Ip, Info
3 | # Register your models here.
4 |
5 | #显示外键
6 | class InfoInline(admin.StackedInline):
7 | model = Info
8 | extra = 0
9 |
10 | #ip管理
11 | class IpAdmin(admin.ModelAdmin):
12 | #搜索框
13 | search_fields = ['ip', ]
14 | #过滤栏
15 | list_filter = ['blackone', ]
16 | #显示列表
17 | list_display = [
18 | 'ip',
19 | 'latestvisit',
20 | 'blackone',
21 | 'remark',
22 | ]
23 | #显示外键
24 | inlines = [InfoInline]
25 |
26 | #信息管理
27 | class InfoAdmin(admin.ModelAdmin):
28 | lists = [
29 | 'ip',
30 | 'get_bmi',
31 | 'get_rank',
32 | 'age',
33 | 'gender',
34 | 'height',
35 | 'weight',
36 | 'date',
37 | ]
38 |
39 | list_filter = ['gender', ]
40 | list_display = lists
41 | search_fields = ['ip__ip', ]
42 |
43 | #注册
44 | admin.site.register(Ip, IpAdmin)
45 | admin.site.register(Info, InfoAdmin)
46 |
--------------------------------------------------------------------------------
/0012/BMI/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class BmiConfig(AppConfig):
5 | name = 'BMI'
6 |
--------------------------------------------------------------------------------
/0012/BMI/forms.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 |
3 | #构造信息表单
4 | class BMIForm(forms.Form):
5 | age = forms.IntegerField(
6 | label = '年龄',
7 | min_value = 1,
8 | error_messages = {'required' : '请填写年龄!'},
9 | widget = forms.NumberInput(
10 | attrs = {
11 | 'placeholder' : '1-150岁',
12 | 'size' : '20',
13 | 'title' : '请填写年龄!',
14 | }
15 | ),
16 | )
17 |
18 | GENDER_CHOICE = (('男', '男'), ('女', '女'))
19 | gender = forms.CharField(
20 | label = '性别',
21 | error_messages = {'required' : '请选择性别!'},
22 | widget = forms.Select(
23 | choices = GENDER_CHOICE
24 | ),
25 | )
26 |
27 | height = forms.DecimalField(
28 | label = '身高',
29 | min_value = 20,
30 | error_messages = {'required' : '请填写身高!'},
31 | max_digits = 4,
32 | decimal_places = 1,
33 | widget = forms.NumberInput(
34 | attrs = {
35 | 'placeholder' : '单位:cm',
36 | 'size' : '20',
37 | 'title' : '请填写身高!',
38 | }
39 | ),
40 | )
41 |
42 | weight = forms.DecimalField(
43 | label = '体重',
44 | min_value = 1,
45 | error_messages = {'required' : '请填写体重!'},
46 | max_digits = 4,
47 | decimal_places = 1,
48 | widget = forms.NumberInput(
49 | attrs = {
50 | 'placeholder' : '单位:g',
51 | 'size' : '20',
52 | 'title' : '请填写体重!',
53 | }
54 | ),
55 | )
56 |
57 | #处理脏数据
58 | def clean_age(self):
59 | age = self.cleaned_data['age']
60 | if age <= 0 or age > 150:
61 | raise forms.ValidationError("请填写有效的年龄(1-150).")
62 | return age
63 |
64 | def clean_height(self):
65 | height = self.cleaned_data['height']
66 | if height <= 20 or height > 300:
67 | raise forms.ValidationError("请填写有效的身高(单位:cm).")
68 | return height
69 |
70 | def clean_weight(self):
71 | weight = self.cleaned_data['weight']
72 | if weight <= 0 or weight > 500:
73 | raise forms.ValidationError("请填写有效的体重(单位:g).")
74 | return weight
75 |
--------------------------------------------------------------------------------
/0012/BMI/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.1 on 2017-02-06 07:13
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 | import django.db.models.deletion
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | initial = True
12 |
13 | dependencies = [
14 | ]
15 |
16 | operations = [
17 | migrations.CreateModel(
18 | name='Info',
19 | fields=[
20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21 | ('age', models.IntegerField(verbose_name='年龄')),
22 | ('gender', models.CharField(choices=[('男', '男'), ('女', '女')], max_length=1, verbose_name='性别')),
23 | ('height', models.DecimalField(decimal_places=1, max_digits=4, verbose_name='身高')),
24 | ('weight', models.DecimalField(decimal_places=1, max_digits=4, verbose_name='体重')),
25 | ('date', models.DateTimeField(auto_now_add=True, verbose_name='填写日期')),
26 | ],
27 | options={
28 | 'verbose_name': 'BMI指数',
29 | 'verbose_name_plural': '参数管理',
30 | },
31 | ),
32 | migrations.CreateModel(
33 | name='Ip',
34 | fields=[
35 | ('ip', models.GenericIPAddressField(primary_key=True, serialize=False, verbose_name='IP')),
36 | ('blackone', models.BooleanField(default=False, verbose_name='黑名单')),
37 | ('latestvisit', models.DateTimeField(auto_now_add=True, verbose_name='最近访问')),
38 | ('remark', models.TextField(blank=True, max_length=100, null=True, verbose_name='备注')),
39 | ],
40 | options={
41 | 'verbose_name_plural': 'IP管理',
42 | },
43 | ),
44 | migrations.AddField(
45 | model_name='info',
46 | name='ip',
47 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='BMI.Ip', verbose_name='IP'),
48 | ),
49 | ]
50 |
--------------------------------------------------------------------------------
/0012/BMI/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0012/BMI/migrations/__init__.py
--------------------------------------------------------------------------------
/0012/BMI/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | # Create your models here.
4 |
5 | #ip表
6 | class Ip(models.Model):
7 | ip = models.GenericIPAddressField(
8 | 'IP',
9 | primary_key = True,
10 | )
11 |
12 | blackone = models.BooleanField(
13 | '黑名单',
14 | default = False,
15 | )
16 |
17 | latestvisit = models.DateTimeField(
18 | '最近访问',
19 | auto_now_add = True,
20 | )
21 |
22 | remark = models.TextField(
23 | '备注',
24 | max_length = 100,
25 | blank = True,
26 | null = True,
27 | )
28 |
29 | class Meta:
30 | #后台显示名称
31 | verbose_name_plural = 'IP管理'
32 |
33 | def __str__(self):
34 | return self.ip
35 |
36 | #信息表
37 | class Info(models.Model):
38 | ip = models.ForeignKey(
39 | Ip,
40 | verbose_name = 'IP',
41 | on_delete = models.CASCADE,
42 | )
43 |
44 | age = models.IntegerField(
45 | '年龄',
46 | )
47 |
48 | GENDER_CHOICE = (('男', '男'), ('女', '女'))
49 | gender = models.CharField(
50 | '性别',
51 | max_length = 1,
52 | choices = GENDER_CHOICE,
53 | )
54 |
55 | height = models.DecimalField(
56 | '身高',
57 | max_digits=4,
58 | decimal_places=1,
59 | )
60 |
61 | weight = models.DecimalField(
62 | '体重',
63 | max_digits=4,
64 | decimal_places=1,
65 | )
66 |
67 | date = models.DateTimeField(
68 | '填写日期',
69 | auto_now_add = True,
70 | )
71 |
72 | #获取BMI
73 | def get_bmi(self):
74 | bmi = (self.weight/2) / (self.height/100 * self.height/100)
75 | return round(bmi, 1)
76 | get_bmi.short_description = 'BMI'
77 | get_bmi.admin_order_field = 'ip__ip'
78 |
79 | #获取等级
80 | def get_rank(self):
81 | bmi = self.get_bmi()
82 | if bmi < 18.5:
83 | return "偏瘦"
84 | elif bmi >= 18.5 and bmi <= 24.9:
85 | return "正常"
86 | elif bmi >= 25.0 and bmi <= 29.9:
87 | return "偏胖"
88 | elif bmi >= 30.0 and bmi <= 34.9:
89 | return "肥胖"
90 | elif bmi >= 35.0 and bmi <= 39.9:
91 | return "重度肥胖"
92 | else:
93 | return "极度肥胖"
94 | get_rank.short_description = '等级'
95 | get_rank.admin_order_field = 'ip__ip'
96 |
97 | class Meta:
98 | #后台显示名称
99 | verbose_name_plural = '参数管理'
100 | verbose_name = 'BMI指数'
101 |
102 | def __str__(self):
103 | return str(self.get_bmi())
104 |
105 |
--------------------------------------------------------------------------------
/0012/BMI/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/0012/BMI/views.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | from django.shortcuts import render, render_to_response
3 | from django.http import HttpResponse, HttpResponseRedirect
4 | from .models import Ip, Info
5 | from .forms import BMIForm
6 | import pylab as pl
7 | import numpy as np
8 | import threading
9 | import time
10 | import os
11 |
12 | #配置中文字体
13 | import matplotlib as mpl
14 | zhfont = mpl.font_manager.FontProperties(fname='/usr/share/fonts/wps-office/FZFSK.TTF')
15 |
16 | # Create your views here.
17 |
18 | #获取ip地址
19 | def get_ip(request):
20 | x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
21 | if x_forwarded_for:
22 | ip = x_forwarded_for.split(',')[0]
23 | else:
24 | ip = request.META.get('REMOTE_ADDR')
25 | return ip
26 |
27 |
28 | def view_of_BMI(request):
29 | ip = get_ip(request)
30 | if request.method == 'POST':
31 | form = BMIForm(request.POST)
32 | try:
33 | ip = Ip.objects.get(ip = ip)
34 | if ip.blackone:
35 | return HttpResponse('非法用户:' + ip)
36 | except:
37 | ip = Ip.objects.create(ip = ip)
38 | if form.is_valid():
39 | Info.objects.create(
40 | ip = ip,
41 | age = form.clean_age(),
42 | gender = form.cleaned_data['gender'],
43 | height = form.cleaned_data['height'],
44 | weight = form.cleaned_data['weight'],
45 | )
46 | condition.acquire()
47 | stat_thread.ip = ip
48 | condition.notifyAll()
49 | condition.release()
50 | return HttpResponseRedirect('/bmi')
51 | else:
52 | form = BMIForm()
53 | try:
54 | history_data = Info.objects.filter(ip = ip)
55 | history_data = history_data.order_by('-date')[:5]
56 | except:
57 | history_data = None
58 | context = {
59 | 'form' : form,
60 | 'ip' : ip,
61 | 'history_data' : history_data,
62 | }
63 | return render(request, 'BMI.html', context)
64 |
65 |
66 | class Statistics(threading.Thread):
67 |
68 | age_bmi_count = None
69 | items = None
70 | condition = threading.Condition()
71 |
72 | def __init__(self):
73 | super().__init__()
74 | self.file_path = './commonstatic/statistics/'
75 | if not os.path.exists('./commonstatic/statistics'):
76 | os.mkdir('./commonstatic/statistics')
77 | print('make dir statistics.')
78 | self.ip = None
79 |
80 | def stat_personal(self):
81 | if not os.path.exists(self.file_path + self.ip.ip):
82 | os.mkdir(self.file_path + self.ip.ip)
83 | print('make dir %s' % self.ip.ip)
84 | try:
85 | items = self.ip.info_set.count()
86 | except:
87 | return 0
88 | my_info = Info.objects.filter(ip = self.ip).order_by('date')
89 | dates = list(range(len(my_info)))
90 | bmis = [info.get_bmi() for info in my_info]
91 | pl.figure('my', figsize = (5.2, 2.8), dpi = 100)
92 | pl.plot(dates, bmis, '*-', color = '#20b2aa', linewidth = 1.5)
93 | pl.ylabel(u'BMI值', fontproperties = zhfont)
94 | pl.ylim(0.0, 50.0)
95 | pl.savefig(self.file_path + self.ip.ip + '/my.jpg')
96 | pl.cla()
97 | return items
98 |
99 | def stat_all_by_age(self):
100 | bmi_by_age = []
101 | sum_of_bmi = 0
102 | count = 0
103 | for i in range(1, 151):
104 | infos = Info.objects.filter(age = i)
105 | count += len(infos)
106 | if infos:
107 | for info in infos:
108 | sum_of_bmi += info.get_bmi()
109 | else:
110 | sum_of_bmi += 0
111 | if not i%10:
112 | bmi_by_age.append((i, sum_of_bmi, count))
113 | sum_of_bmi = 0
114 | count = 0
115 | ages = [i for i in range(10, 151, 10)]
116 | avebmi = [0 if i[1] == 0 else round(i[1]/i[2], 1) for i in bmi_by_age]
117 | pl.figure('all0', figsize = (5.2, 2.8), dpi = 100)
118 | pl.xlabel(u'年龄段', fontproperties = zhfont)
119 | pl.ylabel('平均BMI', fontproperties = zhfont)
120 | pl.ylim(0.0, 50.0)
121 | pl.plot(ages, avebmi, '*', color = '#20b2aa')
122 | pl.savefig(self.file_path + 'all0.jpg')
123 | pl.cla()
124 | avecount = [i[2] for i in bmi_by_age]
125 | ages = ['%d-%d'%(i-9, i) for i in ages]
126 | return list(zip(ages, avebmi, avecount))
127 |
128 | def stat_all_by_rank(self):
129 | ranks = ['偏瘦', '正常', '偏胖', '肥胖', '重度肥胖', '极度肥胖']
130 | men_infos = Info.objects.filter(gender = '男')
131 | women_infos = Info.objects.filter(gender = '女')
132 | men_ranks = [i.get_rank() for i in men_infos]
133 | women_ranks = [i.get_rank() for i in women_infos]
134 | men_count = [men_ranks.count(r) for r in ranks]
135 | women_count = [women_ranks.count(r) for r in ranks]
136 | ind = np.arange(6)
137 | width = 0.35
138 | fig, ax = pl.subplots(figsize = (5.2, 2.8))
139 | rects1 = ax.bar(ind, men_count, width, color = '#20b2aa')
140 | rects2 = ax.bar(ind + width, women_count, width, color = 'w')
141 | ax.set_ylabel('数量', fontproperties = zhfont)
142 | ax.set_xlim(-0.5, 7)
143 | ax.set_xticks(ind+width)
144 | ax.set_xticklabels(ranks, fontproperties = zhfont)
145 | ax.legend((rects1[0], rects2[0]), ('Men', 'Women'), fontsize = 'small')
146 | def autolabel(rects):
147 | for rect in rects:
148 | height = rect.get_height()
149 | ax.text(
150 | rect.get_x() + rect.get_width() / 2,
151 | 1.05 * height,
152 | '%d' % int(height),
153 | ha = 'center',
154 | va='bottom',
155 | )
156 | autolabel(rects1)
157 | autolabel(rects2)
158 | fig.savefig(self.file_path + 'all1.jpg')
159 | fig.clear()
160 |
161 | def run(self):
162 | while True:
163 | print('*'*50, 'alive')
164 | condition.acquire()
165 | try:
166 | if self.ip is not None:
167 | Statistics.items = self.stat_personal()
168 | Statistics.age_bmi_count = self.stat_all_by_age()
169 | self.stat_all_by_rank()
170 | condition.wait()
171 | except:
172 | condition.wait()
173 | condition.release()
174 |
175 |
176 | #单独一个线程绘图
177 | stat_thread = Statistics()
178 | stat_thread.start()
179 | condition = threading.Condition()
180 |
181 |
182 | def view_of_stat(request):
183 | ip = get_ip(request)
184 | ip_count = Ip.objects.count()
185 | items_count = Info.objects.count()
186 |
187 | context = {
188 | 'ip' : ip,
189 | 'items' : Statistics.items,
190 | 'ip_count' : ip_count,
191 | 'items_count' : items_count,
192 | 'age_bmi_count' : Statistics.age_bmi_count,
193 | }
194 |
195 | return render(request, 'statistics.html', context)
196 |
197 |
198 | def view_of_health_home(request):
199 | return render(request, 'health_home.html')
200 |
--------------------------------------------------------------------------------
/0012/README.md:
--------------------------------------------------------------------------------
1 | # 基于Django的BMI指数计算应用
2 |
3 |
4 | ### 一、简介
5 | 本站主要由python和django搭建而成,具有BMI指数计算、等级分析、记录查询、数据统计等功能。
6 |
7 | ## 二、环境依赖
8 | - Python 3.4
9 | - Django 1.10.1
10 | - Matplotlib
11 | - Numpy
12 |
13 | ### 三、安装
14 | **1. 具备上述环境依赖后在根目录下进入终端,输入以下命令迁移数据库(ubuntu中可能用python3替换python)**
15 | ```
16 | $ python manage.py makemigrations
17 | $ python manage.py migrate
18 | ```
19 |
20 | **2. 创建后台管理员用户**
21 | ```
22 | $ python manage.py createsuperuser
23 | ```
24 | **3. 启动服务**
25 | - 本地服务
26 | ```
27 | $python manage.py runserver
28 | ```
29 | - 局域网共享
30 | ```
31 | $python manage.py runserver 0.0.0.0:8000
32 | ```
33 | - ***由于存在部分bug,推荐关闭多线程启动服务***
34 | ```
35 | $python manage.py runserver --nothreading
36 | ```
37 |
38 | ### 四、具体功能应用
39 | **1. 计算BMI**
40 |
41 | 用户可在右侧填写年龄、性别、身高、体重进行计算,计算后右侧会显示最新的5条记录和健康等级。
42 |
43 | 
44 |
45 |
46 | - - -
47 |
48 | **2. 站点数据统计**
49 |
50 | 此页可跟踪个人BMI走势,分析各年龄段BMI均值,健康等级分布情况等功能。
51 |
52 | 
53 |
54 | - - -
55 | **3. 健康之家**
56 |
57 | 提供了几个健康社区
58 |
59 | 
60 |
61 | - - -
62 | **4. 后台管理**
63 |
64 | 后台入口"/admin",用户名和密码为第三点中所创的。可对每项数据进行批量修改等操作。
65 |
66 | 
67 |
68 | - - -
69 | **5. 其他**
70 |
71 | 凡在后台被设为黑名单的ip将无法提交数据。另外隐藏一个"/add"入口用于批量添加随机数据。
72 |
73 | ***注:每个IP对应一个用户***
74 |
75 |
--------------------------------------------------------------------------------
/0012/commonstatic/health_home/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0012/commonstatic/health_home/1.png
--------------------------------------------------------------------------------
/0012/commonstatic/health_home/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0012/commonstatic/health_home/2.png
--------------------------------------------------------------------------------
/0012/commonstatic/health_home/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0012/commonstatic/health_home/3.png
--------------------------------------------------------------------------------
/0012/commonstatic/health_home/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0012/commonstatic/health_home/4.png
--------------------------------------------------------------------------------
/0012/commonstatic/home/css/flexslider.css:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery FlexSlider v2.0
3 | * http://www.woothemes.com/flexslider/
4 | *
5 | * Copyright 2012 WooThemes
6 | * Free to use under the GPLv2 license.
7 | * http://www.gnu.org/licenses/gpl-2.0.html
8 | *
9 | * Contributing author: Tyler Smith (@mbmufffin)
10 | */
11 | /* Browser Resets */
12 | .flex-container a:active,
13 | .flexslider a:active,
14 | .flex-container a:focus,
15 | .flexslider a:focus {outline: none;}
16 | .slides,
17 | .flex-control-nav,
18 | .flex-direction-nav {margin: 0; padding: 0; list-style: none;}
19 |
20 | /* FlexSlider Necessary Styles
21 | *********************************/
22 | .flexslider .slides > li {display: none; -webkit-backface-visibility: hidden;} /* Hide the slides before the JS is loaded. Avoids image jumping */
23 | .flexslider .slides img {width: 100%; display: block;}
24 | .flex-pauseplay span {text-transform: capitalize;}
25 |
26 | /* Clearfix for the .slides element */
27 | .slides:after {content: "."; display: block; clear: both; visibility: hidden; line-height: 0; height: 0;}
28 | html[xmlns] .slides {display: block;}
29 | * html .slides {height: 1%;}
30 |
31 | /* No JavaScript Fallback */
32 | /* If you are not using another script, such as Modernizr, make sure you
33 | * include js that eliminates this class on page load */
34 | .no-js .slides > li:first-child {display: block;}
35 |
36 |
37 | /* FlexSlider Default Theme
38 | *********************************/
39 | .flexslider {
40 | border: 0px;
41 | position: relative;
42 | zoom: 1;
43 | }
44 | .flex-viewport {max-height: 2000px; -webkit-transition: all 1s ease; -moz-transition: all 1s ease; transition: all 1s ease;}
45 | .loading .flex-viewport {max-height: 300px;}
46 | .flexslider .slides {zoom: 1;}
47 |
48 | .carousel li {margin-right: 5px}
49 |
50 |
51 | /* Direction Nav */
52 | .flex-direction-nav {*height: 0;}
53 | .flex-direction-nav a {
54 | width: 50px;
55 | height: 50px;
56 | margin: 0;
57 | display: block;
58 | background: url('../images/img-sprite.png')rgba(255, 255, 255, 0.25) no-repeat 19px center;
59 | position: absolute;
60 | top: 50%;
61 | z-index: 99;
62 | cursor: pointer;
63 | text-indent: -9999px;
64 | -webkit-transition: all .5s;
65 | -moz-transition: all .5s;
66 | transition: all .5s;
67 | -webkit-border-radius: 50%;
68 | -moz-border-radius: 50%;
69 | border-radius: 50%;
70 | }
71 | .flex-direction-nav .flex-next {
72 | background-position: -10px center;
73 | right: -9%;
74 | }
75 | .flex-direction-nav .flex-prev {left: -9%;}
76 | .flexslider:hover .flex-next {opacity: 1;}
77 | .flexslider:hover .flex-prev {opacity: 1;}
78 | .flexslider:hover .flex-next:hover, .flexslider:hover .flex-prev:hover {
79 | opacity: 1;
80 | -webkit-transform: scale(1.2);
81 | -moz-transform: scale(1.2);
82 | -o-transform: scale(1.2);
83 | -ms-transform: scale(1.2);
84 | transform: scale(1.2);
85 | }
86 | .flex-direction-nav .flex-disabled {opacity: .3!important; filter:alpha(opacity=30); cursor: default;}
87 | /* Control Nav */
88 | .flex-control-nav {
89 | display: block;
90 | position: absolute;
91 | left:46%;
92 | margin-left: 0px;
93 | bottom: -65%;
94 | }
95 | .flex-control-nav li {margin: 0 8px; display: inline-block; zoom: 1; *display: inline;}
96 | .flex-control-paging li a {
97 | width: 15px;
98 | height: 15px;
99 | display: block;
100 | background: #fff;
101 | cursor: pointer;
102 | text-indent: -9999px;
103 | border-radius: 50%;
104 | border: 2px solid #FAFAFA;
105 | }
106 | .flex-control-paging li a.flex-active {
107 | background:#2EB6AF;
108 | cursor: default;
109 | }
110 | .flex-control-thumbs {margin: 5px 0 0; position: static; overflow: hidden;}
111 | .flex-control-thumbs li {width: 25%; float: left; margin: 0;}
112 | .flex-control-thumbs img {width: 100%; display: block; opacity: .7; cursor: pointer;}
113 | .flex-control-thumbs img:hover {opacity: 1;}
114 | .flex-control-thumbs .flex-active {opacity: 1; cursor: default;}
115 |
116 |
117 | /* -- RESPONSIVE --*/
118 |
119 | @media screen and (max-width: 1366px){
120 | .flex-direction-nav .flex-prev {
121 | left: -5%;
122 | }
123 | .flex-direction-nav .flex-next {
124 | right: -5%;
125 | }
126 | }
127 | @media screen and (max-width: 1280px){
128 | .flex-direction-nav .flex-prev {
129 | left: 0;
130 | }
131 | .flex-direction-nav .flex-next {
132 | right: 0;
133 | }
134 | }
135 | @media screen and (max-width: 1080px) {
136 | .flex-control-nav {
137 | left: 45%;
138 | bottom: -42%;
139 | }
140 | }
141 | @media screen and (max-width: 991px) {
142 | .flex-control-nav {
143 | left: 43%;
144 | }
145 | }
146 | @media screen and (max-width: 640px) {
147 | .flex-control-nav {
148 | left: 44%;
149 | bottom: -24%;
150 | }
151 | }
152 | @media screen and (max-width: 480px) {
153 | .flex-direction-nav a {
154 | top: 38%;
155 | }
156 | .flex-control-nav {
157 | bottom: -16%;
158 | left: 41%;
159 | }
160 | }
161 | @media screen and (max-width: 414px) {
162 | .flex-direction-nav a {
163 | width: 40px;
164 | height: 40px;
165 | background-position:13px center;
166 | }
167 | .flex-direction-nav .flex-next {
168 | background-position: -14px center;
169 | }
170 | .flex-control-nav {
171 | bottom: -24%;
172 | left: 37%;
173 | }
174 | }
175 | @media screen and (max-width: 384px){
176 |
177 | }
178 | @media screen and (max-width: 320px) {
179 |
180 | }
--------------------------------------------------------------------------------
/0012/commonstatic/home/css/style.css:
--------------------------------------------------------------------------------
1 | body{
2 | margin:0;
3 | font-family: 'Roboto', sans-serif;
4 | background: #fff;
5 | }
6 | body a{
7 | transition: 0.5s all;
8 | -webkit-transition: 0.5s all;
9 | -moz-transition: 0.5s all;
10 | -o-transition: 0.5s all;
11 | -ms-transition: 0.5s all;
12 | text-decoration:none;
13 | outline:none;
14 | }
15 | h1,h2,h3,h4,h5,h6{
16 | margin:0;
17 | font-family: 'Redressed', cursive;
18 | }
19 | p{
20 | margin:0;
21 | }
22 | ul,label{
23 | margin:0;
24 | padding:0;
25 | }
26 | body a:hover{
27 | text-decoration:none;
28 | }
29 | /*-- banner --*/
30 | .banner{
31 | min-height: 700px;
32 | background:url(../images/banner.jpg)no-repeat center 0px;
33 | background-size:cover;
34 | position: relative;
35 | }
36 | .header {
37 | padding-top: 3em;
38 | }
39 |
40 | .logo {
41 | float: left;
42 | text-align: center;
43 | margin-left: 31em;
44 | }
45 | .logo h3 {
46 | font-size: 3.5em;
47 | line-height: 0.7em;
48 | }
49 | .logo h3 a,.logo h3 a:hover{
50 | color: #FFFFFF;
51 | text-decoration: none;
52 | outline:none;
53 | }
54 |
55 |
56 | /*-- banner-text --*/
57 | .banner-text {
58 | margin-top: 11em;
59 | }
60 | .banner-w3lstext h2 ,.banner-w3lstext h3{
61 | font-size: 4em;
62 | color: #fff;
63 | font-weight: 100;
64 | text-align: center;
65 | }
66 | .banner-w3lstext h2 a,.banner-w3lstext h2 a:hover{
67 | color: #fff;
68 | text-decoration:none;
69 | }
70 | .banner-w3lstext p {
71 | font-size: 1.2em;
72 | color: #fff;
73 | text-align: right;
74 | line-height: 2em;
75 | width: 74%;
76 | margin: 1em auto;
77 | font-weight: 300;
78 | }
79 | /*-- //banner --*/
80 | /*-- features --*/
81 | .features,.video,.testimonial,.about,.products,.team,.gallery,.contact,.codes{
82 | padding:6em 0;
83 | }
84 | .title h3 {
85 | font-size: 3.8em;
86 | text-align: center;
87 | color: #20B2AA;
88 | }
89 | .title p {
90 | font-size: 1em;
91 | text-align: center;
92 | color: #777;
93 | line-height: 1.8em;
94 | width: 67%;
95 | margin: 1em auto 0;
96 | font-weight: 400;
97 | }
98 | .title {
99 | margin-bottom: 4em;
100 | }
101 | .features-grids {
102 | text-align: center;
103 | padding: 3em;
104 | }
105 | .features-grids span.glyphicon {
106 | font-size: 2em;
107 | color: #000;
108 | padding-top: 1em;
109 | -webkit-transition:.5s all;
110 | -moz-transition:.5s all;
111 | transition:.5s all;
112 | height: 2.3em;
113 | }
114 | .features-grids h4 {
115 | font-size: 1.7em;
116 | color: #20B2AA;
117 | margin: .5em 0;
118 | }
119 | p {
120 | font-size: 1em;
121 | color: #777;
122 | line-height: 1.8em;
123 | font-weight: 400;
124 | }
125 | .features-grids p {
126 | width: 90%;
127 | margin: 0 auto;
128 | }
129 | .features-grids.features-grd-mdl1,.features-grids.features-grd-mdl2 {
130 | border-left: 1px solid #999;
131 | border-right: 1px solid #999;
132 | }
133 |
134 |
135 | .features-grids.features-grd-mdl1:before {
136 | bottom: -40px;
137 | left: -40px;
138 | }
139 | .features-grids.features-grd-mdl2:before {
140 | top: -40px;
141 | right: -40px;
142 | }
143 | .features-grids:hover span.glyphicon {
144 | padding: 0 0 1em 0;
145 | color: #20B2AA;
146 | }
147 | /*-- //features --*/
148 |
149 | /*--banner-modal--*/
150 | .modal-open .modal {
151 | background: rgba(0, 0, 0, 0.48);
152 | }
153 | .modal-body {
154 | padding: 2em;
155 | }
156 | .modal-dialog {
157 | margin: 6em auto 0;
158 | }
159 | .modal-body img {
160 | width: 100%;
161 | }
162 | .bnr-modal .modal-header {
163 | border: none;
164 | min-height: 2.5em;
165 | padding: 1em 2em 0;
166 | }
167 | .bnr-modal button.close {
168 | color: #E64B3B;
169 | opacity: .9;
170 | font-size: 2.5em;
171 | outline:none;
172 | }
173 | .modal-body p {
174 | margin-top: 1em;
175 | font-size: 1em;
176 | font-weight: 400;
177 | }
178 | /*--//banner-modal--*/
179 | /*-- video --*/
180 | .video {
181 | background: #20B2AA;
182 | }
183 | .video iframe {
184 | width: 100%;
185 | min-height: 300px;
186 | border: 10px solid #0C8A83;
187 | }
188 | .video h1 {
189 | text-align: center;
190 | font-size: 3em;
191 | color: #FFF;
192 | line-height: 1.4em;
193 | margin-bottom: 60px;
194 | }
195 | .video h2 {
196 | font-size: 2em;
197 | color: #FFF;
198 | line-height: 1.4em;
199 | margin-bottom: 40px;
200 | }
201 | .video h3 {
202 | text-align: center;
203 | font-size: 2em;
204 | color: #FFF;
205 | line-height: 1.4em;
206 | }
207 | .video h4 {
208 | font-size: 1.5em;
209 | color: #FFF;
210 | line-height: 1.4em;
211 | }
212 | .video p1 {
213 | color: #FFF;
214 | margin-top: 1.5em;
215 | }
216 | .video p {
217 | color: #777;
218 | margin-left: 200px;
219 | }
220 | .video td {
221 | color: #FFF;
222 | }
223 | .video li {
224 | color: #a92929;
225 | margin-left: 200px;
226 | }
227 | .video label {
228 | color: #fff;
229 | margin:0;
230 | padding:0;
231 | }
232 | /* Pipaluk */
233 |
234 | .button-pipaluk::before,
235 | .button-pipaluk::after {
236 | content: '';
237 | border-radius: 5px;
238 | position: absolute;
239 | top: 0;
240 | left: 0;
241 | width: 100%;
242 | height: 100%;
243 | z-index: -1;
244 | -webkit-transition: -webkit-transform 0.5s, background-color 0.5s;
245 | transition: transform 0.5s, background-color 0.5s;
246 | -moz-transition: transform 0.5s, background-color 0.5s;
247 | -webkit-transition-timing-function: cubic-bezier(0.25, 0, 0.3, 1);
248 | transition-timing-function: cubic-bezier(0.25, 0, 0.3, 1);
249 | -moz-transition-timing-function: cubic-bezier(0.25, 0, 0.3, 1);
250 | }
251 | .button-pipaluk::before {
252 | border: 2px solid #fff;
253 | }
254 | .button-pipaluk.button--inverted::after {
255 | background: #fff;
256 | }
257 | .button-pipaluk:hover::before {
258 | -webkit-transform: scale3d(1, 1, 1);
259 | transform: scale3d(1, 1, 1);
260 | -moz-transform: scale3d(1, 1, 1);
261 | -o-transform: scale3d(1, 1, 1);
262 | -ms-transform: scale3d(1, 1, 1);
263 | }
264 | .button-pipaluk::before,
265 | .button-pipaluk:hover::after {
266 | -webkit-transform: scale3d(0.7, 0.6, 1);
267 | transform: scale3d(0.7, 0.6, 1);
268 | -moz-transform: scale3d(0.7, 0.6, 1);
269 | -o-transform: scale3d(0.7, 0.6, 1);
270 | -ms-transform: scale3d(0.7, 0.6, 1);
271 | }
272 | .more.more2 a {
273 | color: #fff;
274 | }
275 | .more.more2 .button-pipaluk.button--inverted::after {
276 | background: #745EC5;
277 | }
278 | .more.more2 .button-pipaluk::before {
279 | border-color:#745EC5;
280 | }
281 | /*-- //read-more --*/
282 | /*-- //video --*/
283 | /*-- footer --*/
284 | .footer {
285 | background: #fff;
286 | padding: 4em 0;
287 | }
288 |
289 | .copy-right {
290 | padding-top: 2em;
291 | margin-top: 2em;
292 | border-top: 3px solid #7D7D7D;
293 | }
294 | .copy-right p {
295 | text-align: center;
296 | color: #777;
297 | }
298 | .copy-right p a{
299 | color: #20b2aa;
300 | text-decoration:none;
301 | }
302 | .copy-right p a:hover{
303 | color: #777;
304 | }
305 | /*-- //footer --*/
306 | /*-- slider-up-arrow --*/
307 | #toTop {
308 | display: none;
309 | text-decoration: none;
310 | position: fixed;
311 | bottom: 6%;
312 | right: 3%;
313 | overflow: hidden;
314 | width: 32px;
315 | height: 32px;
316 | border: none;
317 | text-indent: 100%;
318 | background: url("../images/move-up.png") no-repeat 0px 0px;
319 | -webkit-transform: scale(0.85);
320 | -moz-transform: scale(0.85);
321 | -o-transform: scale(0.85);
322 | -ms-transform: scale(0.85);
323 | transform: scale(0.85);
324 | -webkit-transition:.5s all;
325 | -moz-transition:.5s all;
326 | transition:.5s all;
327 | }
328 | #toTop:hover {
329 | -webkit-transform: scale(1);
330 | -moz-transform: scale(1);
331 | -o-transform: scale(1);
332 | -ms-transform: scale(1);
333 | transform: scale(1);
334 | }
335 | #toTopHover {
336 | width: 32px;
337 | height: 32px;
338 | display: block;
339 | overflow: hidden;
340 | float: right;
341 | opacity: 0;
342 | -moz-opacity: 0;
343 | filter: alpha(opacity=0);
344 | transform: scale(1);
345 | }
346 | /*-- //slider-up-arrow --*/
347 |
348 |
349 |
350 |
351 |
--------------------------------------------------------------------------------
/0012/commonstatic/home/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0012/commonstatic/home/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/0012/commonstatic/home/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0012/commonstatic/home/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/0012/commonstatic/home/images/banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0012/commonstatic/home/images/banner.jpg
--------------------------------------------------------------------------------
/0012/commonstatic/home/images/move-up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0012/commonstatic/home/images/move-up.png
--------------------------------------------------------------------------------
/0012/commonstatic/home/js/easing.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery EasIng v1.1.2 - http://gsgd.co.uk/sandbox/jquery.easIng.php
3 | *
4 | * Uses the built In easIng capabilities added In jQuery 1.1
5 | * to offer multiple easIng options
6 | *
7 | * Copyright (c) 2007 George Smith
8 | * Licensed under the MIT License:
9 | * http://www.opensource.org/licenses/mit-license.php
10 | */
11 |
12 | // t: current time, b: begInnIng value, c: change In value, d: duration
13 |
14 | jQuery.extend( jQuery.easing,
15 | {
16 | easeInQuad: function (x, t, b, c, d) {
17 | return c*(t/=d)*t + b;
18 | },
19 | easeOutQuad: function (x, t, b, c, d) {
20 | return -c *(t/=d)*(t-2) + b;
21 | },
22 | easeInOutQuad: function (x, t, b, c, d) {
23 | if ((t/=d/2) < 1) return c/2*t*t + b;
24 | return -c/2 * ((--t)*(t-2) - 1) + b;
25 | },
26 | easeInCubic: function (x, t, b, c, d) {
27 | return c*(t/=d)*t*t + b;
28 | },
29 | easeOutCubic: function (x, t, b, c, d) {
30 | return c*((t=t/d-1)*t*t + 1) + b;
31 | },
32 | easeInOutCubic: function (x, t, b, c, d) {
33 | if ((t/=d/2) < 1) return c/2*t*t*t + b;
34 | return c/2*((t-=2)*t*t + 2) + b;
35 | },
36 | easeInQuart: function (x, t, b, c, d) {
37 | return c*(t/=d)*t*t*t + b;
38 | },
39 | easeOutQuart: function (x, t, b, c, d) {
40 | return -c * ((t=t/d-1)*t*t*t - 1) + b;
41 | },
42 | easeInOutQuart: function (x, t, b, c, d) {
43 | if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
44 | return -c/2 * ((t-=2)*t*t*t - 2) + b;
45 | },
46 | easeInQuint: function (x, t, b, c, d) {
47 | return c*(t/=d)*t*t*t*t + b;
48 | },
49 | easeOutQuint: function (x, t, b, c, d) {
50 | return c*((t=t/d-1)*t*t*t*t + 1) + b;
51 | },
52 | easeInOutQuint: function (x, t, b, c, d) {
53 | if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
54 | return c/2*((t-=2)*t*t*t*t + 2) + b;
55 | },
56 | easeInSine: function (x, t, b, c, d) {
57 | return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
58 | },
59 | easeOutSine: function (x, t, b, c, d) {
60 | return c * Math.sin(t/d * (Math.PI/2)) + b;
61 | },
62 | easeInOutSine: function (x, t, b, c, d) {
63 | return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
64 | },
65 | easeInExpo: function (x, t, b, c, d) {
66 | return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
67 | },
68 | easeOutExpo: function (x, t, b, c, d) {
69 | return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
70 | },
71 | easeInOutExpo: function (x, t, b, c, d) {
72 | if (t==0) return b;
73 | if (t==d) return b+c;
74 | if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
75 | return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
76 | },
77 | easeInCirc: function (x, t, b, c, d) {
78 | return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
79 | },
80 | easeOutCirc: function (x, t, b, c, d) {
81 | return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
82 | },
83 | easeInOutCirc: function (x, t, b, c, d) {
84 | if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
85 | return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
86 | },
87 | easeInElastic: function (x, t, b, c, d) {
88 | var s=1.70158;var p=0;var a=c;
89 | if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
90 | if (a < Math.abs(c)) { a=c; var s=p/4; }
91 | else var s = p/(2*Math.PI) * Math.asin (c/a);
92 | return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
93 | },
94 | easeOutElastic: function (x, t, b, c, d) {
95 | var s=1.70158;var p=0;var a=c;
96 | if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
97 | if (a < Math.abs(c)) { a=c; var s=p/4; }
98 | else var s = p/(2*Math.PI) * Math.asin (c/a);
99 | return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
100 | },
101 | easeInOutElastic: function (x, t, b, c, d) {
102 | var s=1.70158;var p=0;var a=c;
103 | if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
104 | if (a < Math.abs(c)) { a=c; var s=p/4; }
105 | else var s = p/(2*Math.PI) * Math.asin (c/a);
106 | if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
107 | return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
108 | },
109 | easeInBack: function (x, t, b, c, d, s) {
110 | if (s == undefined) s = 1.70158;
111 | return c*(t/=d)*t*((s+1)*t - s) + b;
112 | },
113 | easeOutBack: function (x, t, b, c, d, s) {
114 | if (s == undefined) s = 1.70158;
115 | return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
116 | },
117 | easeInOutBack: function (x, t, b, c, d, s) {
118 | if (s == undefined) s = 1.70158;
119 | if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
120 | return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
121 | },
122 | easeInBounce: function (x, t, b, c, d) {
123 | return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
124 | },
125 | easeOutBounce: function (x, t, b, c, d) {
126 | if ((t/=d) < (1/2.75)) {
127 | return c*(7.5625*t*t) + b;
128 | } else if (t < (2/2.75)) {
129 | return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
130 | } else if (t < (2.5/2.75)) {
131 | return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
132 | } else {
133 | return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
134 | }
135 | },
136 | easeInOutBounce: function (x, t, b, c, d) {
137 | if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
138 | return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
139 | }
140 | });
141 |
142 |
--------------------------------------------------------------------------------
/0012/commonstatic/home/js/move-top.js:
--------------------------------------------------------------------------------
1 | /* UItoTop jQuery Plugin 1.2 | Matt Varone | http://www.mattvarone.com/web-design/uitotop-jquery-plugin */
2 | (function($){$.fn.UItoTop=function(options){var defaults={text:'To Top',min:200,inDelay:600,outDelay:400,containerID:'toTop',containerHoverID:'toTopHover',scrollSpeed:1000,easingType:'linear'},settings=$.extend(defaults,options),containerIDhash='#'+settings.containerID,containerHoverIDHash='#'+settings.containerHoverID;$('body').append(''+settings.text+' ');$(containerIDhash).hide().on('click.UItoTop',function(){$('html, body').animate({scrollTop:0},settings.scrollSpeed,settings.easingType);$('#'+settings.containerHoverID,this).stop().animate({'opacity':0},settings.inDelay,settings.easingType);return false;}).prepend(' ').hover(function(){$(containerHoverIDHash,this).stop().animate({'opacity':1},600,'linear');},function(){$(containerHoverIDHash,this).stop().animate({'opacity':0},700,'linear');});$(window).scroll(function(){var sd=$(window).scrollTop();if(typeof document.body.style.maxHeight==="undefined"){$(containerIDhash).css({'position':'absolute','top':sd+$(window).height()-50});}
3 | if(sd>settings.min)
4 | $(containerIDhash).fadeIn(settings.inDelay);else
5 | $(containerIDhash).fadeOut(settings.Outdelay);});};})(jQuery);
--------------------------------------------------------------------------------
/0012/healthweb/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0012/healthweb/__init__.py
--------------------------------------------------------------------------------
/0012/healthweb/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for healthweb project.
3 |
4 | Generated by 'django-admin startproject' using Django 1.10.1.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/1.10/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/1.10/ref/settings/
11 | """
12 |
13 | import os
14 |
15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17 |
18 |
19 | # Quick-start development settings - unsuitable for production
20 | # See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
21 |
22 | # SECURITY WARNING: keep the secret key used in production secret!
23 | SECRET_KEY = '!2l%x)(f_o-ajdww^0$trl6(jxsah#f-&z=c#!+ti^(q*gx410'
24 |
25 | # SECURITY WARNING: don't run with debug turned on in production!
26 | DEBUG = True
27 |
28 | ALLOWED_HOSTS = []
29 |
30 |
31 | # Application definition
32 |
33 | INSTALLED_APPS = [
34 | 'django.contrib.admin',
35 | 'django.contrib.auth',
36 | 'django.contrib.contenttypes',
37 | 'django.contrib.sessions',
38 | 'django.contrib.messages',
39 | 'django.contrib.staticfiles',
40 | 'BMI',
41 | ]
42 |
43 | MIDDLEWARE = [
44 | 'django.middleware.security.SecurityMiddleware',
45 | 'django.contrib.sessions.middleware.SessionMiddleware',
46 | 'django.middleware.common.CommonMiddleware',
47 | 'django.middleware.csrf.CsrfViewMiddleware',
48 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
49 | 'django.contrib.messages.middleware.MessageMiddleware',
50 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
51 | ]
52 |
53 | ROOT_URLCONF = 'healthweb.urls'
54 |
55 | TEMPLATES = [
56 | {
57 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
58 | 'DIRS': [
59 | BASE_DIR + '/templates',
60 | ],
61 | 'APP_DIRS': True,
62 | 'OPTIONS': {
63 | 'context_processors': [
64 | 'django.template.context_processors.debug',
65 | 'django.template.context_processors.request',
66 | 'django.contrib.auth.context_processors.auth',
67 | 'django.contrib.messages.context_processors.messages',
68 | ],
69 | },
70 | },
71 | ]
72 |
73 | WSGI_APPLICATION = 'healthweb.wsgi.application'
74 |
75 |
76 | # Database
77 | # https://docs.djangoproject.com/en/1.10/ref/settings/#databases
78 |
79 | DATABASES = {
80 | 'default': {
81 | 'ENGINE': 'django.db.backends.sqlite3',
82 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
83 | }
84 | }
85 |
86 |
87 | # Password validation
88 | # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
89 |
90 | AUTH_PASSWORD_VALIDATORS = [
91 | {
92 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
93 | },
94 | {
95 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
96 | },
97 | {
98 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
99 | },
100 | {
101 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
102 | },
103 | ]
104 |
105 |
106 | # Internationalization
107 | # https://docs.djangoproject.com/en/1.10/topics/i18n/
108 |
109 | LANGUAGE_CODE = 'zh-hans'
110 |
111 | TIME_ZONE = 'Asia/Shanghai'
112 |
113 | USE_I18N = True
114 |
115 | USE_L10N = True
116 |
117 | USE_TZ = True
118 |
119 |
120 | # Static files (CSS, JavaScript, Images)
121 | # https://docs.djangoproject.com/en/1.10/howto/static-files/
122 | STATICFILES_DIRS = (
123 | os.path.join(BASE_DIR, 'commonstatic'),
124 | )
125 |
126 | STATICFILES_FINDERS = (
127 | 'django.contrib.staticfiles.finders.FileSystemFinder',
128 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
129 | )
130 |
131 | STATIC_URL = '/static/'
132 | STATIC_ROOT = os.path.join(BASE_DIR, 'static')
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/0012/healthweb/urls.py:
--------------------------------------------------------------------------------
1 | """healthweb URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/1.10/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.conf.urls import url, include
14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
15 | """
16 | from django.conf.urls import url
17 | from django.contrib import admin
18 | from BMI.views import view_of_BMI, view_of_stat, view_of_health_home
19 | from .views import index, add_items
20 |
21 | urlpatterns = [
22 | url(r'^add/$', add_items),
23 | url(r'^admin/', admin.site.urls),
24 | url(r'^$', index, name = 'home'),
25 | url(r'^bmi/$', view_of_BMI, name = 'BMI'),
26 | url(r'^statistics/$', view_of_stat, name = 'statistics'),
27 | url(r'^health_home/$', view_of_health_home, name = 'health_home'),
28 | ]
29 |
--------------------------------------------------------------------------------
/0012/healthweb/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render
2 | from django.http import HttpResponse
3 | from BMI.models import Ip, Info
4 | from django.db import transaction
5 | import random
6 |
7 | #主页视图
8 | def index(request):
9 | return render(request, 'index.html')
10 |
11 | #随机添加数据
12 | @transaction.atomic
13 | def add_items(request):
14 |
15 | gender_choice = ['男', '女']
16 | html = []
17 |
18 | #记录个数
19 | for i in range(100):
20 | #for i in range(1000):
21 |
22 | ip = ".".join([str(random.randint(1, 254)) for i in range(4)])
23 | age = random.randint(10, 70)
24 | gender = random.choice(gender_choice)
25 | height_choice = {
26 | '男' : round(random.uniform(150, 190), 1),
27 | '女' : round(random.uniform(140, 180), 1),
28 | }
29 | weight_choice = {
30 | '男' : round(random.uniform(150, 190), 1),
31 | '女' : round(random.uniform(140, 180), 1),
32 | }
33 | height = height_choice[gender]
34 | weight = weight_choice[gender]
35 | bmi = weight/2 / (height/100 * height/100)
36 | #排除无用数据
37 | if bmi > 40 or bmi < 18.5:
38 | continue
39 | Ip.objects.create(ip = ip)
40 | Info.objects.create(
41 | ip = Ip(ip),
42 | age = age,
43 | gender = gender,
44 | height = height,
45 | weight = weight,
46 | )
47 | #输出结果
48 | result = "%s %d %s %.1f \
49 | %.1f %.4f " % (
50 | ip, age, gender, height, weight, bmi)
51 | html.append(result)
52 | return HttpResponse('' % '\n'.join(html))
53 |
54 |
--------------------------------------------------------------------------------
/0012/healthweb/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for healthweb project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "healthweb.settings")
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/0012/imgtemp/admin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0012/imgtemp/admin.png
--------------------------------------------------------------------------------
/0012/imgtemp/bmi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0012/imgtemp/bmi.png
--------------------------------------------------------------------------------
/0012/imgtemp/health.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0012/imgtemp/health.png
--------------------------------------------------------------------------------
/0012/imgtemp/statistics.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeffyLu/little-python/0e6025bb80e3e876d94d5bc775ac326222063006/0012/imgtemp/statistics.png
--------------------------------------------------------------------------------
/0012/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 | if __name__ == "__main__":
6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "healthweb.settings")
7 | try:
8 | from django.core.management import execute_from_command_line
9 | except ImportError:
10 | # The above import may fail for some other reason. Ensure that the
11 | # issue is really that Django is missing to avoid masking other
12 | # exceptions on Python 2.
13 | try:
14 | import django
15 | except ImportError:
16 | raise ImportError(
17 | "Couldn't import Django. Are you sure it's installed and "
18 | "available on your PYTHONPATH environment variable? Did you "
19 | "forget to activate a virtual environment?"
20 | )
21 | raise
22 | execute_from_command_line(sys.argv)
23 |
--------------------------------------------------------------------------------
/0012/templates/BMI.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% load static %}
3 | {% block title %}指数计算{% endblock %}
4 | {% block extracontain%}
5 |
6 |
7 |
计算BMI
8 |
9 |
用户{{ ip }}的最近记录:
10 | {% if history_data %}
11 | {% for data in history_data %}
12 |
13 | {{ data.date }}    BMI:{{ data.get_bmi }}    等级:{{ data.get_rank }}
14 |
15 | 年龄:{{ data.age }}
16 | 性别:{{ data.gender }}
17 | 身高:{{ data.height }}
18 | 体重:{{ data.weight }}
19 |
20 |
21 | {% endfor%}
22 | {% else %}
23 |
无记录!
24 | {% endif %}
25 |
26 |
27 |
28 |
29 |
请填写以下数据:
30 |
31 | {% if form.errors %}
32 | 请修改下列错误项:
33 | {% endif %}
34 |
35 |
36 |
41 |
42 |
BMI指数标准:
43 |
44 |
45 | 偏瘦 < 18.5
46 | 18.5 <= 正常 <= 24.9
47 | 25.0 <= 偏胖 <= 29.9
48 | 30.0 <= 肥胖 <= 34.9
49 | 35.0 <= 重度肥胖 <= 39.9
50 | 39.9 < 极度肥胖
51 |
52 |
53 |
54 |
55 |
56 |
57 | {% endblock %}
58 |
--------------------------------------------------------------------------------
/0012/templates/base.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
3 |
4 | {% block title %}{% endblock %}
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | {% block extrastyle %}{% endblock %}
17 |
18 |
19 | {% block banner %}{% endblock %}
20 |
21 |
22 |
23 |
24 |
25 |
我的BMI
26 |
{% block bodyintroduce %}{% endblock %}
27 |
28 |
29 |
30 |
31 |
数据统计
32 |
统计分析所有数据
33 |
34 |
35 |
36 |
指数计算
37 |
计算您的健康指数BMI
38 |
39 |
40 |
41 |
健康之家
42 |
我们将为您提供一些流行的健康社区
43 |
44 |
45 |
46 |
47 | {% block extracontain %}{% endblock %}
48 |
49 | {% block footer %}
50 |
57 |
58 |
63 |
64 |
65 | {% block extrafooter %}
66 | {% endblock %}
67 | {% endblock %}
68 |
69 |
70 |
--------------------------------------------------------------------------------
/0012/templates/health_home.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% load static %}
3 | {% block title %}健康之家{% endblock %}
4 | {% block extracontain%}
5 |
6 |
7 |
健康社区
8 |
12 |
16 |
20 |
24 |
25 |
26 |
27 |
28 | {% endblock %}
29 |
--------------------------------------------------------------------------------
/0012/templates/index.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% load static %}
3 | {% block title %}主页{% endblock %}
4 | {% block banner %}
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
Happiness lies, first of all, in health.
14 |
----G.W.Curtis
15 |
16 |
17 |
18 |
19 |
20 | {% endblock %}
21 |
22 | {% block bodyintroduce %}
23 | BMI指数(英文为Body Mass Index,简称BMI),是用体重公斤数除以身高米数平方得出的数字,是国际上常用的衡量人体胖瘦程度以及是否健康的一个标准。当我们需要比较及分析一个人的体重对于不同高度的人所带来的健康影响时,BMI值是一个中立而可靠的指标。
24 |
25 |
26 | {% endblock %}
27 |
28 |
--------------------------------------------------------------------------------
/0012/templates/statistics.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% load static %}
3 | {% block title %}数据统计{% endblock %}
4 | {% block extracontain %}
5 |
6 |
7 |
站点数据
8 |
9 |
10 |
11 |
我的IP:{{ ip }}
12 |
我的记录:{{ items }}条
13 |
14 |
15 |
16 |
我的BMI走势
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | 年龄段     记录(条)     BMI(平均)        
26 | 年龄段     记录(条)     BMI(平均)
27 |
28 |
29 | {{ age_bmi_count.0.0 }} {{age_bmi_count.0.2}} {{age_bmi_count.0.1}}
30 | {{ age_bmi_count.8.0 }} {{age_bmi_count.8.2}} {{age_bmi_count.8.1}}
31 |
32 |
33 | {{ age_bmi_count.1.0 }} {{age_bmi_count.1.2}} {{age_bmi_count.1.1}}  
34 | {{ age_bmi_count.9.0 }} {{age_bmi_count.9.2}} {{age_bmi_count.9.1}}
35 |
36 |
37 | {{ age_bmi_count.2.0 }} {{age_bmi_count.2.2}} {{age_bmi_count.2.1}}  
38 | {{ age_bmi_count.10.0 }} {{age_bmi_count.10.2}} {{age_bmi_count.10.1}}
39 |
40 |
41 | {{ age_bmi_count.3.0 }} {{age_bmi_count.3.2}} {{age_bmi_count.3.1}}  
42 | {{ age_bmi_count.11.0 }} {{age_bmi_count.11.2}} {{age_bmi_count.11.1}}
43 |
44 |
45 | {{ age_bmi_count.4.0 }} {{age_bmi_count.4.2}} {{age_bmi_count.4.1}}  
46 | {{ age_bmi_count.12.0 }} {{age_bmi_count.12.2}} {{age_bmi_count.12.1}}
47 |
48 |
49 | {{ age_bmi_count.5.0 }} {{age_bmi_count.5.2}} {{age_bmi_count.5.1}}  
50 | {{ age_bmi_count.13.0 }} {{age_bmi_count.13.2}} {{age_bmi_count.13.1}}
51 |
52 |
53 | {{ age_bmi_count.6.0 }} {{age_bmi_count.6.2}} {{age_bmi_count.6.1}}  
54 | {{ age_bmi_count.14.0 }} {{age_bmi_count.14.2}} {{age_bmi_count.14.1}}
55 |
56 |
57 | {{ age_bmi_count.7.0 }} {{age_bmi_count.7.2}} {{age_bmi_count.7.1}}  
58 |
59 |
60 |
61 |
62 |
63 |
64 |
各年龄段BMI平均值
65 |
66 |
67 |
68 |
69 |
70 |
来自{{ ip_count }}个IP的{{ items_count }}条记录
71 |
72 |
73 |
74 |
BMI等级分布情况
75 |
76 |
77 |
78 |
79 |
80 | {% endblock %}
81 |
--------------------------------------------------------------------------------
/0013/GradeSpyder.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 |
3 | import urllib.request
4 | import urllib.parse
5 | import re
6 | import webbrowser
7 | import http.cookiejar
8 | import os
9 |
10 | #url
11 | url = "http://jwgl.fjnu.edu.cn/"
12 | login_url = url + "default2.aspx"
13 | chkcode_url = url + "CheckCode.aspx"
14 | grade_url = url + "xscjcx.aspx?"
15 |
16 | #cookie
17 | cj = http.cookiejar.CookieJar()
18 | pro = urllib.request.HTTPCookieProcessor(cj)
19 | opener = urllib.request.build_opener(pro)
20 | urllib.request.install_opener(opener)
21 |
22 |
23 | class GradeSpyder:
24 |
25 | def __init__(self):
26 |
27 | self.__cookie = None
28 | self.__name = None
29 | self.__stuid = None
30 | self.__password = None
31 |
32 | def __get_viewstate(self, content):
33 |
34 | viewstate = re.findall(r'''name="__VIEWSTATE" value="(.*?)"''', content)
35 | #print(viewstate)
36 | return viewstate[0]
37 |
38 | @property
39 | def __get_check_code(self):
40 |
41 | chk_dir = os.path.dirname(os.path.abspath(__file__)) + '/CheckCode.aspx'
42 | print('check code path:', chk_dir)
43 | response = urllib.request.urlopen(chkcode_url)
44 | with open(chk_dir, 'wb') as f:
45 | f.write(response.read())
46 | webbrowser.open(chk_dir)
47 | check_code = input("输入验证码:")
48 | for c in cj:
49 | self.__cookie = c.name + "=" + c.value
50 | #print(self.__cookie)
51 | return check_code
52 |
53 | @property
54 | def __get_login_post_data(self):
55 |
56 | response = urllib.request.urlopen(login_url)
57 | content = response.read().decode('gbk')
58 | viewstate = self.__get_viewstate(content)
59 | self.__stuid = input('输入学号:')
60 | self.__password = input('输入密码:')
61 | if not self.__stuid:
62 | self.__stuid = '105032014029'
63 | self.__password = '214121.a'
64 | check_code = self.__get_check_code
65 | identity = "学生"
66 |
67 | post_data = {
68 | 'txtUserName' : self.__stuid,
69 | 'TextBox2' : self.__password,
70 | 'txtSecretCode' : check_code,
71 | 'RadioButtonList1' : identity,
72 | '__VIEWSTATE' : viewstate,
73 | 'Button1' : '',
74 | 'lbLanguage' : '',
75 | 'hidPdrs' : '',
76 | 'hidsc' : '',
77 | }
78 |
79 | return urllib.parse.urlencode(post_data).encode()
80 |
81 | @property
82 | def __get_grade_post_data_and_url(self):
83 |
84 | data = {
85 | 'xh' : self.__stuid,
86 | 'xm' : self.__name,
87 | 'gnmkdm' : 'N121618',
88 | }
89 | url = grade_url + urllib.parse.urlencode(data)
90 |
91 | request = urllib.request.Request(
92 | url,
93 | None,
94 | self.__get_headers,
95 | )
96 | response = urllib.request.urlopen(request)
97 | content = response.read().decode('gbk')
98 | #print(url)
99 |
100 | data = {
101 | '__EVENTTARGET' : '',
102 | '__EVENTARGUMENT' : '',
103 | '__VIEWSTATE' : self.__get_viewstate(content),
104 | 'ddlXN' : input('输入学年, 如(2016-2017):'),
105 | 'ddlXQ' : input('输入学期, 如(1):'),
106 | 'ddl_kcxz' : '',
107 | 'btn_xq' : '学期成绩',
108 | }
109 |
110 | return (urllib.parse.urlencode(data).encode(), url)
111 |
112 | @property
113 | def __get_headers(self):
114 |
115 | headers = {
116 | "Accept" :
117 | "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
118 | "User-Agent" :
119 | "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/53.0.2785.116 Safari/537.36",
120 | "Referer" : "http://jwgl.fjnu.edu.cn/xs_main.aspx?xh=" + self.__stuid,
121 | "Connection" : "keep-alive",
122 | "Cookie" : self.__cookie,
123 | "Host" : "jwgl.fjnu.edu.cn",
124 | }
125 |
126 | return headers
127 |
128 | def login(self):
129 |
130 | try:
131 | request = urllib.request.Request(
132 | login_url,
133 | self.__get_login_post_data,
134 | self.__get_headers,
135 | )
136 | response = urllib.request.urlopen(request)
137 | content = response.read().decode('gbk')
138 | except urllib.request.HTTPError:
139 | print('http error!')
140 | return False
141 |
142 | if '验证码不正确!!' in content:
143 | print('验证码不正确!')
144 | elif '密码错误!!' in content:
145 | print('帐号或密码错误!')
146 | elif '欢迎您:' in content:
147 | name = re.findall(r'''(.*?)同学''', content)
148 | self.__name = name[0]
149 | print('登录成功!')
150 | return True
151 | else:
152 | print('登录失败!')
153 |
154 | return False
155 |
156 | def get_grade(self):
157 |
158 | data, url = self.__get_grade_post_data_and_url
159 | #print(data, url, self.__get_headers)
160 | try:
161 | request = urllib.request.Request(
162 | url,
163 | data,
164 | self.__get_headers,
165 | )
166 | response = urllib.request.urlopen(request)
167 | content = response.read().decode('gbk')
168 | self.__analyze_info(content)
169 | except urllib.request.HTTPError:
170 | print('http error!')
171 | return False
172 |
173 |
174 | def __analyze_info(self, content):
175 |
176 | #print(content)
177 | content = content.replace(' ', '-')
178 | content = re.sub('(?P.*?) ', lambda c: c.group('t'), content)
179 | title = re.findall(r'"lbl_bt">.*>(.*?)', content)
180 | department = re.findall(r'"lbl_xy">(学院.*?) ', content)
181 | _class = re.findall(r'"lbl_xzb">(.*?)', content)
182 | major = re.findall(r'"lbl_zyfx">(专业.*?)', content)
183 | grade_pattern = '(.*?) (.*?) (.*?) (.*?) (.*?) (.*?) (.*?) (.*?) (.*?) (.*?) (.*?) (.*?) (.*?) '
184 | grade = re.findall(grade_pattern, content)
185 | print(department[0])
186 | print(_class[0])
187 | print('学号:'+self.__stuid)
188 | print('姓名:'+self.__name)
189 | print('\n' + '*-'*20 + title[0] + '-*'*20 + '\n')
190 | for l in grade:
191 | print('%-22s\t%-8s\t%-8s\t%-8s\t%-8s\t%-8s' %
192 | (l[3][:9], l[6], l[7].strip(), l[8], l[10], l[11])
193 | )
194 | o = input('\n*输入“f”查看完整信息:\n')
195 | if o == 'f':
196 | for l in grade:
197 | for i in l:
198 | print(i + ' ', end='')
199 | print()
200 |
201 | if __name__ == '__main__':
202 |
203 | op = GradeSpyder()
204 | while True:
205 | if op.login():
206 | break
207 | else:
208 | print('重新登录!')
209 | op.get_grade()
210 |
--------------------------------------------------------------------------------
/0014/accounts_manager.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 |
3 | import os
4 | import re
5 | import hashlib
6 | import pickle
7 | from Crypto.Cipher import AES
8 | from binascii import b2a_hex, a2b_hex
9 |
10 |
11 | DATA = {}
12 | FILE_NAME= 'DATA.dat'
13 |
14 | skip_null = lambda new, old : new if new else old
15 | padding = lambda text : text + ('\0' * (16-(len(text.encode())%16)))
16 | encrypt = None
17 | decrypt = None
18 |
19 | def md5(string):
20 | m = hashlib.md5()
21 | try:
22 | m.update(string.encode())
23 | except TypeError:
24 | print('type error!')
25 | return False
26 | return m.hexdigest()
27 |
28 | def add():
29 | global DATA
30 | account = input("account:")
31 | if account in DATA:
32 | print("{} already exists!".format(account))
33 | return False
34 | user = input("username:")
35 | pwd = input("password:")
36 | notes = input("notes:")
37 | print_data(account, (user, pwd, notes))
38 | confirm = input("(y) to confirm, else to cancel.")
39 | if confirm.upper() == 'Y':
40 | data = [encrypt(i) for i in (user, pwd, notes)]
41 | DATA[account] = data
42 | print("successfully added!")
43 |
44 | def change():
45 | global DATA
46 | account = input("account:")
47 | if account in DATA:
48 | data = [decrypt(i) for i in DATA[account]]
49 | print_data(account, data)
50 | user = input("new username:")
51 | pwd = input("new password:")
52 | notes = input("new notes:")
53 | new_data = [skip_null(n, o) for n, o in zip((user, pwd, notes), data)]
54 | print_data(account, new_data)
55 | confirm = input("(y) to confirm, else to cancel.")
56 | if confirm.upper() == 'Y':
57 | DATA[account] = [encrypt(i) for i in new_data]
58 | print("successfully changed!")
59 | else:
60 | print("{} does not exist!".format(account))
61 |
62 | def delete():
63 | global DATA
64 | account = input("account:")
65 | if account in DATA:
66 | data = [decrypt(i) for i in DATA[account]]
67 | print_data(account, data)
68 | confirm = input("(y) to confirm, else to cancel.")
69 | if confirm.upper() == 'Y':
70 | DATA.pop(account)
71 | print("successfully deleted!")
72 | else:
73 | print("{} does not exist!".format(account))
74 |
75 | def search():
76 | account = input("account:")
77 | if account == '*':
78 | items = [(k, v) for k, v in DATA.items()]
79 | else:
80 | items = [(k, v) for k, v in DATA.items() if account in k]
81 | if items:
82 | for item in items:
83 | data = [decrypt(i) for i in item[1]]
84 | print_data(item[0], data)
85 | else:
86 | print("{} does not exist!".format(account))
87 |
88 | def import_data():
89 | global DATA
90 | if not os.path.isfile('source.txt'):
91 | print("source.txt not found!")
92 | return False
93 |
94 | with open('source.txt', 'r', encoding = 'utf-8', errors = 'ignore') as f:
95 | for line in f:
96 | if line.startswith('#') or not line.strip():
97 | continue
98 | try:
99 | a, u, p, n = re.findall(
100 | r'(.*?), (.*?), (.*?), (.*)', line.strip('\n'))[0]
101 | if a in DATA:
102 | print('{} already exists!'.format(a))
103 | continue
104 | data = [encrypt(i) for i in (u, p, n)]
105 | DATA[a] = data
106 | except:
107 | print('error:{}...'.format(line[:20]))
108 | continue
109 | print_data(a, (u, p, n))
110 |
111 | def export_data():
112 | with open('output.txt', 'w') as f:
113 | for k, v in DATA.items():
114 | f.write('{0}, {1[0]}, {1[1]}, {1[2]}\n'.format(
115 | k, list(map(decrypt, v))))
116 | print('saved to output.txt!')
117 |
118 | def save_data():
119 | if os.path.isfile(FILE_NAME):
120 | os.rename(FILE_NAME, FILE_NAME+'.bak')
121 | with open(FILE_NAME, 'wb') as f:
122 | pickle.dump(DATA, f)
123 |
124 | def load_data():
125 | global DATA, encrypt, decrypt
126 | key = md5(input('security code:'))
127 | iv = key[8:24]
128 | encrypt = lambda text : b2a_hex(
129 | AES.new(key, AES.MODE_CBC, iv).encrypt(padding(text)))
130 | decrypt = lambda text : AES.new(
131 | key, AES.MODE_CBC, iv).decrypt(a2b_hex(text)).decode().rstrip('\0')
132 | if os.path.isfile(FILE_NAME):
133 | with open(FILE_NAME, 'rb') as f:
134 | try:
135 | DATA = pickle.load(f)
136 | except pickle.UnpicklingError:
137 | print('file error!')
138 | return False
139 | except:
140 | print('loading error!')
141 | return False
142 |
143 | def print_data(account, data):
144 | print("{0}\n{1}:\n\t{2[0]}\n\t{2[1]}\n\t{2[2]}\n{0}".format(
145 | '*'*60, account, data))
146 |
147 |
148 | def menu():
149 | print("*"*23)
150 | print("* 'a' to add *")
151 | print("* 'c' to change *")
152 | print("* 'd' to delete *")
153 | print("* 'e' to export *")
154 | print("* 'i' to import *")
155 | print("* 's' to search *")
156 | print("* 'q' to quit *")
157 | print("*"*23)
158 |
159 | if __name__ == '__main__':
160 |
161 | load_data()
162 | menu()
163 |
164 | while True:
165 | op = input("input your choice:")
166 | if op == "a":
167 | add()
168 | save_data()
169 | elif op == "c":
170 | change()
171 | save_data()
172 | elif op == "d":
173 | delete()
174 | save_data()
175 | elif op == "s":
176 | search()
177 | elif op == "i":
178 | import_data()
179 | save_data()
180 | elif op == "e":
181 | export_data()
182 | elif op == "q":
183 | break
184 | else:
185 | continue
186 |
--------------------------------------------------------------------------------
/0014/source.txt:
--------------------------------------------------------------------------------
1 | # 编码utf-8
2 | # 存储格式:帐号, 用户名, 密码, 备注
3 | # 以", "分隔
4 | # 例:
5 | # google, google@gmail.com, testgmail, for google
6 |
7 |
--------------------------------------------------------------------------------
/0015/user_agent.py:
--------------------------------------------------------------------------------
1 | # encoding=utf-8
2 |
3 | agents = [
4 | "Mozilla/5.0 (Linux; U; Android 2.3.6; en-us; Nexus S Build/GRK39F) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
5 | "Avant Browser/1.2.789rel1 (http://www.avantbrowser.com)",
6 | "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.0 Safari/532.5",
7 | "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.310.0 Safari/532.9",
8 | "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.514.0 Safari/534.7",
9 | "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/9.0.601.0 Safari/534.14",
10 | "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/10.0.601.0 Safari/534.14",
11 | "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.20 (KHTML, like Gecko) Chrome/11.0.672.2 Safari/534.20",
12 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.27 (KHTML, like Gecko) Chrome/12.0.712.0 Safari/534.27",
13 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.24 Safari/535.1",
14 | "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.120 Safari/535.2",
15 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.36 Safari/535.7",
16 | "Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9pre) Gecko/2008072421 Minefield/3.0.2pre",
17 | "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10",
18 | "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.0.11) Gecko/2009060215 Firefox/3.0.11 (.NET CLR 3.5.30729)",
19 | "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 GTB5",
20 | "Mozilla/5.0 (Windows; U; Windows NT 5.1; tr; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0E)",
21 | "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
22 | "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
23 | "Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0",
24 | "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0a2) Gecko/20110622 Firefox/6.0a2",
25 | "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1",
26 | "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b4pre) Gecko/20100815 Minefield/4.0b4pre",
27 | "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0 )",
28 | "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90)",
29 | "Mozilla/5.0 (Windows; U; Windows XP) Gecko MultiZilla/1.6.1.0a",
30 | "Mozilla/2.02E (Win95; U)",
31 | "Mozilla/3.01Gold (Win95; I)",
32 | "Mozilla/4.8 [en] (Windows NT 5.1; U)",
33 | "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4) Gecko Netscape/7.1 (ax)",
34 | "HTC_Dream Mozilla/5.0 (Linux; U; Android 1.5; en-ca; Build/CUPCAKE) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
35 | "Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.2; U; de-DE) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/234.40.1 Safari/534.6 TouchPad/1.0",
36 | "Mozilla/5.0 (Linux; U; Android 1.5; en-us; sdk Build/CUPCAKE) AppleWebkit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
37 | "Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
38 | "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
39 | "Mozilla/5.0 (Linux; U; Android 1.5; en-us; htc_bahamas Build/CRB17) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
40 | "Mozilla/5.0 (Linux; U; Android 2.1-update1; de-de; HTC Desire 1.19.161.5 Build/ERE27) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
41 | "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Sprint APA9292KT Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
42 | "Mozilla/5.0 (Linux; U; Android 1.5; de-ch; HTC Hero Build/CUPCAKE) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
43 | "Mozilla/5.0 (Linux; U; Android 2.2; en-us; ADR6300 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
44 | "Mozilla/5.0 (Linux; U; Android 2.1; en-us; HTC Legend Build/cupcake) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
45 | "Mozilla/5.0 (Linux; U; Android 1.5; de-de; HTC Magic Build/PLAT-RC33) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1 FirePHP/0.3",
46 | "Mozilla/5.0 (Linux; U; Android 1.6; en-us; HTC_TATTOO_A3288 Build/DRC79) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
47 | "Mozilla/5.0 (Linux; U; Android 1.0; en-us; dream) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
48 | "Mozilla/5.0 (Linux; U; Android 1.5; en-us; T-Mobile G1 Build/CRB43) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari 525.20.1",
49 | "Mozilla/5.0 (Linux; U; Android 1.5; en-gb; T-Mobile_G2_Touch Build/CUPCAKE) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
50 | "Mozilla/5.0 (Linux; U; Android 2.0; en-us; Droid Build/ESD20) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
51 | "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Droid Build/FRG22D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
52 | "Mozilla/5.0 (Linux; U; Android 2.0; en-us; Milestone Build/ SHOLS_U2_01.03.1) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
53 | "Mozilla/5.0 (Linux; U; Android 2.0.1; de-de; Milestone Build/SHOLS_U2_01.14.0) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
54 | "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
55 | "Mozilla/5.0 (Linux; U; Android 0.5; en-us) AppleWebKit/522 (KHTML, like Gecko) Safari/419.3",
56 | "Mozilla/5.0 (Linux; U; Android 1.1; en-gb; dream) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
57 | "Mozilla/5.0 (Linux; U; Android 2.0; en-us; Droid Build/ESD20) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
58 | "Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
59 | "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Sprint APA9292KT Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
60 | "Mozilla/5.0 (Linux; U; Android 2.2; en-us; ADR6300 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
61 | "Mozilla/5.0 (Linux; U; Android 2.2; en-ca; GT-P1000M Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
62 | "Mozilla/5.0 (Linux; U; Android 3.0.1; fr-fr; A500 Build/HRI66) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",
63 | "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
64 | "Mozilla/5.0 (Linux; U; Android 1.6; es-es; SonyEricssonX10i Build/R1FA016) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
65 | "Mozilla/5.0 (Linux; U; Android 1.6; en-us; SonyEricssonX10i Build/R1AA056) AppleWebKit/528.5 (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
66 | ]
67 |
--------------------------------------------------------------------------------
/0015/vehicle_trace_crawler.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 |
3 | import os
4 | import re
5 | import datetime
6 | import urllib.request
7 | import urllib.parse
8 | import webbrowser
9 | import random
10 | import threading
11 | import queue
12 | import time
13 | from user_agent import agents
14 | from http.cookiejar import CookieJar
15 |
16 | # 0-存储经纬度 1-存储地理位置
17 | LOCATION = 0
18 |
19 | # 线程数
20 | THREADS = 7
21 |
22 | root_url = "http://122.224.8.156:7288/"
23 | login_url = root_url + "Default.aspx"
24 | check_code_url = root_url + "ValidateCode.aspx"
25 |
26 | # 车辆详情
27 | vehicle_detail_url = root_url + "HomePage/AllVehicleInfoDetails.aspx?holdID=10046&stateID=0×=7-4"
28 |
29 | # 车辆行驶记录
30 | trace_detail_url = root_url + "ReportPage/VehicleTravelDetail.aspx?objID={}&time={}"
31 |
32 | # 位置信息
33 | location_url = "http://220.178.1.19:7269/GetAddr.aspx?lon={}&lat={}&type={}"
34 |
35 | # 构造带cookie的opener
36 | cj = CookieJar()
37 | handler = urllib.request.HTTPCookieProcessor(cj)
38 | opener = urllib.request.build_opener(handler)
39 | urllib.request.install_opener(opener)
40 | cookie = None
41 |
42 | # 暂存车辆详情
43 | vehicle_details = []
44 |
45 | # 错误日志
46 | error_log = []
47 |
48 | # 返回utf-8解码后的response
49 | decoded_resp = lambda req: send_response(req).read().decode('utf-8')
50 |
51 | # 返回byte类的response
52 | byte_resp = lambda req: send_response(req).read()
53 |
54 |
55 | def send_response(request):
56 | """超时二次请求"""
57 | try:
58 | return urllib.request.urlopen(request, timeout=5)
59 | except:
60 | try:
61 | return urllib.request.urlopen(request, timeout=10)
62 | except Exception as e:
63 | print(e)
64 | return None
65 |
66 |
67 | def get_viewstate(html):
68 | """return string viewstate"""
69 |
70 | viewstate = re.findall(r'''id="__VIEWSTATE" value="(.*?)"''', html)
71 | #print(viewstate)
72 | return viewstate[0]
73 |
74 |
75 | def get_check_code():
76 | """return check code and set cookie"""
77 |
78 | global cookie
79 |
80 | # check code
81 | chk_dir = os.path.dirname(os.path.abspath(__file__)) + '/CheckCode.aspx'
82 | print('check code path:', chk_dir)
83 | response = byte_resp(check_code_url)
84 | with open(chk_dir, 'wb') as f:
85 | f.write(response)
86 | webbrowser.open(chk_dir)
87 |
88 | # cookie
89 | for c in cj:
90 | cookie = c.name + "=" + c.value
91 | #print(cookie)
92 | return input("输入验证码:")
93 |
94 |
95 | def get_headers():
96 | """headers"""
97 |
98 | headers = {
99 | "Host": "122.224.8.156:7288",
100 | "User-Agent": random.choice(agents),
101 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
102 | "Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
103 | #"Accept-Encoding": "gzip, deflate",
104 | "Cookie": cookie,
105 | "Connection": "keep-alive",
106 | "Upgrade-Insecure-Requests": "1",
107 | "Cache-Control": "max-age=0, no-cache",
108 | "Origin": "http://122.224.8.156:7288",
109 | "Referer": "http://122.224.8.156:7288/Default.aspx",
110 | }
111 | #print(headers['User-Agent'])
112 | return headers
113 |
114 |
115 | def get_login_post_data():
116 | """return bytes of urlencoded post data"""
117 |
118 | post_data = {
119 | "__EVENTTARGET": "btnLogin",
120 | "__EVENTARGUMENT": "",
121 | "__VIEWSTATE": get_viewstate(decoded_resp(login_url)),
122 | "txtUserName": "xxxxxxx",
123 | "txtPassword": "xxxxxxx",
124 | "txtValidateCode": get_check_code(),
125 | "hidpsd": "qaz123ZX",
126 | }
127 | #print(post_data)
128 | return urllib.parse.urlencode(post_data).encode()
129 |
130 |
131 | def login():
132 | """login"""
133 |
134 | request = urllib.request.Request(
135 | login_url,
136 | get_login_post_data(),
137 | get_headers(),
138 | )
139 | response = decoded_resp(request)
140 | if '验证码不正确' in response:
141 | print("验证码不正确")
142 | login()
143 | elif '用户密码不正确' in response:
144 | print("用户密码不正确")
145 | login()
146 | else:
147 | print("登录成功")
148 |
149 |
150 | def get_vehicle_detail_post_data():
151 | """return bytes of urlencoded post data"""
152 |
153 | # 获取车辆详情页面的viewstate
154 | request = urllib.request.Request(
155 | vehicle_detail_url,
156 | None,
157 | get_headers(),
158 | )
159 | __VIEWSTATE = get_viewstate(decoded_resp(request))
160 |
161 | # 请求每页显示200条数据
162 | post_data = {
163 | "__EVENTTARGET": "ddlCount",
164 | "__EVENTARGUMENT": "",
165 | "__LASTFOCUS": "",
166 | "__VIEWSTATE": __VIEWSTATE,
167 | "ddlGoPage": "1",
168 | "ddlCount": "200",
169 | "txtTimeID": "",
170 | "txtHoldID": "10046",
171 | "txtStateID": "0",
172 | "txtIsStop": "",
173 | }
174 | request = urllib.request.Request(
175 | vehicle_detail_url,
176 | urllib.parse.urlencode(post_data).encode(),
177 | get_headers(),
178 | )
179 | response = decoded_resp(request)
180 | index, page = re.findall(r'共有.*?>(\d+)<.*?>\d+/(\d+)<', response)[0]
181 | print("共有{}辆车, {}页.".format(index, page))
182 |
183 | # 如果只有一页就直接返回response, 否则返回每页的post data
184 | if page == '1':
185 | yield response
186 | else:
187 | print("获取第1页")
188 | yield urllib.parse.urlencode(post_data).encode()
189 | for i in range(1, int(page)):
190 | post_data['__EVENTTARGET'] = "btnNext"
191 | post_data['ddlGoPage'] = str(i)
192 | post_data['__VIEWSTATE'] = get_viewstate(response)
193 | print("获取第{}页".format(i+1))
194 | yield urllib.parse.urlencode(post_data).encode()
195 |
196 |
197 | def get_vehicle_detail():
198 | """save vehicle detail into vehicle_details"""
199 |
200 | global vehicle_details
201 |
202 | for post_data in get_vehicle_detail_post_data():
203 |
204 | # 判断返回来的是post data还是response
205 | if not isinstance(post_data, str):
206 | request = urllib.request.Request(
207 | vehicle_detail_url,
208 | post_data,
209 | get_headers(),
210 | )
211 | response = decoded_resp(request)
212 | else:
213 | response = post_data
214 |
215 | # 暂存车辆详情(主要为了后面遍历车辆用)
216 | detail = re.findall(r'(.*?) '*8, response)
217 | vehicle_details += detail
218 | print(" * 确认计数:", len(set(vehicle_details)))
219 | with open('details.txt', 'w+') as f:
220 | for i in vehicle_details:
221 | f.write(str(i) + '\n')
222 | #print(vehicle_details)
223 |
224 |
225 | def get_vehicle_trace_post_data(vid, date):
226 | """return post data"""
227 |
228 | # get viestate
229 | request = urllib.request.Request(
230 | trace_detail_url.format(vid, date),
231 | None,
232 | get_headers(),
233 | )
234 | __VIEWSTATE = get_viewstate(decoded_resp(request))
235 |
236 | # 请求200条数据每页
237 | post_data = {
238 | "__EVENTTARGET": "ddlCount",
239 | "__EVENTARGUMENT": "",
240 | "__LASTFOCUS": "",
241 | "__VIEWSTATE": __VIEWSTATE,
242 | "ddlGoPage": "1",
243 | "ddlCount": "200",
244 | "txtFunID": "",
245 | "txtMaxCount": "",
246 | "hidCameraCount": "",
247 | "hidObjctID": vid,
248 | }
249 | request = urllib.request.Request(
250 | trace_detail_url.format(vid, date),
251 | urllib.parse.urlencode(post_data).encode(),
252 | get_headers(),
253 | )
254 | response = decoded_resp(request)
255 | index, page = re.findall(r'共有.*?>(\d+)<.*?>\d+/(\d+)<', response)[0]
256 | print("[{}]: {} {} 共有{}条记录, {}页.".format(
257 | threading.current_thread().getName(), vid, date, index, page))
258 |
259 | # 和上面一样根据页数返回对应的数据
260 | if page == '1':
261 | yield response
262 | else:
263 | print("获取第1页")
264 | yield urllib.parse.urlencode(post_data).encode()
265 | for i in range(1, int(page)):
266 | post_data['__EVENTTARGET'] = "btnNext"
267 | post_data['ddlGoPage'] = str(i)
268 | post_data['__VIEWSTATE'] = get_viewstate(response)
269 | print("获取第{}页".format(i+1))
270 | yield urllib.parse.urlencode(post_data).encode()
271 |
272 |
273 | def get_daily_data_and_formatter(mode=0):
274 | """select title and formatter"""
275 |
276 | daily_data = [('车辆编号', '车牌号码', '车牌颜色', '所属企业',
277 | '车辆状态', '开始时间', '经度', '纬度', '类型',
278 | '结束时间', '持续时间')]
279 |
280 | daily_data_l = [('车辆编号', '车牌号码', '车牌颜色',
281 | '所属企业', '车辆状态', '开始时间',
282 | '开始位置', '结束时间', '持续时间')]
283 |
284 | formatter = (
285 | "{0[1]}, {0[3]}, {0[4]}, {0[5]}, "
286 | "'{0[6]} {0[7]} {0[8]}', {0[9]}, {0[10]}\n"
287 | )
288 |
289 | formatter_l = (
290 | "{0[1]}, {0[3]}, {0[4]}, {0[5]}, "
291 | "'{0[6]}', {0[7]}, {0[8]}\n"
292 | )
293 | return ([daily_data, daily_data_l][mode], [formatter, formatter_l][mode])
294 |
295 |
296 | def get_vehicle_trace_detail(q):
297 | """save vehicle trace into files"""
298 |
299 | today = datetime.date.today()
300 |
301 | while not q.empty():
302 | i = q.get()
303 | # 过去一周的第一天
304 | date = (today-datetime.timedelta(days=8-i)).strftime('%Y-%m-%d')
305 |
306 | # 按天遍历每辆车
307 | for vehicle in vehicle_details:
308 | try:
309 | daily_data, formatter = get_daily_data_and_formatter(LOCATION)
310 |
311 | # 遍历每辆车一天中的所有记录
312 | for post_data in get_vehicle_trace_post_data(vehicle[0], date):
313 | if not isinstance(post_data, str):
314 | request = urllib.request.Request(
315 | trace_detail_url.format(vehicle[0], date),
316 | post_data,
317 | get_headers(),
318 | )
319 | response = decoded_resp(request)
320 | else:
321 | response = post_data
322 | p1 = r"textCenter.*?" + r"(.*?) "*6
323 | p2 = r".*?"(.*?)","(.*?)",(.*?),".*?""
324 | p3 = r".*?(.*?) (.*?) "
325 | detail = re.findall(p1+p2+p3, response, re.S)
326 |
327 | # 选择经纬度或者位置存储
328 | if LOCATION == 1:
329 | newdetail = []
330 | for d in detail:
331 | request = urllib.request.Request(
332 | location_url.format(d[6], d[7], d[8]),
333 | None,
334 | get_headers(),
335 | )
336 | content = byte_resp(request).decode('gbk')
337 | location = re.findall(r"(.*?) ", content)[0]
338 | newdetail.append(d[:6] + (location, ) + d[9:])
339 | temp = newdetail
340 | else:
341 | temp = detail
342 | daily_data += temp
343 | print(" * 确认计数:{} {} {}条".format(
344 | vehicle[0], date, len(set(daily_data))-1))
345 | except Exception as e:
346 | print(e)
347 | error = " * {} {}数据获取失败".format(vehicle[0], date)
348 | print(error)
349 | error_log.append(error)
350 | continue
351 | if not os.path.isdir(os.path.join(vehicle[3], vehicle[0])):
352 | os.makedirs(os.path.join(vehicle[3], vehicle[0]))
353 | with open(os.path.join(vehicle[3], vehicle[0], date+'.txt'),
354 | 'w+', encoding='utf-8') as f:
355 | for item in daily_data:
356 | f.write(formatter.format(item))
357 |
358 |
359 | def multithread_running():
360 | q = queue.Queue()
361 | for day in range(1, 8):
362 | q.put(day)
363 |
364 | start = time.time()
365 | threads = []
366 | for i in range(THREADS):
367 | t = threading.Thread(
368 | target=get_vehicle_trace_detail,
369 | args=(q,)
370 | )
371 | t.daemon = True
372 | t.start()
373 | threads.append(t)
374 | for t in threads:
375 | t.join()
376 |
377 | print("耗时 {}s".format(time.time()-start))
378 | if error_log:
379 | print('-'*20)
380 | with open('error.log', 'w+') as f:
381 | for e in error_log:
382 | print(e)
383 | f.write(e + '\n')
384 | print('-'*20)
385 |
386 | if __name__ == '__main__':
387 |
388 | login()
389 | get_vehicle_detail()
390 | multithread_running()
391 |
--------------------------------------------------------------------------------
/0016/markdown.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 |
3 | import re
4 |
5 |
6 | class Helper(object):
7 | """
8 | 1. 自动 wrap markdown 文本中的裸链接
9 | 例如:
10 | 将 `https://www.xxxx.com`
11 | 转换成 `[https://www.xxxx.com](https://www.xxxx.com)`
12 | 2. 抽取 markdown 文本中图片链接
13 | """
14 |
15 | def __init__(self, text, img_types = None):
16 |
17 | # 定义图片格式的后缀
18 | if img_types is not None:
19 | if isinstance(img_types, str):
20 | self.img_types = [img_types]
21 | elif isinstance(img_types, list):
22 | self.img_types = img_types
23 | else:
24 | raise TypeError('img_types must be str or list!')
25 | else:
26 | self.img_types = ['png', 'jpg']
27 |
28 | # markdown文本内容
29 | self.text = text
30 |
31 | # 所有已装饰过的链接起始位置
32 | self.wrapped_pos = self._get_wrapped_pos()
33 |
34 | def _get_wrapped_pos(self):
35 | """
36 | 获取已修饰过的链接位置
37 | 返回带有位置信息的list
38 | """
39 |
40 | # 匹配
41 | # [...](...)
42 | # <... src="...">
43 | # <... href="...">
44 | wrapped_link_pattern = re.compile(
45 | r"(?:\[([^\[\]]*?)\]\(|(?:src|href) *= *\")"
46 | r"(https?://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|])"
47 | r"(?:\)|\")",
48 | re.I | re.S,
49 | )
50 |
51 | # 查找所有链接
52 | wrapped_pos = []
53 | def _find_pos(match):
54 | # 匹配到的子串
55 | line = match.group()
56 | for g in match.groups():
57 | if g:
58 | # 分组内容在子串中的偏移量
59 | offset = line.index(g)
60 |
61 | wrapped_pos.append(match.start() + offset)
62 |
63 | # 将已匹配过的内容替换掉
64 | # 避免无法识别[link](link)
65 | line = line[:offset] + ' '*len(g) + line[offset+len(g):]
66 |
67 | wrapped_link_pattern.sub(_find_pos, self.text)
68 | return wrapped_pos
69 |
70 | def _md_wrapper(self, match):
71 | """
72 | 修饰裸链接
73 | 返回修饰后的链接
74 | """
75 |
76 | pattern = match.group()
77 | url = match.groups()[0]
78 |
79 | # 如果链接已修饰,返回匹配的原字符串
80 | # 否则返回修饰后的字符串
81 | if match.start() in self.wrapped_pos:
82 | return pattern
83 | else:
84 | return pattern.replace(url, '[{0}]({0})'.format(url))
85 |
86 | def wrap_links(self):
87 | """
88 | 查找并修饰所有链接
89 | 返回修饰后的文本
90 | """
91 |
92 | # 匹配所有http/https开头的链接
93 | link_pattern = re.compile(
94 | r"(https?://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|])",
95 | re.I | re.S,
96 | )
97 | return link_pattern.sub(self._md_wrapper, self.text)
98 |
99 | def extract_images(self):
100 | """
101 | 导出图片链接
102 | 返回图片链接的集合
103 | """
104 |
105 | # 匹配
106 | #
107 | # 
108 | img_url_pattern = re.compile(
109 | r" .*?"
110 | r"|"
111 | r"!\[.*?\]\((.*?\.(?:{0}))\)".format(
112 | '|'.join(self.img_types), '(?:"|\')'),
113 | re.I,
114 | )
115 | img_urls = img_url_pattern.findall(self.text)
116 | return set(map(lambda url: url[0] if url[0] else url[1], img_urls))
117 |
118 |
119 | if __name__ == '__main__':
120 |
121 | text = '''
122 |  
123 | Hello World! There is an image:
124 | and There is a link: https://www.google.com/search?q=Hello
125 | and There is a good link: [https://www.google.com/search?q=Hello](https://www.google.com/search?q=Hello)
126 | and There is a video:
127 |
128 | extra image:
129 | false
130 | false
131 | true
132 | true asdf
133 |
134 | extra link:
135 | wrap welcome to http://www.google.com !
136 | wrap http://www.google.com
137 | wrap welcome to "http://www.google.com"
138 | wrap welcome to [http://www.google.com] !
139 | wrap welcome to https://www.google.com!
140 | do not wrap
141 | '''
142 |
143 | h = Helper(text)
144 | urls = h.extract_images()
145 | print('-'*30)
146 | print(h.text)
147 | print('-'*30)
148 | print(h.wrap_links())
149 | print('-'*30)
150 | for u in urls:
151 | print('image url:', u)
152 | print('-'*30)
153 |
154 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # little python projects, 一些小的python项目.
2 | ###### [Personal Page](https://jeffylu.github.io/) 个人主页
3 |
4 | - - -
5 |
6 | ##### [0001](0001) 验证码生成器,稍作修改可变成密钥生成器
7 | ##### [0002](0002) 统计纯英文文本行数、单词量以及每个单词出现次数
8 | ##### [0003](0003) 统计文件夹内所有代码的总行数(包括空行和注释)并分别标记出来
9 | ##### [0004](0004) 简易员工信息管理系统,包括对员工信息的增、删、改、查
10 | ##### [0005](0005) 批量更改文件后缀名
11 | ##### [0006](0006) 爬取多特软件站所有软件信息
12 | ##### [0007](0007) 强解三阶幻方
13 | ##### [0008](0008) 基于Django的简易个人待办事项管理应用
14 | ##### [0009](0009) 模拟登录新浪微博(后期会更新微博数据的爬取)
15 | ##### [0010](0010) 翻译器(有道API)
16 | ##### [0011](0011) 日志文件操作
17 | ##### [0012](0012) 基于Django的BMI指数计算和分析应用
18 | ##### [0013](0013) 模拟登录正方教务系统爬取成绩信息
19 | ##### [0014](0014) 用户信息加密管理器
20 | ##### [0015](0015) 爬取绍兴客运所有汽车一周内的行车记录
21 | ##### [0016](0016) markdown链接解析
--------------------------------------------------------------------------------