kindle manager
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
125
changelog.md
125
changelog.md
@@ -1,17 +1,80 @@
|
|||||||
|
|
||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
## 1.0.0 (20200526)
|
## 1.1.1 (20200626)
|
||||||
### create
|
### feature
|
||||||
- unittest
|
- remove pandas because it will make the package too large,
|
||||||
- abstract note/bookmark/highlight from kindle clipping
|
I write mTable calss to operate table data structure
|
||||||
- formatter output to special file
|
- add sort function in nTableModel class which
|
||||||
|
make table can be sort by clicking table header!! cheer!!
|
||||||
|
- make installer package by pyistaller, but run "open kmanapp.app",<br>
|
||||||
|
always show:<br>
|
||||||
|
"LSOpenURLsWithRole() failed with error -10810 for the file /Users/mark/penv/kman/Release/kmanapp.app."<br>
|
||||||
|
which spend me a great mount of time,<br>
|
||||||
|
and I baidu/bing/google all about discuss try to solve it,<br>
|
||||||
|
but problem still here! :cry: :cry: :cry:<br>
|
||||||
|
- modify some bugs let application more stabler
|
||||||
|
|
||||||
|
### learn lesson
|
||||||
|
- how to write a iterable object
|
||||||
|
|
||||||
|
|
||||||
|
## 1.1.0 (20200617)
|
||||||
|
### feature
|
||||||
|
- book information grabbed from douban / amazon
|
||||||
|
|
||||||
|
## 1.0.5 (20200613)
|
||||||
|
### feature
|
||||||
|
- backup clips after kman closed, check and read backup file when kman started
|
||||||
|
- import words from kindle, export filtered words to MD/CSV
|
||||||
|
|
||||||
|
### learn lesson
|
||||||
|
- create virtual envirement
|
||||||
|
```
|
||||||
|
> mkvirtualenv kmanenv
|
||||||
|
> workon kmanenv
|
||||||
|
virtual env lib in ~/.virtualenvs/kmanenv/
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1.0.4 (20200604)
|
||||||
|
### feature
|
||||||
|
- refactoring kman.py
|
||||||
|
- creat constant class for all constant
|
||||||
|
- creat config dialog to do some constant configuration
|
||||||
|
- creat xman class for all clipping manipulation
|
||||||
|
- design config dialog & statusbar information
|
||||||
|
|
||||||
|
### learn lesson
|
||||||
|
- generate ui source(.py) use pyqtuic will 'import kmanapp\_rc',
|
||||||
|
so I need to use resouce file(.qrc) to manage resouce(icons),
|
||||||
|
and generator rcc binnay file, must kmanapp\_rc.py
|
||||||
|
command: pyside2-rcc -binary kmanapp.qrc -o kmanapp\_rc.py
|
||||||
|
- use QTime to check kindle kindle is connected or not
|
||||||
|
- implement table model which inherited from QAbstractTableModel, so
|
||||||
|
we can use **panda data structure**
|
||||||
|
|
||||||
|
## 1.0.3 (20200603)
|
||||||
|
### feature
|
||||||
|
- design GUI with qdesigner
|
||||||
|
- define toolbar action's slots
|
||||||
|
|
||||||
|
## 1.0.2 (20200530)
|
||||||
|
### feature
|
||||||
|
- remove duplication
|
||||||
|
- refactor some code
|
||||||
|
- optimize search feature
|
||||||
|
|
||||||
|
## learn lesson
|
||||||
|
- change dict keys between iteration, will throw RuntimeError:
|
||||||
|
dictionary changed size during iteration
|
||||||
|
- reference - http://www.cocoachina.com/articles/89748
|
||||||
|
- pyQt5 reference - https://www.learnpyqt.com/
|
||||||
|
|
||||||
## 1.0.1 (20200528)
|
## 1.0.1 (20200528)
|
||||||
### feature
|
### feature
|
||||||
- add search clip and some functions
|
- add search clip and some functions
|
||||||
|
|
||||||
## learn lesson
|
### learn lesson
|
||||||
- assign value to a not exist key, will throw KeyError, too inflexible!!! perl much better
|
- assign value to a not exist key, will throw KeyError, too inflexible!!! perl much better
|
||||||
- use defaultdict to solve obove problem, note, defaultdict only create two layer key auto
|
- use defaultdict to solve obove problem, note, defaultdict only create two layer key auto
|
||||||
```
|
```
|
||||||
@@ -40,52 +103,12 @@ b['1']['2'] = {'3':1} # OK
|
|||||||
- unittest error line number is not collect, **unitest bug**?
|
- unittest error line number is not collect, **unitest bug**?
|
||||||
- **unitest testcase execution sequence is disorder, so must create test data for each case**
|
- **unitest testcase execution sequence is disorder, so must create test data for each case**
|
||||||
|
|
||||||
## 1.0.2 (20200530)
|
|
||||||
### feature
|
|
||||||
- remove duplication
|
|
||||||
- refactor some code
|
|
||||||
- optimize search feature
|
|
||||||
|
|
||||||
## learn lesson
|
## 1.0.0 (20200526)
|
||||||
- change dict keys between iteration, will throw RuntimeError:
|
### create
|
||||||
dictionary changed size during iteration
|
- unittest
|
||||||
- reference - http://www.cocoachina.com/articles/89748
|
- abstract note/bookmark/highlight from kindle clipping
|
||||||
- pyQt5 reference - https://www.learnpyqt.com/
|
- formatter output to special file
|
||||||
|
|
||||||
|
|
||||||
## 1.0.3 (20200603)
|
|
||||||
### feature
|
|
||||||
- design GUI with qdesigner
|
|
||||||
- define toolbar action's slots
|
|
||||||
|
|
||||||
## 1.0.4 (20200604)
|
|
||||||
### feature
|
|
||||||
- refactoring kman.py
|
|
||||||
- creat constant class for all constant
|
|
||||||
- creat config dialog to do some constant configuration
|
|
||||||
- creat xman class for all clipping manipulation
|
|
||||||
- design config dialog & statusbar information
|
|
||||||
|
|
||||||
## learn lesson
|
|
||||||
- generate ui source(.py) use pyqtuic will 'import kmanapp\_rc',
|
|
||||||
so I need to use resouce file(.qrc) to manage resouce(icons),
|
|
||||||
and generator rcc binnay file, must kmanapp\_rc.py
|
|
||||||
command: pyside2-rcc -binary kmanapp.qrc -o kmanapp\_rc.py
|
|
||||||
- use QTime to check kindle kindle is connected or not
|
|
||||||
- implement table model which inherited from QAbstractTableModel, so
|
|
||||||
we can use **panda data structure**
|
|
||||||
|
|
||||||
## 1.0.5 (20200613)
|
|
||||||
### feature
|
|
||||||
- backup clips after kman closed, check and read backup file when kman started
|
|
||||||
- import words from kindle, export filtered words to MD/CSV
|
|
||||||
|
|
||||||
## learn lesson
|
|
||||||
|
|
||||||
|
|
||||||
## 1.1.0 (20200617)
|
|
||||||
### feature
|
|
||||||
- book information grabbed from douban / amazon
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
2
cui
2
cui
@@ -1,2 +1,4 @@
|
|||||||
|
|
||||||
pyuic mainwindow.ui -o mainwindow.py --no-protection
|
pyuic mainwindow.ui -o mainwindow.py --no-protection
|
||||||
pyside2-rcc -binary kmanapp.qrc -o kmanapp_rc.py
|
pyside2-rcc -binary kmanapp.qrc -o kmanapp_rc.py
|
||||||
|
cp -fr *py ~/penv/kman/
|
||||||
|
|||||||
35
kman.py
35
kman.py
@@ -8,6 +8,7 @@
|
|||||||
#########################################################
|
#########################################################
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
import sys
|
||||||
import os
|
import os
|
||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
@@ -65,15 +66,16 @@ LASTLINE = '=========='
|
|||||||
NTPREF = '--CG注:'
|
NTPREF = '--CG注:'
|
||||||
CLIPFN = 'My Clippings.txt'
|
CLIPFN = 'My Clippings.txt'
|
||||||
WORDFN = 'vocab.db'
|
WORDFN = 'vocab.db'
|
||||||
CLIPPATH = './'
|
CURRPATH = os.path.dirname(os.path.realpath(sys.argv[0]))
|
||||||
OUTPREF = './clip'
|
OUTPREF = os.path.join(CURRPATH,'CLIP')
|
||||||
DEBUG = 1 # 0 - INFO; 1 - DEBUG
|
DEBUG = 1 # 0 - INFO; 1 - DEBUG
|
||||||
LOG2FILE = 1 # 0 - to stdio; 1 - to file
|
LOG2FILE = 1 # 0 - to stdio; 1 - to file
|
||||||
LOGFILE = 'log'
|
LOGFILE = 'log'
|
||||||
DELIMITER= '|'
|
DELIMITER= '|'
|
||||||
BACKUPNOTEFN = './backup/bk.note.data' # kindle notes
|
BACKUPFOLDER = os.path.join(CURRPATH,'backup')
|
||||||
BACKUPWORDFN = './backup/bk.word.data' # kindle words
|
BACKUPNOTEFN = os.path.join(BACKUPFOLDER,'bk.note.data') # kindle notes
|
||||||
BACKUPINFOFN = './backup/bk.info.data' # book information from douban/amazon
|
BACKUPWORDFN = os.path.join(BACKUPFOLDER,'bk.word.data') # kindle words
|
||||||
|
BACKUPINFOFN = os.path.join(BACKUPFOLDER,'bk.info.data') # book information from douban/amazon
|
||||||
#HEADER = {0:'type',1:'bookname',2:'author',3:'position',4:'date',5:'content'}
|
#HEADER = {0:'type',1:'bookname',2:'author',3:'position',4:'date',5:'content'}
|
||||||
|
|
||||||
# log info
|
# log info
|
||||||
@@ -119,6 +121,7 @@ r'''
|
|||||||
class kMan:
|
class kMan:
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
|
|
||||||
self.hlnum = 0
|
self.hlnum = 0
|
||||||
self.ntnum = 0
|
self.ntnum = 0
|
||||||
self.refleshtime = '2020/10/10 10:00:00'
|
self.refleshtime = '2020/10/10 10:00:00'
|
||||||
@@ -130,7 +133,7 @@ class kMan:
|
|||||||
kp = self.get_kindle_path()
|
kp = self.get_kindle_path()
|
||||||
|
|
||||||
if not kp:
|
if not kp:
|
||||||
s2 = u'Disconnected ({})'.format(CLIPPATH+CLIPFN)
|
s2 = u'Disconnected ({})'.format(os.path.join(CURRPATH,CLIPFN))
|
||||||
else:
|
else:
|
||||||
with open(kp+'/system/version.txt' , 'r', encoding='utf8', errors='ignore') as f:
|
with open(kp+'/system/version.txt' , 'r', encoding='utf8', errors='ignore') as f:
|
||||||
s2 = u'Connected ({}) version {}'.format(kp,f.read().strip())
|
s2 = u'Connected ({}) version {}'.format(kp,f.read().strip())
|
||||||
@@ -597,7 +600,7 @@ class kMan:
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def import_clips(self, fp=(CLIPPATH+CLIPFN)):
|
def import_clips(self, fp=os.path.join(CURRPATH, CLIPFN)):
|
||||||
"""import clips from local file or kindle
|
"""import clips from local file or kindle
|
||||||
4 lines for each section seperated with '======='
|
4 lines for each section seperated with '======='
|
||||||
so read 4 lines before '======='
|
so read 4 lines before '======='
|
||||||
@@ -616,6 +619,8 @@ class kMan:
|
|||||||
path = fn
|
path = fn
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if not os.path.exists(fp): return {}
|
||||||
|
|
||||||
# loop to fill books dict
|
# loop to fill books dict
|
||||||
with open(fp, 'r', encoding='utf8', errors='ignore') as f:
|
with open(fp, 'r', encoding='utf8', errors='ignore') as f:
|
||||||
bks = defaultdict(dict)
|
bks = defaultdict(dict)
|
||||||
@@ -670,7 +675,7 @@ class kMan:
|
|||||||
return self.drop_duplicate(bks)
|
return self.drop_duplicate(bks)
|
||||||
|
|
||||||
# words operations
|
# words operations
|
||||||
def import_words(self, fp=(CLIPPATH+WORDFN)):
|
def import_words(self, fp=(os.path.join(CURRPATH,WORDFN))):
|
||||||
"""import words from local file or kindle
|
"""import words from local file or kindle
|
||||||
vocab.db -> tables: BOOK_INFO, LOOKUPS, WORDS
|
vocab.db -> tables: BOOK_INFO, LOOKUPS, WORDS
|
||||||
|
|
||||||
@@ -784,6 +789,19 @@ class kMan:
|
|||||||
|
|
||||||
return [nu, bk_wd_num]
|
return [nu, bk_wd_num]
|
||||||
|
|
||||||
|
class Util:
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_app_path():
|
||||||
|
"""Returns the base application path."""
|
||||||
|
if hasattr(sys, 'frozen'):
|
||||||
|
# Handles PyInstaller
|
||||||
|
return os.path.dirname(sys.executable) # 使用pyinstaller打包后的exe目录
|
||||||
|
return os.path.dirname(__file__) # 没打包前的py目录
|
||||||
|
|
||||||
|
|
||||||
if __name__=='__main__':
|
if __name__=='__main__':
|
||||||
#books = defaultdict(dict)
|
#books = defaultdict(dict)
|
||||||
km = kMan()
|
km = kMan()
|
||||||
@@ -815,4 +833,3 @@ if __name__=='__main__':
|
|||||||
|
|
||||||
# print data with json format
|
# print data with json format
|
||||||
logger.debug(json.dumps(books, indent=4, sort_keys=True, ensure_ascii=False))
|
logger.debug(json.dumps(books, indent=4, sort_keys=True, ensure_ascii=False))
|
||||||
|
|
||||||
|
|||||||
BIN
kmanapp.png
Normal file
BIN
kmanapp.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
80
kmanapp.py
80
kmanapp.py
@@ -9,11 +9,17 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import operator
|
||||||
from time import sleep
|
from time import sleep
|
||||||
import pandas as pd
|
#import pandas as pd
|
||||||
|
from mtable import mTable
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from PySide2.QtWidgets import (QMainWindow, QApplication, QLabel, QAbstractItemView, QHeaderView)
|
#if hasattr(sys, 'frozen'):
|
||||||
|
# os.environ['PATH'] = sys._MEIPASS + ";" + os.environ['PATH']
|
||||||
|
|
||||||
|
from PySide2.QtWidgets import (QMainWindow, QApplication, QMessageBox,
|
||||||
|
QFileDialog, QLabel, QAbstractItemView, QHeaderView)
|
||||||
from PySide2.QtCore import (QAbstractTableModel, Signal, QSize, QTimer, Qt)
|
from PySide2.QtCore import (QAbstractTableModel, Signal, QSize, QTimer, Qt)
|
||||||
from PySide2.QtGui import (QPalette, QStandardItemModel, QStandardItem, QIcon)
|
from PySide2.QtGui import (QPalette, QStandardItemModel, QStandardItem, QIcon)
|
||||||
|
|
||||||
@@ -81,6 +87,10 @@ class kmanWindow(QMainWindow):
|
|||||||
self.km = kMan()
|
self.km = kMan()
|
||||||
self.spide = bookInfoSpide()
|
self.spide = bookInfoSpide()
|
||||||
|
|
||||||
|
### in order to smaller the package,
|
||||||
|
### substitute pandas table with mTable
|
||||||
|
self.mt = mTable()
|
||||||
|
|
||||||
# initial check order:
|
# initial check order:
|
||||||
# 1. backup file bk.data ->
|
# 1. backup file bk.data ->
|
||||||
# 2. kindle(My Clippings.txt) ->
|
# 2. kindle(My Clippings.txt) ->
|
||||||
@@ -89,9 +99,8 @@ class kmanWindow(QMainWindow):
|
|||||||
if os.path.exists(BACKUPNOTEFN) and os.path.exists(BACKUPWORDFN):
|
if os.path.exists(BACKUPNOTEFN) and os.path.exists(BACKUPWORDFN):
|
||||||
self.books_data = self.km.json2dict(BACKUPNOTEFN)
|
self.books_data = self.km.json2dict(BACKUPNOTEFN)
|
||||||
self.words_data = self.km.json2dict(BACKUPWORDFN)
|
self.words_data = self.km.json2dict(BACKUPWORDFN)
|
||||||
if (len(self.books_data)*len(self.words_data[0]))>=1:
|
if self.books_data and len(self.books_data) >=1 and \
|
||||||
self.books_data = self.km.json2dict(BACKUPNOTEFN)
|
self.words_data and len(self.words_data[0])>=1:
|
||||||
self.words_data = self.km.json2dict(BACKUPWORDFN)
|
|
||||||
flg = 1
|
flg = 1
|
||||||
|
|
||||||
if not flg:
|
if not flg:
|
||||||
@@ -163,6 +172,7 @@ class kmanWindow(QMainWindow):
|
|||||||
ui.tablemodel = nTableModel(data)
|
ui.tablemodel = nTableModel(data)
|
||||||
ui.tableView.verticalHeader().hide()
|
ui.tableView.verticalHeader().hide()
|
||||||
ui.tableView.setModel(self.ui.tablemodel)
|
ui.tableView.setModel(self.ui.tablemodel)
|
||||||
|
ui.tableView.setSortingEnabled(True)
|
||||||
|
|
||||||
self.ui.textEdit.installEventFilter(self)
|
self.ui.textEdit.installEventFilter(self)
|
||||||
|
|
||||||
@@ -319,12 +329,17 @@ class kmanWindow(QMainWindow):
|
|||||||
|
|
||||||
def convert_to_panda(self, mlist, tp=0):
|
def convert_to_panda(self, mlist, tp=0):
|
||||||
if tp==0:
|
if tp==0:
|
||||||
pdframe = pd.DataFrame(mlist, \
|
#### XXX remove pandas
|
||||||
|
#pdframe = pd.DataFrame(mlist, \
|
||||||
|
# columns = ['Type','Bookname','Author','Position','Date','Content'])
|
||||||
|
self.mt.dataframe(mlist, \
|
||||||
columns = ['Type','Bookname','Author','Position','Date','Content'])
|
columns = ['Type','Bookname','Author','Position','Date','Content'])
|
||||||
else:
|
else:
|
||||||
pdframe = pd.DataFrame(mlist, \
|
#pdframe = pd.DataFrame(mlist, \
|
||||||
|
# columns = ['Word','Bookname','Author','Category'])
|
||||||
|
self.mt.dataframe(mlist, \
|
||||||
columns = ['Word','Bookname','Author','Category'])
|
columns = ['Word','Bookname','Author','Category'])
|
||||||
return pdframe
|
return self.mt
|
||||||
|
|
||||||
def tabledata_update_slot(self, s):
|
def tabledata_update_slot(self, s):
|
||||||
print('call tabledata_update_slot() {}'.format(s))
|
print('call tabledata_update_slot() {}'.format(s))
|
||||||
@@ -471,8 +486,8 @@ class kmanWindow(QMainWindow):
|
|||||||
self.messagebox(ico=2, info='\n\n kindle is not connected')
|
self.messagebox(ico=2, info='\n\n kindle is not connected')
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
self.books_data = self.km.import_clips(fp+'documents/'+CLIPFN)
|
self.books_data = self.km.import_clips(os.path.join(fp,'documents',CLIPFN))
|
||||||
self.words_data = self.km.import_words(fp+'system/vocabulary/'+WORDFN)
|
self.words_data = self.km.import_words(os.path.join(fp,'system','vocabulary',WORDFN))
|
||||||
[self.filter_books, self.filter_list] = self.km.filter_clips(self.books_data)
|
[self.filter_books, self.filter_list] = self.km.filter_clips(self.books_data)
|
||||||
self.filter_wordlist = self.km.filter_words(self.words_data)
|
self.filter_wordlist = self.km.filter_words(self.words_data)
|
||||||
|
|
||||||
@@ -676,6 +691,8 @@ class kmanWindow(QMainWindow):
|
|||||||
# backup file when kman closed
|
# backup file when kman closed
|
||||||
# so we can read backup file when kman start
|
# so we can read backup file when kman start
|
||||||
def closeEvent(self, e):
|
def closeEvent(self, e):
|
||||||
|
if not os.path.exists(BACKUPFOLDER): os.mkdir(BACKUPFOLDER)
|
||||||
|
|
||||||
with open(BACKUPNOTEFN, 'w', encoding='utf8', errors='ignore') as fw:
|
with open(BACKUPNOTEFN, 'w', encoding='utf8', errors='ignore') as fw:
|
||||||
fw.write(self.km.dict2json(self.books_data))
|
fw.write(self.km.dict2json(self.books_data))
|
||||||
with open(BACKUPWORDFN, 'w', encoding='utf8', errors='ignore') as fw:
|
with open(BACKUPWORDFN, 'w', encoding='utf8', errors='ignore') as fw:
|
||||||
@@ -711,27 +728,60 @@ class nTableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
def data(self, index, role):
|
def data(self, index, role):
|
||||||
if role == Qt.DisplayRole:
|
if role == Qt.DisplayRole:
|
||||||
value = self._data.iloc[index.row(), index.column()]
|
#### XXX remove pandas
|
||||||
|
#value = self._data.iloc[index.row(), index.column()]
|
||||||
|
value = self._data.get_iat(index.row(), index.column())
|
||||||
self.tabledata_update[str].emit('{} {}'.format(index.row(),index.column()))
|
self.tabledata_update[str].emit('{} {}'.format(index.row(),index.column()))
|
||||||
return str(value)
|
return str(value)
|
||||||
|
|
||||||
def rowCount(self, index):
|
def rowCount(self, index):
|
||||||
return self._data.shape[0]
|
#### XXX remove pandas
|
||||||
|
#return self._data.shape[1]
|
||||||
|
return self._data.get_num_rows()
|
||||||
|
|
||||||
def columnCount(self, index):
|
def columnCount(self, index):
|
||||||
return self._data.shape[1]
|
#### XXX remove pandas
|
||||||
|
#return self._data.shape[1]
|
||||||
|
return self._data.get_num_columns()
|
||||||
|
|
||||||
def headerData(self, section, orientation, role):
|
def headerData(self, section, orientation, role):
|
||||||
# section is the index of the column/row.
|
# section is the index of the column/row.
|
||||||
if role == Qt.DisplayRole:
|
if role == Qt.DisplayRole:
|
||||||
if orientation == Qt.Horizontal:
|
if orientation == Qt.Horizontal:
|
||||||
return str(self._data.columns[section])
|
#### XXX remove pandas
|
||||||
|
#return str(self._data.columns[section])
|
||||||
|
return str(self._data.get_columns()[section])
|
||||||
|
|
||||||
if orientation == Qt.Vertical:
|
if orientation == Qt.Vertical:
|
||||||
return str(self._data.index[section])
|
#### XXX remove pandas
|
||||||
|
#return str(self._data.index[section])
|
||||||
|
return str(self._data.get_index()[section])
|
||||||
|
|
||||||
|
# cheer!!!
|
||||||
|
def sort(self, column, order):
|
||||||
|
"""Sort table by given column number.
|
||||||
|
"""
|
||||||
|
self.layoutAboutToBeChanged.emit()
|
||||||
|
|
||||||
|
self._data.set_data(sorted(self._data.get_data(), key=operator.itemgetter(column)))
|
||||||
|
if order == Qt.DescendingOrder:
|
||||||
|
self._data.reverse()
|
||||||
|
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
print('sys.path[0]', sys.path[0])
|
||||||
|
print('sys.argv[0]', sys.argv[0])
|
||||||
|
print('os.path.realpath(sys.executable)', os.path.realpath(sys.executable))
|
||||||
|
print('os.path.realpath(sys.argv[0]))', os.path.realpath(sys.argv[0]))
|
||||||
|
print('os.path.dirname(os.path.realpath(sys.executable))',
|
||||||
|
os.path.dirname(os.path.realpath(sys.executable)))
|
||||||
|
print('os.path.dirname(os.path.realpath(sys.argv[0]))',
|
||||||
|
os.path.dirname(os.path.realpath(sys.argv[0])))
|
||||||
|
util = Util()
|
||||||
|
print('get_app_path',util.get_app_path())
|
||||||
|
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
kmw = kmanWindow()
|
kmw = kmanWindow()
|
||||||
icon = QIcon()
|
icon = QIcon()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE QtCreatorProject>
|
<!DOCTYPE QtCreatorProject>
|
||||||
<!-- Written by QtCreator 4.11.2, 2020-06-20T21:18:52. -->
|
<!-- Written by QtCreator 4.11.2, 2020-06-25T21:57:36. -->
|
||||||
<qtcreator>
|
<qtcreator>
|
||||||
<data>
|
<data>
|
||||||
<variable>EnvironmentId</variable>
|
<variable>EnvironmentId</variable>
|
||||||
|
|||||||
@@ -55,5 +55,6 @@
|
|||||||
<file>icons/amazon.png</file>
|
<file>icons/amazon.png</file>
|
||||||
<file>icons/flower.png</file>
|
<file>icons/flower.png</file>
|
||||||
<file>kmanapp.ico</file>
|
<file>kmanapp.ico</file>
|
||||||
|
<file>kmanapp.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
1467
kmanapp_rc.py
1467
kmanapp_rc.py
File diff suppressed because it is too large
Load Diff
31
makepkg.md
Normal file
31
makepkg.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
# 打包问题
|
||||||
|
|
||||||
|
|
||||||
|
1. 'ValueError: too many values to unpack (expected 2)
|
||||||
|
A: [资源文件打包配置](https://blog.csdn.net/weixin_42052836/article/details/82315118)
|
||||||
|
资源文件包括打包的python项目使用的相关文件,如图标文件,文本文件等。对于此类资源文件的打包需要设置Analysis的datas,如例子所示datas接收元组:datas=[(SETUP_DIR+'lib\\icon','lib\\icon'),(SETUP_DIR+'data','data')]。元组的组成为(原项目中资源文件路径,打包后路径),例子中的(SETUP_DIR+'lib\\icon','lib\\icon')表示从D:\\install_test\\FASTPLOT\\lib\\icon下的图标文件打包后放入打包结果路径下的lib\\icon目录。
|
||||||
|
|
||||||
|
1. (kmanenv) [gavin@gavin-2 tkman]$open Release/kmanapp.app/
|
||||||
|
FAIL - LSOpenURLsWithRole() failed with error -10810 for the file /Users/mark/penv/tkman/Release/kmanapp.app.
|
||||||
|
(kmanenv) [gavin@gavin-2 tkman]$Release/kmanapp.app/Contents/MacOS/kmanapp
|
||||||
|
OK
|
||||||
|
A:
|
||||||
|
1. 到其他路径区执行(kmanenv) [gavin@gavin-2 penv]$py kman/kmanapp.py看有没有问题
|
||||||
|
2. 所有路径合并,不用+, 用os.path.join()
|
||||||
|
3.
|
||||||
|
|
||||||
|
1. (kmanenv) [gavin@gavin-2 tkman]$pyinstaller --distpath Release -w -c -i kmanapp.ico kmanapp.spec
|
||||||
|
21750 ERROR: Can not find path ./libshiboken2.abi3.5.15.dylib (needed by /Users/mark/.virtualenvs/kmanenv/lib/python3.7/site-packages/PySide2/QtGui.abi3.so)
|
||||||
|
A: rm -fr __pycache__, 重新打包
|
||||||
|
|
||||||
|
|
||||||
|
1. (kmanenv) [gavin@gavin-2 kman]$Release/kmanapp.app/Contents/MacOS/kmanapp
|
||||||
|
NameError: name 'kMan' is not defined
|
||||||
|
A: pathex=['/Users/mark/penv/kman',]
|
||||||
|
|
||||||
|
|
||||||
|
# reference
|
||||||
|
1. [ModuleNotFoundError: No module named 'pkg_resources.py2_warn' ](https://blog.csdn.net/qq_40608730/article/details/104864943)
|
||||||
|
https://www.cnblogs.com/yemeng/p/6253097.html
|
||||||
|
https://blog.csdn.net/SCDS_Zyx/article/details/82052396
|
||||||
128
mtable.py
Normal file
128
mtable.py
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
#########################################################
|
||||||
|
## @file : mtable.py
|
||||||
|
## @desc : pandas is to large,
|
||||||
|
## so i implement a simple table data structure
|
||||||
|
## by my self
|
||||||
|
## @create : 2020/06/25
|
||||||
|
## @author : Chengan
|
||||||
|
## @email : douboer@gmail.com
|
||||||
|
#########################################################
|
||||||
|
|
||||||
|
class mTable():
|
||||||
|
|
||||||
|
def __init__(self, data=[], index=[], columns=[]):
|
||||||
|
self._data = data
|
||||||
|
self._index = index
|
||||||
|
self._columns = columns
|
||||||
|
self._width = 10
|
||||||
|
|
||||||
|
def dataframe(self, data=[], index=[], columns=[]):
|
||||||
|
self._data = data
|
||||||
|
self._index = index
|
||||||
|
self._columns = columns
|
||||||
|
|
||||||
|
def get_iat(self, row: int, column: int):
|
||||||
|
""" just like pandas iat"""
|
||||||
|
return self._data[row][column] if len(self._data)>0 else None
|
||||||
|
|
||||||
|
def get_num_rows(self):
|
||||||
|
return len(self._data) if len(self._data)>0 else 0
|
||||||
|
|
||||||
|
def get_num_columns(self):
|
||||||
|
return len(self._columns) if len(self._columns)>0 else 0
|
||||||
|
|
||||||
|
def reverse(self):
|
||||||
|
self._data.reverse()
|
||||||
|
|
||||||
|
def set_data(self, data=[]):
|
||||||
|
""" get table content"""
|
||||||
|
self._data = data
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
""" get table content"""
|
||||||
|
return self._data
|
||||||
|
|
||||||
|
def get_index(self):
|
||||||
|
""" just like pandas index"""
|
||||||
|
return self._index
|
||||||
|
|
||||||
|
def get_columns(self):
|
||||||
|
""" just like pandas columns"""
|
||||||
|
return self._columns
|
||||||
|
|
||||||
|
def set_repr_width(self, width):
|
||||||
|
self._width = width
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
""" print table """
|
||||||
|
w = self._width
|
||||||
|
s = ''.ljust(w-1,' ')
|
||||||
|
for c in self._columns: s += c.ljust(w,' ')
|
||||||
|
s += '\n'
|
||||||
|
len_index = len(self._index)
|
||||||
|
for i, r in enumerate(self._data):
|
||||||
|
s += self._index[i].ljust(w,' ') if i<len_index else str(i).ljust(w,' ')
|
||||||
|
for c in r:
|
||||||
|
s += str(c).ljust(w,' ')
|
||||||
|
s += '\n'
|
||||||
|
return s
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
# self.a就是当前要迭代的值
|
||||||
|
result = self.a
|
||||||
|
# 计算斐波那契数列的下一个值,并将a变成原来的b,将b变成下一个值
|
||||||
|
self.a, self.b = self.b, self.a + self.b
|
||||||
|
# 返回当前迭代的值
|
||||||
|
return result
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
if __name__=='__main__':
|
||||||
|
|
||||||
|
print('\n---------------------')
|
||||||
|
data = [['Ohiox','Ohio','Ohio','Nevada','Nevada'],
|
||||||
|
[2000,2001,2002,2001,2002],
|
||||||
|
[1.5,1.7,3.6,2.4,2.9],
|
||||||
|
[1.5,1.7,3.6,2.4,2.9],
|
||||||
|
]
|
||||||
|
|
||||||
|
mt = mTable(data,
|
||||||
|
index = ['one', 'two','three','four','five'],
|
||||||
|
columns = ['year','state','pop','debt','xx'])
|
||||||
|
|
||||||
|
print('== frame\n', mt)
|
||||||
|
print('== frame.iat[0, 0]\n', mt.get_iat(0, 0))
|
||||||
|
print('== frame.iat[1, 1]\n', mt.get_iat(1, 1))
|
||||||
|
print('== frame.iat[2, 2]\n', mt.get_iat(2, 2))
|
||||||
|
print('== frame.iat[2, 1]\n', mt.get_iat(2, 1))
|
||||||
|
print('== frame.shape[0]\n', mt.get_num_rows())
|
||||||
|
print('== frame.shape[1]\n', mt.get_num_columns())
|
||||||
|
print('== frame.columns\n', mt.get_columns())
|
||||||
|
print('== frame.index\n', mt.get_index())
|
||||||
|
|
||||||
|
mt = mTable(data,
|
||||||
|
columns = ['year','state','pop','debt','xx'])
|
||||||
|
print('== frame\n', mt)
|
||||||
|
print('== frame.iat[2, 1]\n', mt.get_iat(2, 1))
|
||||||
|
print('== frame.shape[0]\n', mt.get_num_rows())
|
||||||
|
print('== frame.shape[1]\n', mt.get_num_columns())
|
||||||
|
print('== frame.columns\n', mt.get_columns())
|
||||||
|
print('== frame.index\n', mt.get_index())
|
||||||
|
|
||||||
|
mt = mTable(data)
|
||||||
|
mt.set_repr_width(20)
|
||||||
|
print('== frame\n', mt)
|
||||||
|
print('== frame.iat[2, 1]\n', mt.get_iat(2, 1))
|
||||||
|
print('== frame.shape[0]\n', mt.get_num_rows())
|
||||||
|
print('== frame.shape[1]\n', mt.get_num_columns())
|
||||||
|
print('== frame.columns\n', mt.get_columns())
|
||||||
|
print('== frame.index\n', mt.get_index())
|
||||||
|
|
||||||
|
mt = mTable()
|
||||||
|
print('== frame\n', mt)
|
||||||
|
print('== frame.iat[2, 1]\n', mt.get_iat(2, 1))
|
||||||
|
print('== frame.shape[0]\n', mt.get_num_rows())
|
||||||
|
print('== frame.shape[1]\n', mt.get_num_columns())
|
||||||
|
print('== frame.columns\n', mt.get_columns())
|
||||||
|
print('== frame.index\n', mt.get_index())
|
||||||
@@ -1,3 +1,2 @@
|
|||||||
PySide2==5.15.0
|
PySide2==5.15.0
|
||||||
pandas==1.0.3
|
|
||||||
requests==2.23.0
|
requests==2.23.0
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
|
|
||||||
# CG test pandas
|
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
from kman import *
|
|
||||||
|
|
||||||
data = {
|
|
||||||
'state':['Ohio','Ohio','Ohio','Nevada','Nevada'],
|
|
||||||
'year':[2000,2001,2002,2001,2002],
|
|
||||||
'pop':[1.5,1.7,3.6,2.4,2.9],
|
|
||||||
'xx':[1.5,1.7,3.6,2.4,2.9]
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
year state pop debt
|
|
||||||
one 2000 Ohio 1.5 16.5
|
|
||||||
two 2001 Ohio 1.7 16.5
|
|
||||||
three 2002 Ohio 3.6 16.5
|
|
||||||
four 2001 Nevada 2.4 16.5
|
|
||||||
five 2002 Nevada 2.9 16.5
|
|
||||||
"""
|
|
||||||
frame = pd.DataFrame(data,
|
|
||||||
index = ['one', 'two','three','four','five'],
|
|
||||||
columns = ['year','state','pop','debt','xx'])
|
|
||||||
|
|
||||||
print(frame.iat[0, 0])
|
|
||||||
print(frame.iat[1, 1])
|
|
||||||
print(frame.iat[2, 2])
|
|
||||||
print(frame.iat[2, 1])
|
|
||||||
|
|
||||||
'''
|
|
||||||
print('\n---------------------')
|
|
||||||
print(frame)
|
|
||||||
print('\n---------------------')
|
|
||||||
frame['debt']=16.5
|
|
||||||
print(frame)
|
|
||||||
print('\n---------------------')
|
|
||||||
print(frame.iloc[2]) #line 2
|
|
||||||
print('\n---------------------')
|
|
||||||
print(frame.iloc[[2,3],0:2])
|
|
||||||
print('\n---------------------')
|
|
||||||
print(frame.iloc[[2,3],0:2])
|
|
||||||
print('\n---------------------')
|
|
||||||
print(frame.iat[1, 1])
|
|
||||||
print('\n---------------------')
|
|
||||||
for index, row in frame.iterrows():
|
|
||||||
print(index)
|
|
||||||
print(row)
|
|
||||||
print('\n---------------------')
|
|
||||||
for row in frame.iterrows():
|
|
||||||
print(row)
|
|
||||||
#print(row[0], row[1])
|
|
||||||
print('\n---------------------')
|
|
||||||
print(frame.head(2))
|
|
||||||
print('\n---------------------')
|
|
||||||
print(frame.columns)
|
|
||||||
print('\n---------------------')
|
|
||||||
print(frame.index)
|
|
||||||
print('\n---------------------')
|
|
||||||
print(frame.to_dict())
|
|
||||||
print('\n---------------------')
|
|
||||||
'''
|
|
||||||
|
|
||||||
km = kMan()
|
|
||||||
books = km.import_clips()
|
|
||||||
print(books)
|
|
||||||
print('\n---------------------')
|
|
||||||
frame = pd.DataFrame(books)
|
|
||||||
print(frame)
|
|
||||||
|
|
||||||
print('\n---------------------')
|
|
||||||
data = [['Ohio','Ohio','Ohio','Nevada','Nevada'],
|
|
||||||
[2000,2001,2002,2001,2002],
|
|
||||||
[1.5,1.7,3.6,2.4,2.9],
|
|
||||||
[1.5,1.7,3.6,2.4,2.9],
|
|
||||||
[1.5,1.7,3.6,2.4,2.9],
|
|
||||||
]
|
|
||||||
frame = pd.DataFrame(data,
|
|
||||||
columns = ['year','state','pop','debt','xx'])
|
|
||||||
print(frame)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
|
|
||||||
#########################################################
|
|
||||||
## @file : tdict.py
|
|
||||||
## @desc : test dict
|
|
||||||
## @create : 2020/05/26
|
|
||||||
## @author : Chengan
|
|
||||||
## @email : douboer@gmail.com
|
|
||||||
#########################################################
|
|
||||||
|
|
||||||
import re
|
|
||||||
from collections import defaultdict
|
|
||||||
|
|
||||||
t = {'a':{'b':{'c':1}}}
|
|
||||||
t['a']['b']['c']=2
|
|
||||||
t['a']=2
|
|
||||||
print(t)
|
|
||||||
|
|
||||||
t1 = {'a':{'b':{'c':'3'}}}
|
|
||||||
t2 = t1
|
|
||||||
print(t2)
|
|
||||||
|
|
||||||
t3 = {'b':{'c':'4'}}
|
|
||||||
t4 = defaultdict(dict)
|
|
||||||
t4['a'] = t3
|
|
||||||
print(t4)
|
|
||||||
|
|
||||||
t4['a1']['b2'] = {'c3':'5'}
|
|
||||||
print(t4)
|
|
||||||
t4['a1']['d2'] = {'c3':'6'}
|
|
||||||
print(t4)
|
|
||||||
t4['a1']['e2'] = {'c3':'7'}
|
|
||||||
print(t4)
|
|
||||||
|
|
||||||
t4['b1']['b2'] = {'b5':1}
|
|
||||||
print(t4)
|
|
||||||
|
|
||||||
t4['b1']['b2']['b3'] = {'b5':1}
|
|
||||||
print(t4)
|
|
||||||
|
|
||||||
25236
tfile/tdouban.data
25236
tfile/tdouban.data
File diff suppressed because it is too large
Load Diff
@@ -1,19 +0,0 @@
|
|||||||
|
|
||||||
# CG test logging
|
|
||||||
|
|
||||||
import logging
|
|
||||||
import os.path
|
|
||||||
import time
|
|
||||||
|
|
||||||
logger = logging.getLogger()
|
|
||||||
logging.basicConfig(format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s',
|
|
||||||
level=logging.INFO)
|
|
||||||
logger.setLevel(logging.DEBUG)
|
|
||||||
|
|
||||||
tt = 'xxx'
|
|
||||||
tt1 = 'yyy'
|
|
||||||
logger.debug('this is a logger debug message {} {}'.format(tt,tt1))
|
|
||||||
logger.info('this is a logger info message')
|
|
||||||
logger.warning('this is a logger warning message')
|
|
||||||
logger.error('this is a logger error message')
|
|
||||||
logger.critical('this is a logger critical message')
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
#########################################################
|
|
||||||
## @file : tparseamazon.py
|
|
||||||
## @desc : test parse amazon response
|
|
||||||
## @create : 2020/05/26
|
|
||||||
## @author : Chengan
|
|
||||||
## @email : douboer@gmail.com
|
|
||||||
#########################################################
|
|
||||||
|
|
||||||
import re
|
|
||||||
import json
|
|
||||||
|
|
||||||
s =['''<div class="a-row a-size-base a-color-secondary"><span class="a-size-base" dir="auto"></span><span class="a-size-base" dir="auto">丹·琼斯(Dan Jones)</span><span class="a-size-base" dir="auto">, </span><span class="a-size-base" dir="auto">杰弗里·瓦夫罗(Geoffrey Wawro)</span><span class="a-size-base" dir="auto">, </span><span class="a-size-base" dir="auto">克里斯托弗·希伯特(Christopher Hibbert)</span><span class="a-size-base" dir="auto">, </span><span class="a-size-base" dir="auto">罗斯·金(Ross King)</span><span class="a-size-base" dir="auto">等等。</span></div>''',
|
|
||||||
'''<div class="a-row a-size-base a-color-secondary"><span class="a-size-base" dir="auto"></span><span class="a-size-base" dir="auto">马克·哈里斯</span><span class="a-size-base" dir="auto">、 </span><span class="a-size-base" dir="auto">黎绮妮</span></div>''',
|
|
||||||
'''<div class="a-row a-size-base a-color-secondary"><span class="a-size-base" dir="auto"></span><span class="a-size-base" dir="auto">马克·哈里斯</span><span class="a-size-base" dir="auto">、 </span><span class="a-size-base" dir="auto">黎绮妮</span></div>''',
|
|
||||||
'''<div class="a-row a-size-base a-color-secondary"><span class="a-size-base" dir="auto"></span><span class="a-size-base" dir="auto">[美]威廉·厄本(William Urban)</span><span class="a-size-base" dir="auto">, </span><span class="a-size-base" dir="auto">陆大鹏</span><span class="a-size-base" dir="auto">、 </span><span class="a-size-base" dir="auto">刘晓晖</span></div>''',
|
|
||||||
'''<div class="a-row a-size-base a-color-secondary"><span class="a-size-base" dir="auto"></span><span class="a-size-base" dir="auto">[英]安德鲁·罗伯茨(Andrew Roberts)</span><span class="a-size-base" dir="auto">、 </span><span class="a-size-base" dir="auto">苏然</span></div>''',
|
|
||||||
'''<div class="a-row a-size-base a-color-secondary"><span class="a-size-base" dir="auto"></span><span class="a-size-base" dir="auto">[英]安德鲁·罗伯茨(Andrew Roberts)</span><span class="a-size-base" dir="auto">、 </span><span class="a-size-base" dir="auto">苏然</span></div>''',
|
|
||||||
'''<div class="a-row a-size-base a-color-secondary"><span class="a-size-base" dir="auto"></span><span class="a-size-base" dir="auto">堀田江理(Eri Hotta)</span></div>''',
|
|
||||||
'''<div class="a-row a-size-base a-color-secondary"><span class="a-size-base" dir="auto"></span><span class="a-size-base" dir="auto">景跃进</span><span class="a-size-base" dir="auto">, </span><span class="a-size-base" dir="auto">张小劲</span><span class="a-size-base" dir="auto">、 </span><span class="a-size-base" dir="auto">余逊达</span></div>''']
|
|
||||||
|
|
||||||
tre = ['''<div data-asin="B07S46LMCK" data-index="3" data-uuid="ef76dd52-2ab2-4372-8597-2c3258698b6e" data-component-type="s-search-result" class="sg-col-20-of-24 s-result-item s-asin sg-col-0-of-12 sg-col-28-of-32 sg-col-16-of-20 sg-col sg-col-32-of-36 sg-col-12-of-16 sg-col-24-of-28"><div class="sg-col-inner">''',
|
|
||||||
'''<img src="https://images-cn.ssl-images-amazon.com/images/I/41JFUwuJPCL._AC_UY218_.jpg"''',
|
|
||||||
'''alt="小窗幽记(国学大书院)(为人处世的智慧之果 修身齐家的行动指南)"''',
|
|
||||||
'''<div class="a-row a-size-base a-color-secondary"><span class="a-size-base" dir="auto"></span><span class="a-size-base" dir="auto">野田洋次郎</span><span class="a-size-base" dir="auto">、 </span><span class="a-size-base" dir="auto">蒋青青</span></div>''',
|
|
||||||
'''<span aria-label="4.7 颗星,最多 5 颗星">''',
|
|
||||||
'''<span class="a-letter-space"></span></div></div>''']
|
|
||||||
|
|
||||||
|
|
||||||
for t in s:
|
|
||||||
ret = re.split('<span.+?auto\">|<\/span',t)
|
|
||||||
fret = ret[3::4]
|
|
||||||
#print(json.dumps(re.split('<span.+?auto\">|<\/span',t), indent=2, ensure_ascii=False))
|
|
||||||
print(','.join(fret))
|
|
||||||
|
|
||||||
re_asin = re.compile(r'''^<div data-asin=\"(.+?)\" data-index''')
|
|
||||||
re_img = re.compile(r'''^<img src=\"(.+?)\"$''')
|
|
||||||
re_bn = re.compile(r'''^alt=\"(.+?)\"$''')
|
|
||||||
re_author = re.compile(r'''^<div class=.+auto\"><\/span>.+$''')
|
|
||||||
re_rate = re.compile(r'''^<span aria-label=\"(.+?)\">$''')
|
|
||||||
#re_end = re.compile(r'''<\/body><\/html>''')
|
|
||||||
re_end = re.compile(r'''^<span class=\"a-letter-space\"><\/span><\/div><\/div>''')
|
|
||||||
|
|
||||||
print(re.search(re_asin, tre[0]).group(1))
|
|
||||||
print(re.search(re_img , tre[1]).group(1))
|
|
||||||
print(re.search(re_bn , tre[2]).group(1))
|
|
||||||
print(re.search(re_author,tre[3]).group(0))
|
|
||||||
print(re.search(re_rate, tre[4]).group(1))
|
|
||||||
print(re.search(re_end , tre[5]).group(0))
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,341 +0,0 @@
|
|||||||
#########################################################
|
|
||||||
## @file : tparsedbcomments.py
|
|
||||||
## @desc : parse douban comments & reviews
|
|
||||||
## @create : 2020/06/15
|
|
||||||
## @author : Chengan
|
|
||||||
## @email : douboer@gmail.com
|
|
||||||
#########################################################
|
|
||||||
|
|
||||||
#comments - https://book.douban.com/subject/26591910/comments/hot?p=1
|
|
||||||
# https://book.douban.com/subject/26591910/comments/
|
|
||||||
#reviews - https://book.douban.com/subject/26591910/reviews/
|
|
||||||
# https://book.douban.com/subject/26591910/reviews?start=0
|
|
||||||
|
|
||||||
import requests
|
|
||||||
import json
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import logging
|
|
||||||
from collections import defaultdict
|
|
||||||
|
|
||||||
# log info
|
|
||||||
logger=logging.getLogger()
|
|
||||||
logger.addHandler(logging.FileHandler('log'))
|
|
||||||
logger.setLevel(logging.DEBUG)
|
|
||||||
|
|
||||||
FROMFILE=1
|
|
||||||
ISDOUBAN=1
|
|
||||||
IMGPATH = './downimg'
|
|
||||||
LINKPREF = 'https://book.douban.com/subject/' \
|
|
||||||
if ISDOUBAN else 'https://www.amazon.cn/s?k='
|
|
||||||
|
|
||||||
mheaders = {
|
|
||||||
'Host': 'www.douban.com',
|
|
||||||
'Referer': 'http://www.douban.com',
|
|
||||||
'User-Agent': 'User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'
|
|
||||||
}
|
|
||||||
#"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36"
|
|
||||||
|
|
||||||
mparams = {}
|
|
||||||
murl = ""
|
|
||||||
if ISDOUBAN==1:
|
|
||||||
mparams['Host']='www.douban.com',
|
|
||||||
mparams['search_text'] = 'bkname_xxx'
|
|
||||||
mparams['cat']='1001'
|
|
||||||
mparams['k']='bookname_xxx'
|
|
||||||
murl = "https://search.douban.com/book/subject_search"
|
|
||||||
else:
|
|
||||||
mheaders['Host']='www.amazon.cn'
|
|
||||||
mheaders['Referer']='http:/www.amazon.cn'
|
|
||||||
|
|
||||||
#https://www.amazon.cn/s?k={bookname}&i=stripbooks&__mk_zh_CN=亚马逊网站&ref=nb_sb_noss
|
|
||||||
mparams['Host']='www.amazon.cn'
|
|
||||||
mparams['k']='bkname_xxx'
|
|
||||||
mparams['i']='stripbooks'
|
|
||||||
mparams['__mk_zh_CN=']='亚马逊网站'
|
|
||||||
mparams['reg']='nb_sb_noss'
|
|
||||||
|
|
||||||
murl = 'https://www.amazon.cn/s'
|
|
||||||
|
|
||||||
testbooks=['24堂财富课',
|
|
||||||
'甲骨文',
|
|
||||||
'庆余年(精校版)',
|
|
||||||
'商君书-中华经典名著全本全注全译丛书',
|
|
||||||
'苏世民:我的经验与教训(2018读桥水达利欧的原则,2020看黑石苏世民的经验!一本书读懂从白手起家到华尔街新国王的传奇人生)',
|
|
||||||
'杨伯峻_论语译注',
|
|
||||||
'小窗幽记',
|
|
||||||
'少年凯歌',
|
|
||||||
'投资要义',
|
|
||||||
'白鱼解字',
|
|
||||||
'历史的巨镜',
|
|
||||||
'货币的教训',
|
|
||||||
'钱从哪里来',
|
|
||||||
'中国古代简史',
|
|
||||||
'罗马人的故事(套装共15册)',
|
|
||||||
'改变心理学的40项研究',
|
|
||||||
'如何假装懂音乐',
|
|
||||||
'管子(上下册)--中华经典名著全本全注全译(精)',
|
|
||||||
'投资中最简单的事',
|
|
||||||
'薛兆丰经济学讲义',
|
|
||||||
'枪炮、病菌与钢铁:人类社会的命运(世纪人文系列丛书·开放人文)',
|
|
||||||
'中央帝国的哲学密码',
|
|
||||||
'新编说文解字大全集(超值白金版)',
|
|
||||||
'市场的逻辑(增订本)',
|
|
||||||
'金融的本质:伯南克四讲美联储(看一个风云人物的金融思考)',
|
|
||||||
'从零开始学写作:个人增值的有效方法',
|
|
||||||
'中国国家治理的制度逻辑:一个组织学研究',
|
|
||||||
'中国为什么有前途:对外经济关系的战略潜能(第3版)',
|
|
||||||
'日本的世界观(《剑桥日本史》主编凝练之作三个人物故事串起日本两百年变局了解近代日本转向的必读之书理想国出品))']
|
|
||||||
|
|
||||||
class bookInfoSpide():
|
|
||||||
|
|
||||||
[re_bn,re_bn,re_score,re_star,re_author,re_end]=[None,None,None,None,None,None]
|
|
||||||
if ISDOUBAN==1:
|
|
||||||
re_bn=re.compile(r'''class=\"nbg.+?sid: (\d+?),.+?title=\"(.+?)\".+?img src=\"(.+?)\".+?rating_nums\">(.+?)<''', re.S)
|
|
||||||
re_bn=re.compile(r'''class=\"nbg.+?sid: (\d+?),.+?title=\"(.+?)\".+?img src=\"(.+?)\"''')
|
|
||||||
re_star=re.compile(r'''^<span class=\"allstar(\d+)\"></span>''')
|
|
||||||
re_score=re.compile(r'''class=\"rating_nums\">(.+?)<''')
|
|
||||||
re_ratenum=re.compile(r'''^<span>\((\d+)人评价\)</span>''')
|
|
||||||
re_author=re.compile(r'''class=\"subject-cast\">(.+?)<''')
|
|
||||||
else:
|
|
||||||
re_asin=re.compile(r'''^<div data-asin=\"(.+?)\" data-index''')
|
|
||||||
re_img=re.compile(r'''^<img src=\"(.+?)\"$''')
|
|
||||||
re_bn=re.compile(r'''^alt=\"(.+?)\"$''')
|
|
||||||
re_author=re.compile(r'''^<div class=.+auto\"><\/span>.+$''')
|
|
||||||
re_rate=re.compile(r'''^<span aria-label=\"(.+?)\">$''')
|
|
||||||
#re_end=re.compile(r'''<\/body><\/html>''')
|
|
||||||
re_end=re.compile(r'''^<span class=\"a-letter-space\"><\/span><\/div><\/div>''')
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def grab_book_info(self, mbkn: str):
|
|
||||||
"""mbkn - bookname to be spided
|
|
||||||
return: {
|
|
||||||
"25853071": { # sid
|
|
||||||
"link":"https://....xxxxx"
|
|
||||||
"bookname": "庆余年",
|
|
||||||
"img": "https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2575362797.jpg",
|
|
||||||
"score": "8.0",
|
|
||||||
"ratenum": "1000",
|
|
||||||
"author": "猫腻"
|
|
||||||
"publisher": "中华书局"
|
|
||||||
"publishing": "2015"
|
|
||||||
},...}
|
|
||||||
"""
|
|
||||||
|
|
||||||
bkinfo=defaultdict(dict)
|
|
||||||
sid=None
|
|
||||||
stat=None
|
|
||||||
|
|
||||||
if FROMFILE:
|
|
||||||
with open('./tdouban.data', 'r', encoding='utf8', errors='ignore') as f:
|
|
||||||
resp=f.read()
|
|
||||||
else:
|
|
||||||
if ISDOUBAN==1: #douban
|
|
||||||
mparams['search_text'] = mbkn
|
|
||||||
else: #amazon
|
|
||||||
mparams['k'] = mbkn
|
|
||||||
try:
|
|
||||||
session = requests.Session()
|
|
||||||
session.header = mheaders
|
|
||||||
session.params = mparams
|
|
||||||
r = session.get( url=murl, headers=mheaders, params=mparams)
|
|
||||||
#r = requests.get( url=murl, headers=mheaders, params=mparams)
|
|
||||||
except requests.exceptions.ConnectionError:
|
|
||||||
print('ConnectionError -- please wait 3 seconds')
|
|
||||||
time.sleep(3)
|
|
||||||
except requests.exceptions.ChunkedEncodingError:
|
|
||||||
print('ChunkedEncodingError -- please wait 3 seconds')
|
|
||||||
time.sleep(3)
|
|
||||||
except:
|
|
||||||
print('Unfortunitely -- An Unknow Error Happened, Please wait 3 seconds')
|
|
||||||
time.sleep(3)
|
|
||||||
if r.status_code != 200:
|
|
||||||
print('grab book {} info from webside failure'.format(mbkn))
|
|
||||||
|
|
||||||
if ISDOUBAN==1:
|
|
||||||
stat='SID'
|
|
||||||
for line in resp.split('\n'):
|
|
||||||
line=line.strip()
|
|
||||||
if line=='': continue
|
|
||||||
|
|
||||||
if stat=='SID':
|
|
||||||
ret=re.search(self.re_bn, line)
|
|
||||||
if ret:
|
|
||||||
sid=ret.group(1)
|
|
||||||
bkinfo[sid]['link']=os.path.join(LINKPREF,sid)
|
|
||||||
bkinfo[sid]['bookname']=ret.group(2)
|
|
||||||
bkinfo[sid]['img']=ret.group(3)
|
|
||||||
stat='STAR'
|
|
||||||
continue
|
|
||||||
elif stat=='STAR':
|
|
||||||
ret=re.search(self.re_star, line)
|
|
||||||
if ret:
|
|
||||||
star = ret.group(1)
|
|
||||||
if star=='00':
|
|
||||||
stat='AUTHOR'
|
|
||||||
elif int(star) > 0:
|
|
||||||
stat='SCORE'
|
|
||||||
elif stat=='SCORE':
|
|
||||||
ret=re.search(self.re_score, line)
|
|
||||||
if ret:
|
|
||||||
bkinfo[sid]['score']=ret.group(1)
|
|
||||||
stat='RATENUM'
|
|
||||||
continue
|
|
||||||
elif stat=='RATENUM':
|
|
||||||
ret=re.search(self.re_ratenum, line)
|
|
||||||
if ret:
|
|
||||||
bkinfo[sid]['ratenum']=ret.group(1)
|
|
||||||
stat='AUTHOR'
|
|
||||||
continue
|
|
||||||
elif stat=='AUTHOR':
|
|
||||||
ret=re.search(self.re_author, line)
|
|
||||||
if ret:
|
|
||||||
tt=ret.group(1).split(' / ')
|
|
||||||
if len(tt)>=3:
|
|
||||||
*author, bkinfo[sid]['publisher'], bkinfo[sid]['publishing']=tt
|
|
||||||
bkinfo[sid]['author']='/'.join(author)
|
|
||||||
else:
|
|
||||||
bkinfo[sid]['author']=ret[0]
|
|
||||||
stat='SID'
|
|
||||||
else: continue
|
|
||||||
else:
|
|
||||||
stat='ASIN'
|
|
||||||
for line in resp.split('\n'):
|
|
||||||
line=line.strip()
|
|
||||||
if line=='': continue
|
|
||||||
|
|
||||||
if stat=='ASIN':
|
|
||||||
ret=re.search(self.re_asin, line)
|
|
||||||
if ret:
|
|
||||||
sid=ret.group(1)
|
|
||||||
bkinfo[sid]['link']=os.path.join(LINKPREF,ret.group(1))
|
|
||||||
stat='IMG'
|
|
||||||
continue
|
|
||||||
elif stat=='IMG':
|
|
||||||
ret=re.search(self.re_img, line)
|
|
||||||
if ret:
|
|
||||||
bkinfo[sid]['img']=ret.group(1)
|
|
||||||
stat='BOOKNAME'
|
|
||||||
continue
|
|
||||||
elif stat=='BOOKNAME':
|
|
||||||
ret=re.search(self.re_bn, line)
|
|
||||||
if ret:
|
|
||||||
bkname=re.split(r'[((\s]',ret.group(1).strip())[0]
|
|
||||||
bkinfo[sid]['bookname']=bkname
|
|
||||||
stat='AUTHOR'
|
|
||||||
continue
|
|
||||||
elif stat=='AUTHOR':
|
|
||||||
ret=re.search(self.re_author, line)
|
|
||||||
if ret:
|
|
||||||
author=','.join(re.split('<span.+?auto\">|<\/span', ret.group(0))[3::4])
|
|
||||||
bkinfo[sid]['author']=author
|
|
||||||
stat='RATE'
|
|
||||||
continue
|
|
||||||
elif stat=='RATE':
|
|
||||||
ret=re.search(self.re_rate, line)
|
|
||||||
if ret:
|
|
||||||
bkinfo[sid]['rate']=ret.group(1).split(' ')[0]
|
|
||||||
stat='AUTHOR'
|
|
||||||
continue
|
|
||||||
else: continue
|
|
||||||
|
|
||||||
if re.search(self.re_end, line):
|
|
||||||
stat=='ASIN'
|
|
||||||
continue
|
|
||||||
|
|
||||||
return [mbkn, bkinfo]
|
|
||||||
|
|
||||||
def filter_spide_book(self, mbkinfo):
|
|
||||||
"""
|
|
||||||
mbkinfo:
|
|
||||||
douban
|
|
||||||
"10530219": {
|
|
||||||
"link": "https://book.douban.com/subject/10530219",
|
|
||||||
"bookname": "市场的逻辑",
|
|
||||||
"img": "https://img3.doubanio.com/view/subject/s/public/s8912552.jpg",
|
|
||||||
"score": "8.3",
|
|
||||||
"ratenum": "218",
|
|
||||||
"publisher": "世纪文景 上海人民出版社",
|
|
||||||
"publishing": "2012",
|
|
||||||
"author": "张维迎"
|
|
||||||
},...}
|
|
||||||
amazon
|
|
||||||
"孟子": {
|
|
||||||
"link": "https://....B07RN73425",
|
|
||||||
"bookname": "古典名著普及文库:孟子",
|
|
||||||
"img": "https://images-cn.ssl-images-amazon.com/images/I/511vbVrhIBL._AC_UY218_.jpg",
|
|
||||||
"rate": "3.9"
|
|
||||||
"author": "孙钦善",
|
|
||||||
}
|
|
||||||
|
|
||||||
"""
|
|
||||||
#booklink - https://book.douban.com/subject/{sid}
|
|
||||||
# f1/d1: mbkn include in bookname
|
|
||||||
# f2/d2: bookname include mbkn
|
|
||||||
# f3/d3: mbkn and bookname different
|
|
||||||
[f1,f2,f3]=[0,0,0]
|
|
||||||
[d1,d2,d3] =[{},{},{}]
|
|
||||||
mbkn=mbkinfo[0]
|
|
||||||
for k,v in mbkinfo[1].items():
|
|
||||||
bkn=v['bookname']
|
|
||||||
if len(v)==8:
|
|
||||||
if (not f1) and (mbkn in bkn):
|
|
||||||
f1=1
|
|
||||||
d1={mbkn:v}
|
|
||||||
elif (not f1) and (not f2) and (bkn in mbkn):
|
|
||||||
f2=1
|
|
||||||
d2={mbkn:v}
|
|
||||||
elif (not f3):
|
|
||||||
f3=1
|
|
||||||
d3={mbkn:v}
|
|
||||||
else: continue
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if f1:
|
|
||||||
return d1
|
|
||||||
elif f2:
|
|
||||||
return d2
|
|
||||||
elif f3:
|
|
||||||
return d3
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def down_book_img(self, mbkinfo):
|
|
||||||
import os
|
|
||||||
import socket
|
|
||||||
from urllib.request import urlretrieve
|
|
||||||
|
|
||||||
headers={'User-Agent': 'User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'}
|
|
||||||
|
|
||||||
for k,v in mbkinfo.items():
|
|
||||||
link=v['img']
|
|
||||||
if not os.path.exists(IMGPATH): os.mkdir(IMGPATH)
|
|
||||||
p=os.path.join(IMGPATH,link.split('/')[-1])
|
|
||||||
|
|
||||||
try:
|
|
||||||
img=requests.get(link, headers=headers)
|
|
||||||
if img.status_code==200:
|
|
||||||
with open(p, 'wb') as fp:
|
|
||||||
fp.write(img.content)
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
|
|
||||||
if __name__=='__main__':
|
|
||||||
|
|
||||||
spide=bookInfoSpide()
|
|
||||||
|
|
||||||
for bkname in testbooks:
|
|
||||||
bkname=re.split(r'[\((\-\::_\s]',bkname.strip())[0]
|
|
||||||
bkinfo=spide.grab_book_info(bkname)
|
|
||||||
filter_bkinfo=spide.filter_spide_book(bkinfo)
|
|
||||||
if filter_bkinfo: spide.down_book_img(filter_bkinfo)
|
|
||||||
|
|
||||||
#logger.debug('================ {} ================'.format(bkname))
|
|
||||||
#logger.debug(json.dumps(bkinfo,indent=2, ensure_ascii=False))
|
|
||||||
logger.debug('================ {} ================'.format(bkname))
|
|
||||||
logger.debug(json.dumps(filter_bkinfo,indent=2, ensure_ascii=False))
|
|
||||||
|
|
||||||
@@ -1,345 +0,0 @@
|
|||||||
#########################################################
|
|
||||||
## @file : tparsedbinfo.py
|
|
||||||
## @desc : kindle note managerment tool
|
|
||||||
## @create : 2020/06/15
|
|
||||||
## @author : Chengan
|
|
||||||
## @email : douboer@gmail.com
|
|
||||||
#########################################################
|
|
||||||
|
|
||||||
|
|
||||||
import requests
|
|
||||||
import json
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import logging
|
|
||||||
from collections import defaultdict
|
|
||||||
|
|
||||||
# log info
|
|
||||||
logger=logging.getLogger()
|
|
||||||
logger.addHandler(logging.FileHandler('log'))
|
|
||||||
logger.setLevel(logging.DEBUG)
|
|
||||||
|
|
||||||
FROMFILE=1
|
|
||||||
ISDOUBAN=1
|
|
||||||
IMGPATH = './downimg'
|
|
||||||
LINKPREF = 'https://book.douban.com/subject/' \
|
|
||||||
if ISDOUBAN else 'https://www.amazon.cn/s?k='
|
|
||||||
|
|
||||||
mheaders = {
|
|
||||||
'Host': 'www.douban.com',
|
|
||||||
'Referer': 'http://www.douban.com',
|
|
||||||
'User-Agent': 'User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'
|
|
||||||
}
|
|
||||||
#"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36"
|
|
||||||
|
|
||||||
mparams = {}
|
|
||||||
murl = ""
|
|
||||||
if ISDOUBAN==1:
|
|
||||||
mparams['Host']='www.douban.com',
|
|
||||||
mparams['search_text'] = 'bkname_xxx'
|
|
||||||
mparams['cat']='1001'
|
|
||||||
mparams['k']='bookname_xxx'
|
|
||||||
murl = "https://search.douban.com/book/subject_search"
|
|
||||||
else:
|
|
||||||
mheaders['Host']='www.amazon.cn'
|
|
||||||
mheaders['Referer']='http:/www.amazon.cn'
|
|
||||||
|
|
||||||
#https://www.amazon.cn/s?k={bookname}&i=stripbooks&__mk_zh_CN=亚马逊网站&ref=nb_sb_noss
|
|
||||||
mparams['Host']='www.amazon.cn'
|
|
||||||
mparams['k']='bkname_xxx'
|
|
||||||
mparams['i']='stripbooks'
|
|
||||||
mparams['__mk_zh_CN=']='亚马逊网站'
|
|
||||||
mparams['reg']='nb_sb_noss'
|
|
||||||
|
|
||||||
murl = 'https://www.amazon.cn/s'
|
|
||||||
|
|
||||||
testbooks=['24堂财富课',
|
|
||||||
'甲骨文',
|
|
||||||
'庆余年(精校版)',
|
|
||||||
'商君书-中华经典名著全本全注全译丛书',
|
|
||||||
'苏世民:我的经验与教训(2018读桥水达利欧的原则,2020看黑石苏世民的经验!一本书读懂从白手起家到华尔街新国王的传奇人生)',
|
|
||||||
'杨伯峻_论语译注',
|
|
||||||
'小窗幽记',
|
|
||||||
'少年凯歌',
|
|
||||||
'投资要义',
|
|
||||||
'白鱼解字',
|
|
||||||
'历史的巨镜',
|
|
||||||
'货币的教训',
|
|
||||||
'钱从哪里来',
|
|
||||||
'中国古代简史',
|
|
||||||
'罗马人的故事(套装共15册)',
|
|
||||||
'改变心理学的40项研究',
|
|
||||||
'如何假装懂音乐',
|
|
||||||
'管子(上下册)--中华经典名著全本全注全译(精)',
|
|
||||||
'投资中最简单的事',
|
|
||||||
'薛兆丰经济学讲义',
|
|
||||||
'枪炮、病菌与钢铁:人类社会的命运(世纪人文系列丛书·开放人文)',
|
|
||||||
'中央帝国的哲学密码',
|
|
||||||
'新编说文解字大全集(超值白金版)',
|
|
||||||
'市场的逻辑(增订本)',
|
|
||||||
'金融的本质:伯南克四讲美联储(看一个风云人物的金融思考)',
|
|
||||||
'从零开始学写作:个人增值的有效方法',
|
|
||||||
'中国国家治理的制度逻辑:一个组织学研究',
|
|
||||||
'中国为什么有前途:对外经济关系的战略潜能(第3版)',
|
|
||||||
'日本的世界观(《剑桥日本史》主编凝练之作三个人物故事串起日本两百年变局了解近代日本转向的必读之书理想国出品))']
|
|
||||||
|
|
||||||
class bookInfoSpide():
|
|
||||||
|
|
||||||
[re_bn,re_bn,re_score,re_star,re_author,re_description,re_end]=[None,None,None,None,None,None,None]
|
|
||||||
if ISDOUBAN==1:
|
|
||||||
re_bn=re.compile(r'''class=\"nbg.+?sid: (\d+?),.+?title=\"(.+?)\".+?img src=\"(.+?)\".+?rating_nums\">(.+?)<''', re.S)
|
|
||||||
re_bn=re.compile(r'''class=\"nbg.+?sid: (\d+?),.+?title=\"(.+?)\".+?img src=\"(.+?)\"''')
|
|
||||||
re_star=re.compile(r'''^<span class=\"allstar(\d+)\"></span>''')
|
|
||||||
re_score=re.compile(r'''class=\"rating_nums\">(.+?)<''')
|
|
||||||
re_ratenum=re.compile(r'''^<span>\((\d+)人评价\)</span>''')
|
|
||||||
re_author=re.compile(r'''class=\"subject-cast\">(.+?)<''')
|
|
||||||
re_description=re.compile(r'''^<p>(.+?)(<\/p>){0,1}$''')
|
|
||||||
else:
|
|
||||||
re_asin=re.compile(r'''^<div data-asin=\"(.+?)\" data-index''')
|
|
||||||
re_img=re.compile(r'''^<img src=\"(.+?)\"$''')
|
|
||||||
re_bn=re.compile(r'''^alt=\"(.+?)\"$''')
|
|
||||||
re_author=re.compile(r'''^<div class=.+auto\"><\/span>.+$''')
|
|
||||||
re_rate=re.compile(r'''^<span aria-label=\"(.+?)\">$''')
|
|
||||||
#re_end=re.compile(r'''<\/body><\/html>''')
|
|
||||||
re_end=re.compile(r'''^<span class=\"a-letter-space\"><\/span><\/div><\/div>''')
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def grab_book_info(self, mbkn: str):
|
|
||||||
"""mbkn - bookname to be spided
|
|
||||||
return: {
|
|
||||||
"25853071": { # sid
|
|
||||||
"link":"https://....xxxxx"
|
|
||||||
"bookname": "庆余年",
|
|
||||||
"img": "https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2575362797.jpg",
|
|
||||||
"score": "8.0",
|
|
||||||
"ratenum": "1000",
|
|
||||||
"author": "猫腻"
|
|
||||||
"publisher": "中华书局"
|
|
||||||
"publishing": "2015"
|
|
||||||
},...}
|
|
||||||
"""
|
|
||||||
|
|
||||||
bkinfo=defaultdict(dict)
|
|
||||||
sid=None
|
|
||||||
stat=None
|
|
||||||
|
|
||||||
if FROMFILE:
|
|
||||||
with open('./tdouban.data', 'r', encoding='utf8', errors='ignore') as f:
|
|
||||||
resp=f.read()
|
|
||||||
else:
|
|
||||||
if ISDOUBAN==1: #douban
|
|
||||||
mparams['search_text'] = mbkn
|
|
||||||
else: #amazon
|
|
||||||
mparams['k'] = mbkn
|
|
||||||
try:
|
|
||||||
session = requests.Session()
|
|
||||||
session.header = mheaders
|
|
||||||
session.params = mparams
|
|
||||||
r = session.get( url=murl, headers=mheaders, params=mparams)
|
|
||||||
#r = requests.get( url=murl, headers=mheaders, params=mparams)
|
|
||||||
except requests.exceptions.ConnectionError:
|
|
||||||
print('ConnectionError -- please wait 3 seconds')
|
|
||||||
time.sleep(3)
|
|
||||||
except requests.exceptions.ChunkedEncodingError:
|
|
||||||
print('ChunkedEncodingError -- please wait 3 seconds')
|
|
||||||
time.sleep(3)
|
|
||||||
except:
|
|
||||||
print('Unfortunitely -- An Unknow Error Happened, Please wait 3 seconds')
|
|
||||||
time.sleep(3)
|
|
||||||
if r.status_code != 200:
|
|
||||||
print('grab book {} info from webside failure'.format(mbkn))
|
|
||||||
|
|
||||||
if ISDOUBAN==1:
|
|
||||||
stat='SID'
|
|
||||||
for line in resp.split('\n'):
|
|
||||||
line=line.strip()
|
|
||||||
if line=='': continue
|
|
||||||
|
|
||||||
if stat=='SID':
|
|
||||||
ret=re.search(self.re_bn, line)
|
|
||||||
if ret:
|
|
||||||
sid=ret.group(1)
|
|
||||||
bkinfo[sid]['link']=os.path.join(LINKPREF,sid)
|
|
||||||
bkinfo[sid]['bookname']=ret.group(2)
|
|
||||||
bkinfo[sid]['img']=ret.group(3)
|
|
||||||
stat='STAR'
|
|
||||||
continue
|
|
||||||
elif stat=='STAR':
|
|
||||||
ret=re.search(self.re_star, line)
|
|
||||||
if ret:
|
|
||||||
star = ret.group(1)
|
|
||||||
if star=='00':
|
|
||||||
stat='AUTHOR'
|
|
||||||
elif int(star) > 0:
|
|
||||||
stat='SCORE'
|
|
||||||
elif stat=='SCORE':
|
|
||||||
ret=re.search(self.re_score, line)
|
|
||||||
if ret:
|
|
||||||
bkinfo[sid]['score']=ret.group(1)
|
|
||||||
stat='RATENUM'
|
|
||||||
continue
|
|
||||||
elif stat=='RATENUM':
|
|
||||||
ret=re.search(self.re_ratenum, line)
|
|
||||||
if ret:
|
|
||||||
bkinfo[sid]['ratenum']=ret.group(1)
|
|
||||||
stat='AUTHOR'
|
|
||||||
continue
|
|
||||||
elif stat=='AUTHOR':
|
|
||||||
ret=re.search(self.re_author, line)
|
|
||||||
if ret:
|
|
||||||
tt=ret.group(1).split(' / ')
|
|
||||||
if len(tt)>=3:
|
|
||||||
*author, bkinfo[sid]['publisher'], bkinfo[sid]['publishing']=tt
|
|
||||||
bkinfo[sid]['author']='/'.join(author)
|
|
||||||
else:
|
|
||||||
bkinfo[sid]['author']=ret[0]
|
|
||||||
stat='DESCRIPTION'
|
|
||||||
continue
|
|
||||||
elif stat=='DESCRIPTION':
|
|
||||||
ret=re.search(self.re_description, line)
|
|
||||||
if ret:
|
|
||||||
bkinfo[sid]['description']=ret.group(1)
|
|
||||||
stat='SID'
|
|
||||||
continue
|
|
||||||
else: continue
|
|
||||||
else:
|
|
||||||
stat='ASIN'
|
|
||||||
for line in resp.split('\n'):
|
|
||||||
line=line.strip()
|
|
||||||
if line=='': continue
|
|
||||||
|
|
||||||
if stat=='ASIN':
|
|
||||||
ret=re.search(self.re_asin, line)
|
|
||||||
if ret:
|
|
||||||
sid=ret.group(1)
|
|
||||||
bkinfo[sid]['link']=os.path.join(LINKPREF,ret.group(1))
|
|
||||||
stat='IMG'
|
|
||||||
continue
|
|
||||||
elif stat=='IMG':
|
|
||||||
ret=re.search(self.re_img, line)
|
|
||||||
if ret:
|
|
||||||
bkinfo[sid]['img']=ret.group(1)
|
|
||||||
stat='BOOKNAME'
|
|
||||||
continue
|
|
||||||
elif stat=='BOOKNAME':
|
|
||||||
ret=re.search(self.re_bn, line)
|
|
||||||
if ret:
|
|
||||||
bkname=re.split(r'[((\s]',ret.group(1).strip())[0]
|
|
||||||
bkinfo[sid]['bookname']=bkname
|
|
||||||
stat='AUTHOR'
|
|
||||||
continue
|
|
||||||
elif stat=='AUTHOR':
|
|
||||||
ret=re.search(self.re_author, line)
|
|
||||||
if ret:
|
|
||||||
author=','.join(re.split('<span.+?auto\">|<\/span', ret.group(0))[3::4])
|
|
||||||
bkinfo[sid]['author']=author
|
|
||||||
stat='RATE'
|
|
||||||
continue
|
|
||||||
elif stat=='RATE':
|
|
||||||
ret=re.search(self.re_rate, line)
|
|
||||||
if ret:
|
|
||||||
bkinfo[sid]['rate']=ret.group(1).split(' ')[0]
|
|
||||||
stat='AUTHOR'
|
|
||||||
continue
|
|
||||||
else: continue
|
|
||||||
|
|
||||||
if re.search(self.re_end, line):
|
|
||||||
stat=='ASIN'
|
|
||||||
continue
|
|
||||||
|
|
||||||
return [mbkn, bkinfo]
|
|
||||||
|
|
||||||
def filter_spide_book(self, mbkinfo):
|
|
||||||
"""
|
|
||||||
mbkinfo:
|
|
||||||
douban
|
|
||||||
"10530219": {
|
|
||||||
"link": "https://book.douban.com/subject/10530219",
|
|
||||||
"bookname": "市场的逻辑",
|
|
||||||
"img": "https://img3.doubanio.com/view/subject/s/public/s8912552.jpg",
|
|
||||||
"score": "8.3",
|
|
||||||
"ratenum": "218",
|
|
||||||
"publisher": "世纪文景 上海人民出版社",
|
|
||||||
"publishing": "2012",
|
|
||||||
"author": "张维迎"
|
|
||||||
},...}
|
|
||||||
amazon
|
|
||||||
"孟子": {
|
|
||||||
"link": "https://....B07RN73425",
|
|
||||||
"bookname": "古典名著普及文库:孟子",
|
|
||||||
"img": "https://images-cn.ssl-images-amazon.com/images/I/511vbVrhIBL._AC_UY218_.jpg",
|
|
||||||
"rate": "3.9"
|
|
||||||
"author": "孙钦善",
|
|
||||||
}
|
|
||||||
|
|
||||||
"""
|
|
||||||
#booklink - https://book.douban.com/subject/{sid}
|
|
||||||
# f1/d1: mbkn include in bookname
|
|
||||||
# f2/d2: bookname include mbkn
|
|
||||||
# f3/d3: mbkn and bookname different
|
|
||||||
[f1,f2,f3]=[0,0,0]
|
|
||||||
[d1,d2,d3] =[{},{},{}]
|
|
||||||
mbkn=mbkinfo[0]
|
|
||||||
for k,v in mbkinfo[1].items():
|
|
||||||
bkn=v['bookname']
|
|
||||||
if len(v)==9:
|
|
||||||
if (not f1) and (mbkn in bkn):
|
|
||||||
f1=1
|
|
||||||
d1={mbkn:v}
|
|
||||||
elif (not f1) and (not f2) and (bkn in mbkn):
|
|
||||||
f2=1
|
|
||||||
d2={mbkn:v}
|
|
||||||
elif (not f3):
|
|
||||||
f3=1
|
|
||||||
d3={mbkn:v}
|
|
||||||
else: continue
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if f1:
|
|
||||||
return d1
|
|
||||||
elif f2:
|
|
||||||
return d2
|
|
||||||
elif f3:
|
|
||||||
return d3
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def down_book_img(self, mbkinfo):
|
|
||||||
import os
|
|
||||||
import socket
|
|
||||||
from urllib.request import urlretrieve
|
|
||||||
|
|
||||||
headers={'User-Agent': 'User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'}
|
|
||||||
|
|
||||||
for k,v in mbkinfo.items():
|
|
||||||
link=v['img']
|
|
||||||
if not os.path.exists(IMGPATH): os.mkdir(IMGPATH)
|
|
||||||
p=os.path.join(IMGPATH,link.split('/')[-1])
|
|
||||||
|
|
||||||
try:
|
|
||||||
img=requests.get(link, headers=headers)
|
|
||||||
if img.status_code==200:
|
|
||||||
with open(p, 'wb') as fp:
|
|
||||||
fp.write(img.content)
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
|
|
||||||
if __name__=='__main__':
|
|
||||||
|
|
||||||
spide=bookInfoSpide()
|
|
||||||
|
|
||||||
for bkname in testbooks:
|
|
||||||
bkname=re.split(r'[\((\-\::_\s]',bkname.strip())[0]
|
|
||||||
bkinfo=spide.grab_book_info(bkname)
|
|
||||||
filter_bkinfo=spide.filter_spide_book(bkinfo)
|
|
||||||
if filter_bkinfo: spide.down_book_img(filter_bkinfo)
|
|
||||||
|
|
||||||
#logger.debug('================ {} ================'.format(bkname))
|
|
||||||
#logger.debug(json.dumps(bkinfo,indent=2, ensure_ascii=False))
|
|
||||||
logger.debug('================ {} ================'.format(bkname))
|
|
||||||
logger.debug(json.dumps(filter_bkinfo,indent=2, ensure_ascii=False))
|
|
||||||
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
@author: Taar
|
|
||||||
"""
|
|
||||||
|
|
||||||
#conversion of https://github.com/openwebos/qt/tree/master/examples/tutorials/modelview/5_edit
|
|
||||||
|
|
||||||
#I work with ints for values instead of strings (less cumbersome to add)
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import pandas as pd
|
|
||||||
|
|
||||||
from PySide2.QtWidgets import *
|
|
||||||
from PySide2.QtGui import (QBrush, QColor, QConicalGradient, QCursor, QFont,
|
|
||||||
QFontDatabase, QIcon, QKeySequence, QLinearGradient, QPalette, QPainter,
|
|
||||||
QPixmap, QRadialGradient, QStandardItem, QStandardItemModel)
|
|
||||||
from PySide2.QtCore import (QCoreApplication, QDate, QDateTime, QMetaObject,
|
|
||||||
QAbstractTableModel, QObject, QPoint, QRect, QSize, QTime,
|
|
||||||
QUrl, Qt, QThread, Signal, QTimer)
|
|
||||||
|
|
||||||
class TableModel(QAbstractTableModel):
|
|
||||||
|
|
||||||
def __init__(self, data):
|
|
||||||
super(TableModel, self).__init__()
|
|
||||||
self._data = data
|
|
||||||
|
|
||||||
def data(self, index, role):
|
|
||||||
if role == Qt.DisplayRole:
|
|
||||||
value = self._data.iloc[index.row(), index.column()]
|
|
||||||
return str(value)
|
|
||||||
|
|
||||||
def rowCount(self, index):
|
|
||||||
return self._data.shape[0]
|
|
||||||
|
|
||||||
def columnCount(self, index):
|
|
||||||
return self._data.shape[1]
|
|
||||||
|
|
||||||
def headerData(self, section, orientation, role):
|
|
||||||
# section is the index of the column/row.
|
|
||||||
if role == Qt.DisplayRole:
|
|
||||||
if orientation == Qt.Horizontal:
|
|
||||||
return str(self._data.columns[section])
|
|
||||||
|
|
||||||
if orientation == Qt.Vertical:
|
|
||||||
return str(self._data.index[section])
|
|
||||||
|
|
||||||
class MainWindow(QMainWindow):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
self.table = QTableView()
|
|
||||||
|
|
||||||
data = pd.DataFrame([
|
|
||||||
[1, 9, 2],
|
|
||||||
[1, 0, -1],
|
|
||||||
[3, 5, 2],
|
|
||||||
[3, 3, 2],
|
|
||||||
[5, 8, 9],
|
|
||||||
],
|
|
||||||
columns = ['A', 'B', 'C'],
|
|
||||||
index=['Row 1', 'Row 2', 'Row 3', 'Row 4', 'Row 5'])
|
|
||||||
|
|
||||||
self.model = TableModel(data)
|
|
||||||
self.table.setModel(self.model)
|
|
||||||
|
|
||||||
data = pd.DataFrame([
|
|
||||||
[1, 5, 5, 9],
|
|
||||||
[1, 5, 5, 9],
|
|
||||||
[1, 2, 1, 3],
|
|
||||||
[1, 1, 0, -1],
|
|
||||||
[1, 5, 5, 2],
|
|
||||||
[1, 5, 5, 8],
|
|
||||||
[1, 5, 5, 9],
|
|
||||||
],
|
|
||||||
columns = ['Aa', 'Bb', 'Cc', 'dd'],
|
|
||||||
index=['Row 1', 'Row 3', 'Row 4', 'Row 4', 'Row 5', '6', '7'])
|
|
||||||
|
|
||||||
self.model = TableModel(data)
|
|
||||||
self.table.setModel(self.model)
|
|
||||||
self.setCentralWidget(self.table)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
app=QApplication(sys.argv)
|
|
||||||
window=MainWindow()
|
|
||||||
window.show()
|
|
||||||
app.exec_()
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
#########################################################
|
|
||||||
## @file : tsqlite.py
|
|
||||||
## @desc : test sqlite3
|
|
||||||
## @create : 2020/06/11
|
|
||||||
## @author : Chengan
|
|
||||||
## @email : douboer@gmail.com
|
|
||||||
#########################################################
|
|
||||||
|
|
||||||
|
|
||||||
import sqlite3
|
|
||||||
|
|
||||||
dbname = 'vocab.db'
|
|
||||||
conn = sqlite3.connect(dbname)
|
|
||||||
|
|
||||||
try:
|
|
||||||
cursor = conn.cursor()
|
|
||||||
sql1 = '''select * from words;'''
|
|
||||||
sql2 = '''select * from lookups;'''
|
|
||||||
|
|
||||||
# fetch one record
|
|
||||||
cursor.execute(sql2)
|
|
||||||
one=cursor.fetchone()
|
|
||||||
print(one)
|
|
||||||
|
|
||||||
# fetch all records
|
|
||||||
for row in cursor.fetchall():
|
|
||||||
print(row)
|
|
||||||
|
|
||||||
# fetch table structure
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print('sql failure {}'.format(e))
|
|
||||||
pass
|
|
||||||
finally:
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
|
|
||||||
import platform
|
|
||||||
|
|
||||||
print(platform.system(),platform.machine(),platform.platform(aliased=0, terse=0) )
|
|
||||||
|
|
||||||
|
|
||||||
106
tfile/tthread.py
106
tfile/tthread.py
@@ -1,106 +0,0 @@
|
|||||||
|
|
||||||
import sys
|
|
||||||
import pyqtgraph as pg
|
|
||||||
from PyQt5.QtGui import *
|
|
||||||
from PyQt5.QtWidgets import *
|
|
||||||
from PyQt5.QtCore import QThread, pyqtSignal, QTimer
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
class PlotSin(QThread):
|
|
||||||
|
|
||||||
# 定义信号,self.y 是 numpy.array,所以信号数据类型为 object
|
|
||||||
signal = pyqtSignal(object)
|
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
super().__init__()
|
|
||||||
self.y = None
|
|
||||||
self.phase = 0
|
|
||||||
|
|
||||||
def sin(self):
|
|
||||||
self.x = np.arange(0, 3.0, 0.01)
|
|
||||||
self.y = np.sin(2 * np.pi * self.x + self.phase)
|
|
||||||
self.phase += 0.1
|
|
||||||
QThread.msleep(200) # 等待200毫秒
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
for _ in range(300):
|
|
||||||
self.sin()
|
|
||||||
self.signal.emit(self.y) # 向连接槽发射信号 self.y
|
|
||||||
|
|
||||||
class PlotSin_MainWindow(QDialog):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.initUI()
|
|
||||||
self.clock_time = 0
|
|
||||||
self.timer = QTimer(self) # 生成定时器
|
|
||||||
self.timer.timeout.connect(self.clock) # 绑定计时函数 self.clock
|
|
||||||
|
|
||||||
def initUI(self):
|
|
||||||
|
|
||||||
self.creatContorls("时间显示:")
|
|
||||||
self.creatResult("函数绘制:")
|
|
||||||
|
|
||||||
layout = QHBoxLayout()
|
|
||||||
layout.addWidget(self.controlsGroup)
|
|
||||||
layout.addWidget(self.resultGroup)
|
|
||||||
self.setLayout(layout)
|
|
||||||
self.beginButton.clicked.connect(self.clock_begin)
|
|
||||||
self.setGeometry(300, 300, 600, 300)
|
|
||||||
self.setWindowTitle('Plot Sine')
|
|
||||||
self.show()
|
|
||||||
|
|
||||||
def creatContorls(self,title):
|
|
||||||
self.controlsGroup = QGroupBox(title)
|
|
||||||
self.beginButton = QPushButton("开始")
|
|
||||||
numberLabel = QLabel("运行时间:")
|
|
||||||
self.clockLabel = QLabel("")
|
|
||||||
controlsLayout = QGridLayout()
|
|
||||||
controlsLayout.addWidget(numberLabel, 0, 0)
|
|
||||||
controlsLayout.addWidget(self.clockLabel, 0, 1)
|
|
||||||
controlsLayout.addWidget(self.beginButton, 3, 0)
|
|
||||||
self.controlsGroup.setLayout(controlsLayout)
|
|
||||||
|
|
||||||
def creatResult(self,title):
|
|
||||||
self.resultGroup = QGroupBox(title)
|
|
||||||
self.guiplot = pg.PlotWidget()
|
|
||||||
gridLayout = QGridLayout()
|
|
||||||
gridLayout.addWidget(self.guiplot,0,2,2,3)
|
|
||||||
self.resultGroup.setLayout(gridLayout)
|
|
||||||
|
|
||||||
def clock_begin(self):
|
|
||||||
if not self.timer.isActive():
|
|
||||||
self.recorder_thread = PlotSin()
|
|
||||||
self.recorder_thread.signal.connect(self.displaySin) # 绑定信号槽函数
|
|
||||||
self.recorder_thread.start() # 线程执行
|
|
||||||
self.clock()
|
|
||||||
self.timer.start(1000)
|
|
||||||
else:
|
|
||||||
self.beginButton.setText("开始")
|
|
||||||
self.clockLabel.setText("")
|
|
||||||
self.recorder_thread.terminate() # 终止线程
|
|
||||||
self.timer.stop() # 终止定时器
|
|
||||||
self.clock_time = 0
|
|
||||||
text = str(self.clock_time) + "s"
|
|
||||||
self.clockLabel.setText(text)
|
|
||||||
|
|
||||||
def clock(self):
|
|
||||||
text = str(self.clock_time) + "s"
|
|
||||||
self.clockLabel.setText(text)
|
|
||||||
if self.clock_time == 0:
|
|
||||||
self.beginButton.setText("结束")
|
|
||||||
|
|
||||||
self.clock_time += 1
|
|
||||||
|
|
||||||
def plotSin(self, y):
|
|
||||||
self.guiplot.clear()
|
|
||||||
self.guiplot.plot(y)
|
|
||||||
|
|
||||||
def displaySin(self, y):
|
|
||||||
self.plotSin(y)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
window = PlotSin_MainWindow()
|
|
||||||
window.show()
|
|
||||||
sys.exit(app.exec_())
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
|
|
||||||
# from webside not test, only for reference XXX
|
|
||||||
|
|
||||||
#coding=utf8
|
|
||||||
import random
|
|
||||||
import requests
|
|
||||||
import hashlib
|
|
||||||
appid = 'xxxxxx'
|
|
||||||
secretKey = 'xxxxx'
|
|
||||||
def get_md5(string):#返回字符串md5加密
|
|
||||||
hl = hashlib.md5()
|
|
||||||
hl.update(string.encode('utf-8'))
|
|
||||||
return hl.hexdigest()
|
|
||||||
|
|
||||||
def en_to_zh(en_str):#英语翻译成中文
|
|
||||||
api_url = 'http://api.fanyi.baidu.com/api/trans/vip/translate'
|
|
||||||
salt = random.randint(32768,65536)
|
|
||||||
sign = get_md5(appid + en_str + str(salt) + secretKey)
|
|
||||||
api_data = {
|
|
||||||
'q':en_str,
|
|
||||||
'from':'en',
|
|
||||||
'to':'zh',
|
|
||||||
'appid':appid,
|
|
||||||
'salt':salt,
|
|
||||||
'sign':sign
|
|
||||||
}
|
|
||||||
req_get = requests.get(api_url,api_data)
|
|
||||||
result = req_get.json()
|
|
||||||
print(result)
|
|
||||||
return result['trans_result']
|
|
||||||
|
|
||||||
print(en_to_zh('test'))
|
|
||||||
|
|
||||||
'''
|
|
||||||
import urllib.request
|
|
||||||
import urllib.parse
|
|
||||||
import json
|
|
||||||
from tkinter import *
|
|
||||||
root=Tk()
|
|
||||||
root.title("翻译小程序")
|
|
||||||
sw = root.winfo_screenwidth()
|
|
||||||
#得到屏幕宽度
|
|
||||||
sh = root.winfo_screenheight()
|
|
||||||
#得到屏幕高度
|
|
||||||
ww = 500
|
|
||||||
wh = 300
|
|
||||||
x = (sw-ww) / 2
|
|
||||||
y = (sh-wh) / 2-50
|
|
||||||
root.geometry("%dx%d+%d+%d" %(ww,wh,x,y))
|
|
||||||
lb2=Label(root,text="输入英文翻译中文,或者输入中文翻译英文,按回车键翻译。--版权所有,翻录必究。")
|
|
||||||
lb2.place(relx=0, rely=0.05)
|
|
||||||
txt = Text(root,font=("宋体",20))
|
|
||||||
txt.place(rely=0.6, relheight=0.4,relwidth=1)
|
|
||||||
inp1 = Entry(root,font=("",20))
|
|
||||||
inp1.place(relx=0, rely=0.2, relwidth=1, relheight=0.25)
|
|
||||||
def run2(event):
|
|
||||||
txt.delete("0.0",END)
|
|
||||||
a = (inp1.get())
|
|
||||||
content = a
|
|
||||||
url='http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
|
|
||||||
data={}
|
|
||||||
data['i'] = content
|
|
||||||
data['from'] = 'AUTO'
|
|
||||||
data['to'] = 'AUTO'
|
|
||||||
data['smartresult'] = 'dict'
|
|
||||||
data['client'] = 'fanyideskweb'
|
|
||||||
data['salt'] = '15812376682056'
|
|
||||||
data['sign'] = 'a1246b257926af8432be022564ff79f5'
|
|
||||||
data['ts'] = '1581237668205'
|
|
||||||
data['bv'] = '656f750600466990f874a839d9f5ad23'
|
|
||||||
data['doctype'] = 'json'
|
|
||||||
data['version'] = '2.1'
|
|
||||||
data['keyfrom'] = 'fanyi.web'
|
|
||||||
data['action'] = 'FY_BY_CLICKBUTTION'
|
|
||||||
data = urllib.parse.urlencode(data).encode('utf-8')
|
|
||||||
response = urllib.request.urlopen(url,data)
|
|
||||||
html = response.read().decode('utf-8')
|
|
||||||
target = json.loads(html)
|
|
||||||
s=("%s"%(target['translateResult'][0][0]['tgt'])+"\n")
|
|
||||||
print(s)
|
|
||||||
txt.insert(END, s)
|
|
||||||
def button1(event):
|
|
||||||
btn1 = Button(root, text='结果如下', font=("",12))
|
|
||||||
btn1.place(relx=0.35, rely=0.45, relwidth=0.2, relheight=0.15)
|
|
||||||
inp1.bind("<Return>",run2)
|
|
||||||
button1(1)
|
|
||||||
root.mainloop()
|
|
||||||
'''
|
|
||||||
@@ -31,6 +31,7 @@ class TestKman(unittest.TestCase):
|
|||||||
DELIMITER= '|'
|
DELIMITER= '|'
|
||||||
|
|
||||||
self.km = kMan()
|
self.km = kMan()
|
||||||
|
self.util = util()
|
||||||
|
|
||||||
global t_bm_sec
|
global t_bm_sec
|
||||||
global t_hl_sec
|
global t_hl_sec
|
||||||
@@ -232,6 +233,9 @@ class TestKman(unittest.TestCase):
|
|||||||
logger.debug(json.dumps(bookinfo, indent=2, ensure_ascii=False))
|
logger.debug(json.dumps(bookinfo, indent=2, ensure_ascii=False))
|
||||||
logger.debug('========== 5 ==========\n')
|
logger.debug('========== 5 ==========\n')
|
||||||
logger.debug(json.dumps(lookups, indent=2, ensure_ascii=False))
|
logger.debug(json.dumps(lookups, indent=2, ensure_ascii=False))
|
||||||
|
logger.debug('========== 6 ==========\n')
|
||||||
|
logger.debug(json.dumps(words, indent=2, ensure_ascii=False))
|
||||||
|
|
||||||
# test filter_words()
|
# test filter_words()
|
||||||
logger.debug('========== 7 ==========\n')
|
logger.debug('========== 7 ==========\n')
|
||||||
self.km.filter_words(lookups, '中国历史风云录 (陈舜臣作品)', tp=0)
|
self.km.filter_words(lookups, '中国历史风云录 (陈舜臣作品)', tp=0)
|
||||||
|
|||||||
62
x
62
x
@@ -1,62 +0,0 @@
|
|||||||
《解读基金——我的投资观和实践》e2780
|
|
||||||
薛兆丰经济学讲义
|
|
||||||
xxxx bkn 解读基金——我的投资观与实践(修订版) {'link': 'https://book.douban.com/subject/30784282', 'bookname': '解读基金——我的投资观与实践(修订版)', 'img': 'https://img3.doubanio.com/view/subject/s/public/s32292360.jpg', 'score': '8.1', 'ratenum': '469', 'publisher': '中国经济出版社', 'publishing': '2020', 'author': '季凯帆', 'description': '季凯帆的网名LaoK恐怕比他的真名还要响亮,因为他的系列科普帖《解读基金——我的投资观和实践》和博客曾经传遍了中国基金类网站的各个论坛,成为基金投资者入门和提高...'} len 9
|
|
||||||
xxxx bkn 解读基金 {'link': 'https://book.douban.com/subject/2051332', 'bookname': '解读基金', 'img': 'https://img3.doubanio.com/view/subject/s/public/s4561451.jpg', 'score': '8.3', 'ratenum': '3268', 'publisher': '中国经济出版社', 'publishing': '2007', 'author': '季凯帆', 'description': '作者季凯帆的网名-LaoK恐怕要比他的真名还要响亮,因为他的作品《我的投资观和实践》和他的博客几乎传遍了中国基金类网站的各个论坛,成为基金投资者入门和提高的必读文...'} len 9
|
|
||||||
金融街
|
|
||||||
xxxx bkn 金融街购物中心 {'link': 'https://book.douban.com/subject/162518', 'bookname': '金融街购物中心', 'img': 'https://img3.doubanio.com/icon/g162518-1.jpg', 'score': '7.6', 'ratenum': '725', 'publisher': '中信出版集团', 'publishing': '2017', 'author': '梁成', 'description': '本书以一家名为“鑫城财富”的公司为背景,以主人公杨晓波的视角,讲述了这家公司在金融街上的繁荣与衰落,也解答了人们对金融街及金融行业的种种疑问。这或许只是金融...'} len 9
|
|
||||||
xxxx bkn 金融街 {'link': 'https://book.douban.com/subject/1036614', 'bookname': '金融街', 'img': 'https://img1.doubanio.com/view/subject/s/public/s1026488.jpg', 'score': '6.5', 'ratenum': '49', 'publisher': '春风文艺出版社', 'publishing': '2004', 'author': '陈一夫', 'description': '具有黑社会性质的犯罪团伙把持着拥有上市子公司的怒潮集团,他们虽已取得了数十亿巨额贷款,但却依然资不抵债,靠骗取银行贷款、圈股市资金度日。瘸子处长识破了怒潮集...'} len 9
|
|
||||||
xxxx bkn 金融街 {'link': 'https://book.douban.com/subject/30874491', 'bookname': '金融街', 'img': 'https://img3.doubanio.com/f/shire/5522dd1f5b742d1e1394a17f44d590646b63871d/pics/book-default-lpic.gif', 'author': 'class="subject-cast">陈一夫 / 九州出版社<', 'description': '欢迎在北京金融街一带工作、生活的朋友们加入这个小组,讨论共同感兴趣的话题,分享收获与快乐!'} len 5
|
|
||||||
xxxx bkn 占领金融街 {'link': 'https://book.douban.com/subject/370556', 'bookname': '占领金融街', 'img': 'https://img3.doubanio.com/icon/g370556-1.jpg', 'author': 'class="subject-cast">鈴置洋孝<', 'description': '鈴置洋孝(鷲崎\u3000勲)×緑川光(五十嵐邦彦)'} len 5
|
|
||||||
xxxx bkn The Bank Job {'link': 'https://book.douban.com/subject/1889152', 'bookname': 'The Bank Job', 'img': 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p1521131641.jpg', 'score': '7.5', 'ratenum': '46711', 'publisher': '杰森·斯坦森', 'publishing': '2008', 'author': '原名:The Bank Job/罗杰·唐纳森', 'description': '本片根据真实历史事件改编。'} len 9
|
|
||||||
xxxx bkn 求金融街的同事中午吃饭 {'link': 'https://book.douban.com/subject/344904', 'bookname': '求金融街的同事中午吃饭', 'img': 'https://img9.doubanio.com/icon/user.jpg', 'score': '6.7', 'ratenum': '332', 'publisher': '中国友谊出版公司', 'publishing': '2018', 'author': '梁成', 'description': '故事发生在浮华光鲜的金融街,在这个看似高大上,实则暗水流深的商业世界里,交织着一场对“西南第一城”项目控股权的争夺。'} len 9
|
|
||||||
xxxx bkn 金融街没有爱情(Ⅰ、Ⅱ) {'link': 'https://book.douban.com/subject/34482165', 'bookname': '金融街没有爱情(Ⅰ、Ⅱ)', 'img': 'https://img3.doubanio.com/view/subject/s/public/s33325310.jpg', 'score': '7.3', 'ratenum': '68', 'publisher': '广西师范大学出版社', 'publishing': '2019', 'author': '刘玥', 'description': '◉内容简介'} len 9
|
|
||||||
xxxx bkn 金融街 {'link': 'https://book.douban.com/subject/1059122', 'bookname': '金融街', 'img': 'https://img3.doubanio.com/view/subject/s/public/s10284623.jpg', 'score': '6.7', 'ratenum': '19', 'publisher': '山东文艺出版社', 'publishing': '2003', 'author': '矫健', 'description': '金融街上故事多。咖啡之战,展现早期期货界风浪迭起、硝烟弥漫的情景。红星风暴,揭露任家炒股内幕,疑云重重,陷阱密布;大豆激斗,描绘中国加入WTO之后期货界最新状况...'} len 9
|
|
||||||
xxxx bkn 金融街:危险交易 {'link': 'https://book.douban.com/subject/34636557', 'bookname': '金融街:危险交易', 'img': 'https://img9.doubanio.com/view/subject/s/public/s33445355.jpg', 'score': '7.4', 'ratenum': '74', 'publisher': '中国友谊出版公司', 'publishing': '2019', 'author': '梁成', 'description': '终极之战,一触即发!私募基金、上市公司、金融大鳄……多方势力齐聚!开启资本市场ZUI真实的博弈,金钱世界ZUI残酷的厮杀!'} len 9
|
|
||||||
xxxx bkn 老天津金融街 {'link': 'https://book.douban.com/subject/11606234', 'bookname': '老天津金融街', 'img': 'https://img9.doubanio.com/view/subject/s/public/s26096804.jpg', 'publisher': '天津人民出版社', 'publishing': '2013', 'author': '档案馆', 'description': '老天津金融街(平装),ISBN:9787201067698,作者:'} len 7
|
|
||||||
xxxx bkn 愛と欲望の金融街 {'link': 'https://book.douban.com/subject/4175765', 'bookname': '愛と欲望の金融街', 'img': 'https://img9.doubanio.com/view/subject/s/public/s4083115.jpg', 'publisher': '講談社', 'publishing': '2003', 'author': '井村仁美', 'description': '出版社/著者からの内容紹介'} len 7
|
|
||||||
xxxx bkn 金融芝麻街 {'link': 'https://book.douban.com/subject/24526755', 'bookname': '金融芝麻街', 'img': 'https://img3.doubanio.com/view/subject/s/public/s26386853.jpg', 'publisher': '上書局', 'publishing': '2011', 'author': '蔡東豪', 'description': '金融和財經一直都是香港由政府到市民都最為關注的問題,蔡東豪繼《金錢之王》、《金融海嘯.我所學到的十件事》和《金融是文化》之後,又再推出新作,以金融和財經為切...'} len 7
|
|
||||||
大教堂与集市
|
|
||||||
xxxx bkn Rebuilding Notre Dame: Inside the Great Cathedral Rescue {'link': 'https://book.douban.com/subject/35034029', 'bookname': 'Rebuilding Notre Dame: Inside the Great Cathedral Rescue', 'img': 'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2599296429.jpg', 'score': '8.7', 'ratenum': '735', 'publisher': '', 'publishing': '2020', 'author': '原名:Rebuilding Notre Dame: Inside the Great Cathedral Rescue', 'description': '法国最著名哥特式建筑、法兰西最重要的文化遗产之一巴黎圣母院于2019年4月遭遇了百年难得一遇之大火,整个教堂顶几乎被大火摧毁,随后法国政府承诺将在五年内完成巴黎圣...'} len 9
|
|
||||||
xxxx bkn Andrea Bocelli : Music for Hope - Live from Duomo di Milano {'link': 'https://book.douban.com/subject/35034134', 'bookname': 'Andrea Bocelli : Music for Hope - Live from Duomo di Milano', 'img': 'https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2595998004.jpg', 'score': '9.5', 'ratenum': '244', 'publisher': '安德烈·波切利', 'publishing': '2020', 'author': '原名:Andrea Bocelli : Music for Hope - Live from Duomo di Milano', 'description': 'On Easter Sunday (April 12, 2020), by invitation of the City and of the Duomo cathedral of Milan, Italian global music icon Andrea Bocelli gave a solo perfor...'} len 9
|
|
||||||
xxxx bkn Sobor {'link': 'https://book.douban.com/subject/35064531', 'bookname': 'Sobor', 'img': 'https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2604453204.jpg', 'publisher': '谢尔盖·马林', 'publishing': '2020', 'author': '原名:Sobor/谢尔盖·金斯堡', 'description': '全球3000萬樂迷深情呼喚'} len 7
|
|
||||||
xxxx bkn La Catedral del mar {'link': 'https://book.douban.com/subject/30228956', 'bookname': 'La Catedral del mar', 'img': 'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2523139197.jpg', 'score': '8.2', 'ratenum': '152', 'publisher': '埃托尔·卢纳', 'publishing': '2018', 'author': '原名:La Catedral del mar/乔迪·弗拉德斯', 'description': '在14世纪的巴塞罗那,一名农奴决心要获得财富和自由,但却遭到了贵族阶层的鄙夷和宗教法庭的怀疑。'} len 9
|
|
||||||
xxxx bkn Katedra {'link': 'https://book.douban.com/subject/1417236', 'bookname': 'Katedra', 'img': 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2494920420.jpg', 'score': '7.7', 'ratenum': '4932', 'publisher': '托默克·巴金斯基', 'publishing': '2002', 'author': '原名:Katedra', 'description': '朝圣者在日食之时来到神秘的大教堂门外。'} len 9
|
|
||||||
xxxx bkn Ancient Megastructures: St. Paul's Cathedral {'link': 'https://book.douban.com/subject/5265489', 'bookname': 'Ancient Megastructures: St. Paul's Cathedral', 'img': 'https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2500960684.jpg', 'score': '8.6', 'ratenum': '175', 'publisher': '', 'publishing': '2009', 'author': '原名:Ancient Megastructures: St. Paul's Cathedral', 'description': '当代软件技术领域最重要的著作,中文版首次出版!'} len 9
|
|
||||||
xxxx bkn Kathedralen der Kultur {'link': 'https://book.douban.com/subject/25813839', 'bookname': 'Kathedralen der Kultur', 'img': 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2215497480.jpg', 'score': '7.5', 'ratenum': '48', 'publisher': '维姆·文德斯', 'publishing': '2014', 'author': '原名:Kathedralen der Kultur', 'description': ''If buildings could talk, what would they say about us?' Cathedrals of Culture offers six startling responses to this question. This 3D film project about th...'} len 9
|
|
||||||
xxxx bkn Murder in the Cathedral {'link': 'https://book.douban.com/subject/3081315', 'bookname': 'Murder in the Cathedral', 'img': 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2334286071.jpg', 'publisher': 'Clement McCallin', 'publishing': '1952', 'author': '原名:Murder in the Cathedral/乔治·赫勒林', 'description': '欧洲大教堂'} len 7
|
|
||||||
xxxx bkn 大数据译丛译者与读者互动小组 {'link': 'https://book.douban.com/subject/508070', 'bookname': '大数据译丛译者与读者互动小组', 'img': 'https://img1.doubanio.com/view/group/sqxs/public/ff4adc4140a6107.jpg', 'publisher': '约亨·希克', 'publishing': '1992', 'author': '原名:Willkommen im Dom', 'description': '德国行动起来(艾滋病联盟释放权力)运动的罕见记录。在1991年9月26日德国主教会议的闭幕式祈祷中,法兰克福行动小组聚集在一起,举行了一场壮观的抗议活动,抗议天主教...'} len 7
|
|
||||||
xxxx bkn Phineas and Ferb the Movie: Across the 2nd Dimension {'link': 'https://book.douban.com/subject/6890326', 'bookname': 'Phineas and Ferb the Movie: Across the 2nd Dimension', 'img': 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2176180893.jpg', 'score': '8.3', 'ratenum': '1179', 'publisher': '艾莉森·斯通勒', 'publishing': '2011', 'author': '原名:Phineas and Ferb the Movie: Across the 2nd Dimension/丹·波文迈尔', 'description': '故事叙述一个巧妙的契机,在泰瑞进入飞哥小佛家五周年纪念日当天,飞哥做了一个用大型鸭嘴兽羽毛球机器,而且两人就坐在里头,在阴错阳差之下撞上了背着两人驾着火箭车...'} len 9
|
|
||||||
xxxx bkn Building the Great Cathedrals {'link': 'https://book.douban.com/subject/25766508', 'bookname': 'Building the Great Cathedrals', 'img': 'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2158147438.jpg', 'publisher': '杰伊·桑德斯', 'publishing': '2010', 'author': '原名:Building the Great Cathedrals', 'description': '本片讲述了“八卦掌”传人女侠易水寒与中医小郎中钱成用正义战胜邪恶、用真诚孕育爱情、用美德诠释和谐的感人故事。'} len 7
|
|
||||||
xxxx bkn Salida de misa de doce del Pilar de Zaragoza {'link': 'https://book.douban.com/subject/6967938', 'bookname': 'Salida de misa de doce del Pilar de Zaragoza', 'img': 'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2550701347.jpg', 'publisher': '', 'publishing': '1896', 'author': '原名:Salida de misa de doce del Pilar de Zaragoza', 'description': '一群人走出萨拉戈萨的皮拉尔大教堂。'} len 7
|
|
||||||
xxxx bkn La inviolabilidad del domicilio se basa en el hombre que apa {'link': 'https://book.douban.com/subject/6124027', 'bookname': 'La inviolabilidad del domicilio se basa en el hombre que apa', 'img': 'https://img1.doubanio.com/view/subject/s/public/s4718927.jpg', 'publisher': '艾力克斯·皮培诺', 'publishing': '2011', 'author': '原名:La inviolabilidad del domicilio se basa en el hombre que apa', 'description': 'In the garden of a provincial summer house, a series of operations is carried out, involving a man, a woman and a group of individuals with certain convictions.'} len 7
|
|
||||||
xxxx bkn 大军阀与大老千 {'link': 'https://book.douban.com/subject/26862219', 'bookname': '大军阀与大老千', 'img': 'https://img3.doubanio.com/f/movie/b6dc761f5e4cf04032faa969826986efbecd54bb/pics/movie/movie_default_small.png', 'publisher': '恬妮', 'publishing': '1970', 'author': '原名:大军阀与大老千/谢君仪', 'description': '……'} len 7
|
|
||||||
中国历史风云录
|
|
||||||
xxxx bkn 中国历史风云录 {'link': 'https://book.douban.com/subject/3335643', 'bookname': '中国历史风云录', 'img': 'https://img3.doubanio.com/view/subject/s/public/s29347220.jpg', 'score': '8.0', 'ratenum': '788', 'publisher': '理想国 | 广西师范大学出版社', 'publishing': '2016', 'author': '陈舜臣/陈亚坤', 'description': '本书原名《中国五千年》,是陈舜臣的代表作。五千年华夏历史的风云变幻、世事沉浮,从远古到近代,从荣光到黯然,从分裂到统一,一个个大的时代的起落,一个个王朝的兴...'} len 9
|
|
||||||
xxxx bkn 共和国战争--新中国战争风云录 {'link': 'https://book.douban.com/subject/4906235', 'bookname': '共和国战争--新中国战争风云录', 'img': 'https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2591179524.jpg', 'score': '8.8', 'ratenum': '179', 'publisher': '道格拉斯·麦克阿瑟', 'publishing': '1996', 'author': '原名:共和国战争--新中国战争风云录', 'description': '《共和国战争》是一部历史文献系列纪录片,由当时的北京五岳文化策划公司策划,著名军旅作家冯精志参与撰稿,于20世纪90年代前期进行录制,并由中国康艺音像出版社在199...'} len 9
|
|
||||||
xxxx bkn 中国历史悬案 {'link': 'https://book.douban.com/subject/25895930', 'bookname': '中国历史悬案', 'img': 'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2185170549.jpg', 'publisher': '', 'publishing': '2010', 'author': '原名:中国历史悬案', 'description': '《中国历史悬案》收录了中国历史上影响最大、最有研究价值和最被广泛关注的历史悬案,内容涉及国宝之谜、帝王身世、战争悬案、宫廷政变、神秘宝藏、历史奇案等。'} len 7
|
|
||||||
xxxx bkn 中国变法历史风云录 {'link': 'https://book.douban.com/subject/31107144', 'bookname': '中国变法历史风云录', 'img': 'https://img3.doubanio.com/f/shire/5522dd1f5b742d1e1394a17f44d590646b63871d/pics/book-default-lpic.gif', 'author': 'class="subject-cast">商务印书馆 / 1992<', 'description': '《朝鲜历史风云录》合订本收录4位朝鲜历史名人小传和4次重大历史事件,其中包括:朝鲜民族英雄李舜臣;近代农民革命领袖全琫准;朝鲜1884年的政变;爱国志士安重根;著...'} len 5
|
|
||||||
xxxx bkn 经典军用飞机战史风云录 {'link': 'https://book.douban.com/subject/30668640', 'bookname': '经典军用飞机战史风云录', 'img': 'https://img3.doubanio.com/f/shire/5522dd1f5b742d1e1394a17f44d590646b63871d/pics/book-default-lpic.gif', 'publisher': '四川大学', 'publishing': '2010', 'author': '范咏涛', 'description': '《美国历史风云》为“美国视野”丛书之一。《美国历史风云》把美国建国两百多年的重要历史事件中选出对美国文化的形成和发展颇具影响的事件若干,编成16个单元向读者,...'} len 7
|
|
||||||
xxxx bkn 近现代历史风云沙龙 {'link': 'https://book.douban.com/subject/32466', 'bookname': '近现代历史风云沙龙', 'img': 'https://img3.doubanio.com/icon/g32466-1.jpg', 'author': 'class="subject-cast">林如 周正 瞿弦 张筠英<', 'description': '《中国历史故事版》听故事,学历史。这是一套由著名历史学家专门为中小学生编写的中国历史故事读本。它以中国各朝代的著名历史人物和事件为主线,搭建了中国历史知识的...'} len 5
|
|
||||||
xxxx bkn 中国历史故事版(8CD) {'link': 'https://book.douban.com/subject/6547839', 'bookname': '中国历史故事版(8CD)', 'img': 'https://img3.doubanio.com/view/subject/s/public/s6548603.jpg', 'author': 'class="subject-cast">林如 周正 瞿弦 张筠英<', 'description': '《中国历史故事版》听故事,学历史。这是一套由著名历史学家专门为中小学生编写的中国历史故事读本。它以中国各朝代的著名历史人物和事件为主线,搭建了中国历史知识的...'} len 5
|
|
||||||
xxxx bkn 故事会历史传说6:中国历史文化名人珍闻1 {'link': 'https://book.douban.com/subject/2172579', 'bookname': '故事会历史传说6:中国历史文化名人珍闻1', 'img': 'https://img3.doubanio.com/f/music/11496305e2cd99415ec541326b236b6b8d61175c/pics/music/default_cover/lpic/music-default.gif', 'author': 'class="subject-cast">未知艺术家<', 'description': '《故事会历史传说6:中国历史文化名人珍闻1》收集了在我国民间流传、传播着的大量与古代文化名人相关的民间传说和轶闻趣事,它们构思新颖独特,情节生动奇巧,内容或慷...'} len 5
|
|
||||||
xxxx bkn 中国历史传奇故事(3CD) {'link': 'https://book.douban.com/subject/6552322', 'bookname': '中国历史传奇故事(3CD)', 'img': 'https://img3.doubanio.com/view/subject/s/public/s6556931.jpg', 'author': 'class="subject-cast">未知艺术家<', 'description': '《中国历史传奇故事》记载了从传说中的五帝时代到近现代时期上下五千年的传奇故事,一一展现中华民族传奇历史人物的光辉事迹!故事材料丰富,忠于史实,它对古代历史重...'} len 5
|
|
||||||
xxxx bkn 故事会历史传说7:中国历代文化名人珍闻2 {'link': 'https://book.douban.com/subject/2172730', 'bookname': '故事会历史传说7:中国历代文化名人珍闻2', 'img': 'https://img3.doubanio.com/f/music/11496305e2cd99415ec541326b236b6b8d61175c/pics/music/default_cover/lpic/music-default.gif', 'author': 'class="subject-cast">未知艺术家<', 'description': '《中国历史》历史如画,也如人。闻香识女人,特色读王朝!我们一起来了解一下夹缝中生存的宋朝、徘徊在汉文化的元朝、皇帝个性多姿多彩的明朝……每一个王朝,自有其与...'} len 5
|
|
||||||
xxxx bkn 中国历史 {'link': 'https://book.douban.com/subject/3727029', 'bookname': '中国历史', 'img': 'https://img3.doubanio.com/f/music/11496305e2cd99415ec541326b236b6b8d61175c/pics/music/default_cover/lpic/music-default.gif', 'publisher': '', 'publishing': '2007', 'author': '原名:Histoire du look', 'description': '衣服款式颜色的发展史。能翻墙的同学可以到IMDb把相关资料补齐。@玛娜娜'} len 7
|
|
||||||
xxxx bkn 中国古代历史风云:列国交聘(套装上下册) {'link': 'https://book.douban.com/subject/30845381', 'bookname': '中国古代历史风云:列国交聘(套装上下册)', 'img': 'https://img3.doubanio.com/f/shire/5522dd1f5b742d1e1394a17f44d590646b63871d/pics/book-default-lpic.gif', 'author': 'class="subject-cast">马永刚 / 江西人民出版社<', 'description': '中国历史风云录 【日】陈舜臣 陈亚坤(译) 桂林:广西师范大学出版社2009.1 ISBN 978-7-5633-7973-6 CIP(2008)第200782号 ◇古代遗址与神话 P3中国神话的特征在于,它具有高度的片段性,而没有系统性。有个叫共...'} len 5
|
|
||||||
印度,漂浮的次大陆
|
|
||||||
xxxx bkn 印度,漂浮的次大陆 {'link': 'https://book.douban.com/subject/25716134', 'bookname': '印度,漂浮的次大陆', 'img': 'https://img3.doubanio.com/view/subject/s/public/s27044840.jpg', 'score': '7.5', 'ratenum': '623', 'publisher': '浙江大学出版社', 'publishing': '2013', 'author': '郭建龙', 'description': '为什么所有的人都喜欢把中国和印度做比较?'} len 9
|
|
||||||
xxxx bkn 神秘的南亚次大陆 {'link': 'https://book.douban.com/subject/1488786', 'bookname': '神秘的南亚次大陆', 'img': 'https://img1.doubanio.com/view/subject/s/public/s7616387.jpg', 'publisher': '海潮出版社', 'publishing': '2006', 'author': '白献竞,高晶编著', 'description': '印度是南亚次大陆的文明古国,是一个宗教复杂而具有多姿多彩的国家,也是一个充满奇异和神秘的大陆。'} len 7
|
|
||||||
xxxx bkn 看見南亞 {'link': 'https://book.douban.com/subject/30211892', 'bookname': '看見南亞', 'img': 'https://img1.doubanio.com/view/subject/s/public/s29757837.jpg', 'publisher': '八旗文化', 'publishing': '2018', 'author': '林汝羽', 'description': '五個國家、七個台灣人,九種觀察南亞的視角'} len 7
|
|
||||||
PythonCookbook
|
|
||||||
note_bleaf PythonCookbook(第3版)中文版(异步图书)(大卫·比斯利(DavidBeazley);布莱恩·K.琼斯 (1)
|
|
||||||
PythonCookbook
|
|
||||||
note_bleaf 印度,漂浮的次大陆 (36)
|
|
||||||
印度,漂浮的次大陆
|
|
||||||
note_bleaf 中国历史风云录(陈舜臣作品) (135)
|
|
||||||
中国历史风云录
|
|
||||||
note_bleaf 印度,漂浮的次大陆 (36)
|
|
||||||
印度,漂浮的次大陆
|
|
||||||
note_bleaf PythonCookbook(第3版)中文版(异步图书)(大卫·比斯利(DavidBeazley);布莱恩·K.琼斯 (1)
|
|
||||||
PythonCookbook
|
|
||||||
note_bleaf 印度,漂浮的次大陆 (36)
|
|
||||||
印度,漂浮的次大陆
|
|
||||||
Reference in New Issue
Block a user