#
import sys from PyQt4.QtCore import * from PyQt4.QtGui import * from PyQt4.QtWebKit import * start_url = 'http://searchex.yixun.com/?YTAG=1.100090000' def save_file(data,file='temp.txt'): f = open(file,'w') f.write(data) f.close() web = None def onDone(): f = open('scrapy.html','w') page = web.page().mainFrame().toHtml().toUtf8().data() f.write(page) f.close() print "Done ..." e = web.page().mainFrame().documentElement().findFirst("h3[class=m_classbox_hd]") print e.tagName() #print dir(e) print e.toPlainText().toUtf8().data() #.decode('gbk') #.decode('utf-8') #.encode('utf-8') save_file(e.toPlainText().toUtf8().data()) def onStart(): print "Started..." app = QApplication(sys.argv) web = QWebView() web.page().mainFrame().loadStarted.connect(onStart) web.page().mainFrame().loadFinished.connect(onDone) web.load(QUrl(start_url)) #print web.page().mainFrame().toHtml() print 'end' web.show() sys.exit(app.exec_())
開始抓yixun.com的商品信息,開始很開心,但一下子來了問題。http請求回來的商品分類條目用<a href=>, 但這個href不能直接使用,因為頁面加載之后會啟動js程序(一般都是jquery)對頁面element進行配置和處理,例如:設置風格、事件等等。
yixun玩了個防頁面過期的小技巧: >每個請求page在server都會產生一個有效期變量XY(具體算法不詳), >如果獲取商品<a>直接請求,server將返回失敗,因為<a href>并未包含XY >page加載完成之后js代碼設置<a>被點擊時觸發事件E,E將XY添加到<a href>內 >然后可以正確請求了 易迅防止請求頁面過期,在主頁中設置了一下參數: <script type="text/javascript"> window.yPageId = '17384560'; window.yPageLevel = '2';</script>
在頁面內容中顯示 <a ytag="40037" target="_blank">路由器</a> 注意: 返回的html就是如此
但如果用戶點擊(左鍵或者右鍵)此 node對象時,js代碼會動態插入一個YTAG的變量
未點擊: <a ytag="40037" target="_blank">路由器</a> 點擊: <a ytag="40037" target="_blank">路由器</a>
變量生成方式在這個js中實現: 此js 使用了jquery,頁面完成加載之后,將配置頁面元素的onclick行為,如果點擊了頁面元素,將YTAG屬性加入到商品<a href=""/>中去
js代碼凌亂可以使用: 進行格式化觀察
js代碼: G.header.search = { init: function() { G.header.search.event(); G.header.search.setInputStyle(); G.header.search.autoComplete(); },G.header.search.init();query: function() { var input = $("#q_show"), v = $.trim(input.val()), c = $("#cate_show").val(), ret = true, href = input.attr("_href"); if (v === G.header._Q_SHOW_DEF_TEXT && href) { window.location.href = href; ret = false; } else if (v === "" || v === G.header._Q_SHOW_DEF_TEXT) { if (!c || (c && c == "")) { input.focus(); ret = false; } } if ($('#q_show').parents("form").find('input[name="YTAG"]').length === 0) { var ytag = $('#q_show').parents("form").find('input[type="submit"]').attr("ytag"); var YTAG = (window.yPageLevel || 0) + '.' + (window.yPageId || 0) + ytag; $('#q_show').parents("form").append($('<input type="hidden" name="YTAG" value="' + YTAG + '" />')); } return ret; }
程序定義了G.header.search對象,并進行初始化init() ,query()是用戶點擊查詢時觸發使用 init()內部配置了query函數,用于鼠標點擊時候生成YTAG屬性 看代碼就很簡單了
YTAG生成方式就是 window.yPageLevel+'.'+window.yPageId + <a ytag="40037"> 這樣一個商品條目的href就獲得了
sudo kextunload /System/Library/Extensions/AppleHDA.kext sudo kextload /System/Library/Extensions/AppleHDA.kext 執行這兩條就行了
tkinter工作在主線程,而gevent是單線程工作,如何整合在一起? 瞅到一段代碼,迅速收藏 1 import gevent 2 from gevent import socket 3 import Tkinter as tk 4 5 class SockLoop(object): 6 def __init__(self, callback): 7 self.callback = callback 8 9 def __call__(self, sock, client): 10 while 1: 11 mes = sock.recv(256) 12 ret = self.callback(client, mes) 13 if ret is not None: 14 sock.send(ret) 15 16 def socket_server(port, callback): 17 ssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP) 18 ssock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 19 ssock.bind(('', port)) 20 ssock.listen(5) 21 22 while 1: 23 sock, client = ssock.accept() 24 gevent.spawn(callback, sock, client) 25 26 class App(object): 27 def __init__(self, root): 28 self.greenlet = None 29 self.root = root 30 self._build_window(root) 31 self.root.after(100, self._connect) 32 33 def add_text(self, text): 34 cleaned_string = text.replace('\r', '') 35 self.text.insert(tk.END, cleaned_string) 36 37 def quit(self): 38 self.root.quit() 39 40 def _build_window(self, root): 41 self.frame = tk.Frame(root) 42 self.text = tk.Text(self.frame) 43 self.quit_button = tk.Button(self.frame, text="Quit", command=self.quit) 44 self.text.pack() 45 self.quit_button.pack() 46 self.frame.pack() 47 48 def _connect(self): 49 self.greenlet = gevent.spawn( 50 socket_server, 51 8080, 52 SockLoop(lambda cl, txt: self.add_text("%s: %s" % (cl, txt)))) 53 self.gevent_loop_step() 54 55 def gevent_loop_step(self): 56 gevent.sleep() 57 self.root.after_idle(self.gevent_loop_step) 58 59 60 if __name__ == '__main__': 61 root = tk.Tk() 62 app = App(root) 63 root.mainloop()
俺不是果粉,但開發必須mac 參加的開發者大會,老外沒一個不是mac的,也的確如此,mac是開發神器,雖然貴點,但還是很值,對得起他的身價 。 這是一種態度,價值觀世界觀的體現 linux+windows的完美結合,不!! ui遠超windows
14.5k mac pro 15 retina 8G 內存 250 G ssd ,都配置差了點,但目前夠了,有錢了再買臺高配的,然后imac,還有那個外星桶的工作站
酷斃!
寫代碼,寫好代碼其實并不難,但如果要做好文檔,能完整闡述清楚自己的構思、想法和邏輯結構,這比較難,自己也缺少這方面的耐心。 很多opensource的代碼根本不需要文檔也能一目了然,這是一種定力 多年前的項目中使用到python和ffmpeg, 網絡上搜索了一下,均不能滿足自己的要求。ffmpeg的python綁定提供的均是文件級的訪問控制,也就是說沒有暴露更多的可控接口來用。 所以還是一切都自己來做 ffmpeg采用0.81版本以上,當時發現mov文件在0.71以下無法正常解碼,到0.81則解決了此問題。 python包裝ffmpeg的方式很多,最好的可能就是swig,但太煩了,最后選擇ctypes來訪問ffmpeg接口。 如果直接使用ffmpeg的api接口也不太合適,因為要暴露很多ffmpeg的接口、數據類型、常數定義等。 所以我是這么處理: 1. 編寫一個功能動態庫來包裝ffmpeg,提供基本的業務功能 ,屏蔽ffmpeg細節,這里叫ffmpeg_media_codec.dll 2. 用ctypes包裝此ffmpeg_media_codec.dll,這里是ffmpeg.py 3. 業務代碼使用ffmpeg.py提供的接口訪問、解碼多媒體文件 代碼: http://sw2us.com/static/projects/py-ffmpeg/ffmpeg_media_codec.dll 暴露的c接口 1 ffmpeg lib interface list: 2 =========================== 4 typedef unsigned char StreamByte_t; 6 struct MediaStreamInfo_t{ 7 int codec_type; 8 int codec_id; 9 int width; 10 int height; 11 int gopsize; 12 int pixfmt; 13 int tb_num; 14 int tb_den; 15 int bitrate; 16 int frame_number; 17 int videostream; //視頻流編號 18 }; 19 20 struct MediaVideoFrame_t{ 21 StreamByte_t * rgb24; 22 size_t size; 23 int width; 24 int height; 25 unsigned int sequence; //控制播放順序 26 unsigned int duration; //播放時間 27 }; 28 29 struct MediaPacket_t{ 30 StreamByte_t* data; 31 size_t size; 32 AVPacket * pkt; 33 int stream; //流編號 34 int dts; 35 int pts; 36 size_t sequence; 37 size_t duration; 39 }; 40 41 struct MediaFormatContext_t; 42 43 //解碼器 44 struct MediaCodecContext_t{ 45 AVCodecContext * codecCtx; //AVCodecContext* 46 AVCodec * codec; 47 int stream; //流編號 48 AVFrame * rgbframe24; // 49 AVFrame* frame; // 50 StreamByte_t* buffer; 51 size_t bufsize; 52 void * user; 53 MediaStreamInfo_t si; 54 }; 55 56 struct MediaFormatContext_t{ 57 AVFormatContext * fc; //AVFormatContext* 58 MediaStreamInfo_t video; //視頻信息 60 }; 66 #ifdef __cplusplus 67 extern "C" { 68 #endif 69 70 int InitLib(); //初始化解碼庫 71 void Cleanup(); // 73 MediaCodecContext_t* InitAvCodec(MediaStreamInfo_t* si); //根據媒體類型分配解碼器對象 74 void FreeAvCodec(MediaCodecContext_t* codec); //釋放解碼器對象 76 MediaVideoFrame_t * DecodeVideoFrame(MediaCodecContext_t* ctx,MediaPacket_t* pkt); //送入媒體包進行解碼,返回視頻幀 77 void FreeVideoFrame(MediaVideoFrame_t* frame); //釋放視頻幀 79 MediaPacket_t * AllocPacket(); //分配一個流媒體包對象(用于網傳) 80 void FreePacket(MediaPacket_t* pkt); //釋放流媒體包 82 MediaFormatContext_t* InitAvFormatContext(char * file); //媒體文件訪問上下文,申請 83 void FreeAvFormatContext(MediaFormatContext_t* ctx); //釋放 84 MediaPacket_t* ReadNextPacket(MediaFormatContext_t* ctx); //讀媒體文件一個數據包 85 void ReadReset(MediaFormatContext_t* ctx) ; //重置媒體訪問讀取位置 86 int SeekToTime(int timesec) ; //跳躍到指定時間 ffmpeg.py 包裝: 1 import ctypes 2 from ctypes import *
5 _lib = cdll.LoadLibrary('ffmpeg.dll') 6 7 _int_types = (c_int16, c_int32) 8 if hasattr(ctypes, 'c_int64'): 9 # Some builds of ctypes apparently do not have c_int64 10 # defined; it's a pretty good bet that these builds do not 11 # have 64-bit pointers. 12 _int_types += (ctypes.c_int64,) 13 for t in _int_types: 14 if sizeof(t) == sizeof(c_size_t): 15 c_ptrdiff_t = t 16 17 class c_void(Structure): 18 # c_void_p is a buggy return type, converting to int, so 19 # POINTER(None) == c_void_p is actually written as 20 # POINTER(c_void), so it can be treated as a real pointer. 21 _fields_ = [('dummy', c_int)]
26 class MediaStreamInfo_t(Structure): 27 _fields_ = [ 28 ('codec_type', c_int), 29 ('codec_id', c_int), 30 ('width', c_int), 31 ('height', c_int), 32 ('gopsize', c_int), 33 ('pixfmt', c_int), 34 ('tb_num',c_int), 35 ('tb_den',c_int), 36 ('bitrate',c_int), 37 ('frame_number',c_int), 38 ('videostream',c_int), 39 ('duration',c_int), 40 ('extr',POINTER(c_char)), #解碼器 額外hash表數據 41 ('extrsize',c_int), 42 ] 43 44 class MediaVideoFrame_t(Structure): 45 _fields_=[ 46 ('rgb24',POINTER(c_char)), 47 ('size',c_uint), 48 ('width',c_int), 49 ('height',c_int), 50 ('sequence',c_uint), 51 ('duration',c_uint) 52 ] 53 54 class MediaPacket_t(Structure): 55 _fields_=[ 56 ('data',POINTER(c_char)), 57 ('size',c_uint), 58 ('pkt',c_char_p), 59 ('stream',c_int), 60 ('dts',c_int), 61 ('pts',c_int), 62 ('sequence',c_uint), 63 ('duration',c_uint) 64 ] 65 66 67 class MediaCodecContext_t(Structure): 68 _fields_=[ 69 ('codecCtx',c_char_p), 70 ('codec',c_char_p), 71 ('stream',c_int), 72 ('rgbframe24',c_char_p), 73 ('frame',c_char_p), 74 ('buffer',c_char_p), 75 ('bufsize',c_uint), 76 ('user',c_char_p), 77 ('si',MediaStreamInfo_t) 78 ] 79 80 class MediaFormatContext_t(Structure): 81 _fields_=[ 82 ('fc',c_char_p), 83 ('video',MediaStreamInfo_t) 84 ] 85 86 InitAvCodec = _lib.InitAvCodec 87 InitAvCodec.restype = POINTER(MediaCodecContext_t) 88 InitAvCodec.argtypes = [POINTER(MediaStreamInfo_t)] 89 90 91 FreeAvCodec = _lib.FreeAvCodec 92 FreeAvCodec.restype = None 93 FreeAvCodec.argtypes = [POINTER(MediaCodecContext_t)] 96 DecodeVideoFrame = _lib.DecodeVideoFrame 97 DecodeVideoFrame.restype = POINTER(MediaVideoFrame_t) 98 DecodeVideoFrame.argtypes = [POINTER(MediaCodecContext_t),POINTER(MediaPacket_t)] 100 FreeVideoFrame = _lib.FreeVideoFrame 101 FreeVideoFrame.restype = None 102 FreeVideoFrame.argtypes = [POINTER(MediaVideoFrame_t)] 104 AllocPacket = _lib.AllocPacket 105 AllocPacket.restype = POINTER(MediaPacket_t) 106 AllocPacket.argtypes = [] 109 FreePacket = _lib.FreePacket 110 FreePacket.restype = None 111 FreePacket.argtypes = [POINTER(MediaPacket_t),c_int] 113 InitAvFormatContext = _lib.InitAvFormatContext 114 InitAvFormatContext.restype = POINTER(MediaFormatContext_t) 115 InitAvFormatContext.argtypes = [c_char_p] 117 FreeAvFormatContext = _lib.FreeAvFormatContext 118 FreeAvFormatContext.restype = None 119 FreeAvFormatContext.argtypes = [POINTER(MediaFormatContext_t)] 122 ReadNextPacket = _lib.ReadNextPacket 123 ReadNextPacket.restype = POINTER(MediaPacket_t) 124 ReadNextPacket.argtypes = [POINTER(MediaFormatContext_t)] 127 ReadReset = _lib.ReadReset 128 ReadReset.restype = None 129 ReadReset.argtypes = [POINTER(MediaFormatContext_t)] 130 131 SeekToTime = _lib.SeekToTime 132 SeekToTime.restype = c_int 133 SeekToTime.argtypes = [POINTER(MediaFormatContext_t),c_int] 134 135 FlushBuffer = _lib.FlushBuffer 136 FlushBuffer.restype =None 137 FlushBuffer.argtypes = [POINTER(MediaCodecContext_t)] 138 139 InitLib = _lib.InitLib 140 InitLib.restype =None 141 InitLib.argtypes = [] 142 143 Cleanup = _lib.Cleanup 144 Cleanup.restype =None 145 Cleanup.argtypes = [] 好了,看看如何使用這些接口 視頻文件播放: http://sw2us.com/static/projects/py-ffmpeg/test_qt.py
從事webgis及其應用有些時日,實驗性質的東西一直沒有被大規模應用,一路走來頗多辛苦 現將代碼放出,有興趣的朋友可看看,包括地圖數據處理編譯、地圖渲染服務程序、wms程序、tce
近一周時間都在玩p2p,本來以為實現很簡單,但做起來實屬不易 。 Udp穿透Nat會遇到多種Nat類型: 1.FULL CORE 2. RESTRICT 3. PORT-RESTRICT 4. SYMMETRIC 1-3三種NAT實現穿透很簡單,問題在于處理第4種類型:對等NAT SYMMETRIC NAT的工作模式區分在于內網通過NAT時分配的外部端口的方式不同,這又有三種情況: 1. 端口遞增: 通常新端口號會是前一次分配端口號加1或者加固定值 2. 端口在當前NAT最新端口的左右區間: 例如當前NAT外網端口P,那新的分配端口會落在 -N < P < N 3. 隨機分配SR (這個根據當時NAT的網絡情況參數等作為函數f(x)的因子決定) 這第三種分配方式,目前無解,只要任意一端存在SR,則無法穿透 當然很多技術研究者提出了如何猜測動態端口的方案,例如:統計技術的使用,服務器可對固定NAT進行采樣分析等等。。 這個很難哦! 面對SR我直接放棄了,還真不巧,測試了3,4個網絡環境的NAT,居然50%是SR,50%是SYMMETRIC的1,2種類型 。 還是老實的服務器中轉把! 一些p2p資料供參考: http://114.215.178.29/static/p2p
應用中經常用pyCrypto 來生成用戶Token等相關信息,夠簡單,所以貼代碼分享 部分代碼被關閉或者打開,使用者請自行調整,如果了解rsa很簡單理解一下代碼 1 GCONFS={ 2 'auth_public_keyfile':'public.rsa', 3 'auth_private_keyfile':'private.rsa' 4 } 5 6 7 def encrypt_des(key,text): 8 from Crypto.Cipher import DES 9 import base64 10 from Crypto import Random 11 #iv = Random.get_random_bytes(8) 12 des = DES.new(key, DES.MODE_ECB) 13 reminder = len(text)%8 14 if reminder ==0: # pad 8 bytes 15 text+='\x08'*8 16 else: 17 text+=chr(8-reminder)* (8-reminder) 18 #text+=' '*(8-len(text)%8) 19 return des.encrypt(text) 20 #return base64.encodestring(des.encrypt(text)) 21 22 def decrypt_des(key,text): 23 from Crypto.Cipher import DES 24 import base64 25 # print key 26 des = DES.new(key, DES.MODE_ECB) 27 text = des.decrypt(text) 28 pad = ord(text[-1]) 29 if pad == '\x08': 30 return text[:-8] 31 return text[:-pad] 32 33 34 def rsa_generate(): 35 from Crypto.PublicKey import RSA 36 from Crypto import Random 37 random_generator = Random.new().read 38 key = RSA.generate(1024, random_generator) 39 40 41 #print key.publickey().encrypt('123213213123213213',20) 42 public = key.publickey().exportKey() 43 #print key.publickey().exportKey() 44 private = key.exportKey() 45 return public,private 46 47 def rsa_encrypt(key,text): 48 ''' 49 傳入私鑰key和待加密明文數據text 50 自動生成8字節長度隨機密碼P,用P將text進行des加密生成E, 51 用私鑰key加密P生成P2 52 53 key - private key 54 text - orignal text 55 @return: [P2+E] RSA加密的des秘鑰 + 加密的密文 56 ''' 57 import uuid 58 from Crypto.PublicKey import RSA 59 deskey = hashlib.md5(uuid.uuid1().hex).hexdigest()[:8] 60 text = encrypt_des(deskey,text) 61 62 key = RSA.importKey(key) 63 r = key.encrypt(deskey,32) 64 65 return r[0]+text # 加密的key,和des加密的數據 66 67 def rsa_decrypt(key,text): 68 from Crypto.PublicKey import RSA 69 try: 70 rsa = RSA.importKey(key) 71 deskey = text[:128] 72 text = text[128:] 73 deskey = rsa.decrypt(deskey) 74 return decrypt_des(deskey,text) 75 except: 76 return '' 77 78 class Cipher: 79 def __init__(self): 80 # self.pubkey = pubkey 81 # self.privkey = privkey 82 pass 83 84 def encrypt(self,key,text): 85 return rsa_encrypt(key,text) 86 87 88 def decrypt(self,key,text): 89 return rsa_decrypt(key,text) 90 91 @staticmethod 92 def getCipher(): 93 try: 94 cip = Cipher() 95 return cip 96 except: 97 traceback.print_exc() 98 return None 99 100 def encryptToken(user): 101 ''' 102 用戶信息轉換為token 103 ''' 104 token='' 105 try: 106 d = json.dumps(user) 107 # f = open(GCONFS['auth_public_keyfile'],'r') 108 # pubkey = f.read() 109 # f.close() 110 pubkey = ENCRYPT_PUBKEY 111 # d = Cipher.getCipher().encrypt(pubkey,d) #rsa encrpyt 112 token = base64.encodestring(d).strip() 113 #print 'token size:',len(token) 114 except: 115 print traceback.format_exc() 116 token = '' 117 118 return token 119 120 def decryptToken(token): 121 user = None 122 try: 123 # f = open(GCONFS['auth_private_keyfile'],'r') 124 # privkey = f.read() 125 # f.close() 126 privkey = ENCRYPT_PRIVKEY 127 d = base64.decodestring(token) 128 # d = Cipher.getCipher().decrypt(privkey,d) #rsa decrept 129 user = json.loads(d) 130 except: 131 #print traceback.format_exc() 132 pass 133 return user
|