├── .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 | ![效果图](temp_img/show.png) -------------------------------------------------------------------------------- /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 |
18 | {% csrf_token %} 19 | 21 | 22 |
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 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {% for item in items %} 19 | 20 | 21 | 22 | {% csrf_token %} 23 | 24 | 27 | 30 | 33 | 34 | 35 | {% endfor %} 36 | 37 |
ItemDoneRemoveOption
{{ item.item }}
25 | 26 | 28 | 29 | 31 | 32 |
38 |
39 | {% endif %} 40 | 41 | {% if done_items %} 42 |
43 |

Done

44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | {% for item in done_items %} 55 | 56 | 57 | 58 | {% csrf_token %} 59 | 60 | 63 | 66 | 69 | 70 | 71 | {% endfor %} 72 | 73 |
ItemRedoRemoveOption
{{ item.item }}
61 | 62 | 64 | 65 | 67 | 68 |
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 |
{% csrf_token %} 49 |
50 | {{ form.username.errors }} 51 | {{ form.username.label_tag }} {{ form.username }} 52 |
53 |
54 | {{ form.password.errors }} 55 | {{ form.password.label_tag }} {{ form.password }} 56 | 57 |
58 | {% url 'admin_password_reset' as password_reset_url %} 59 | {% if password_reset_url %} 60 | 63 | {% endif %} 64 |
65 | 66 |
67 |
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 | ![bmi](imgtemp/bmi.png) 44 | 45 | 46 | - - - 47 | 48 | **2. 站点数据统计** 49 | 50 |   此页可跟踪个人BMI走势,分析各年龄段BMI均值,健康等级分布情况等功能。 51 | 52 | ![statistics](imgtemp/statistics.png) 53 | 54 | - - - 55 | **3. 健康之家** 56 | 57 |   提供了几个健康社区 58 | 59 | ![health](imgtemp/health.png) 60 | 61 | - - - 62 | **4. 后台管理** 63 | 64 |   后台入口"/admin",用户名和密码为第三点中所创的。可对每项数据进行批量修改等操作。 65 | 66 | ![admin](imgtemp/admin.png) 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('%s
' % '\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 | 16 | 17 | 18 | 19 |
年龄:{{ data.age }}
性别:{{ data.gender }}
身高:{{ data.height }}
体重:{{ data.weight }}
20 |
21 | {% endfor%} 22 | {% else %} 23 |

无记录!

24 | {% endif %} 25 |
26 | 27 |
28 | 29 |

请填写以下数据:

30 |

31 | {% if form.errors %} 32 | 请修改下列错误项: 33 | {% endif %} 34 |

35 | 36 |
37 | {% csrf_token %} 38 | {{ form.as_p }} 39 | 40 |
41 | 42 |

BMI指数标准:

43 |

44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 |
偏瘦 < 18.5
18.5 <= 正常 <= 24.9
25.0 <= 偏胖 <= 29.9
30.0 <= 肥胖 <= 34.9
35.0 <= 重度肥胖 <= 39.9
39.9 < 极度肥胖
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 |
9 |

天天饮食网

10 | 11 |
12 |
13 |

keep健身网

14 | 15 |
16 |
17 |

Health健康网

18 | 19 |
20 |
21 |

瑜伽网

22 | 23 |
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 | 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 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 |
年龄段    记录(条)    BMI(平均)        年龄段    记录(条)    BMI(平均)
{{ age_bmi_count.0.0 }}{{age_bmi_count.0.2}}{{age_bmi_count.0.1}}{{ age_bmi_count.8.0 }}{{age_bmi_count.8.2}}{{age_bmi_count.8.1}}
{{ age_bmi_count.1.0 }}{{age_bmi_count.1.2}}{{age_bmi_count.1.1}}  {{ age_bmi_count.9.0 }}{{age_bmi_count.9.2}}{{age_bmi_count.9.1}}
{{ age_bmi_count.2.0 }}{{age_bmi_count.2.2}}{{age_bmi_count.2.1}}  {{ age_bmi_count.10.0 }}{{age_bmi_count.10.2}}{{age_bmi_count.10.1}}
{{ age_bmi_count.3.0 }}{{age_bmi_count.3.2}}{{age_bmi_count.3.1}}  {{ age_bmi_count.11.0 }}{{age_bmi_count.11.2}}{{age_bmi_count.11.1}}
{{ age_bmi_count.4.0 }}{{age_bmi_count.4.2}}{{age_bmi_count.4.1}}  {{ age_bmi_count.12.0 }}{{age_bmi_count.12.2}}{{age_bmi_count.12.1}}
{{ age_bmi_count.5.0 }}{{age_bmi_count.5.2}}{{age_bmi_count.5.1}}  {{ age_bmi_count.13.0 }}{{age_bmi_count.13.2}}{{age_bmi_count.13.1}}
{{ age_bmi_count.6.0 }}{{age_bmi_count.6.2}}{{age_bmi_count.6.1}}  {{ age_bmi_count.14.0 }}{{age_bmi_count.14.2}}{{age_bmi_count.14.1}}
{{ age_bmi_count.7.0 }}{{age_bmi_count.7.2}}{{age_bmi_count.7.1}}  

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 | ![aa](1.png) ![](https://static.xxx.com/static/img/logo_v1.png) 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链接解析 --------------------------------------------------------------------------------