利用pyquery抓資料

有些網站的資料並不是很直接可以抓取到,尤其是每次網頁資料屬於需要即時更新,那網站的設計者常會加上一個 timemap 好處理cache的問題,那原本要取得的資料網址就可能變成一串又長又臭的亂碼,如此一來要從固定網址去追蹤動態網址舊常常會是不斷的解析。還好python裡有個好用的模組pyquery它的使用方法就跟jquery一樣方便。

首先抓取主頁取得動態網址,得先點選後才能跳入資料頁:


from pyquery import PyQuery as pq
import urllib2,sys,os

d = pq(url='https://www.jpmrich.com.tw/wps/portal')
p = d("a#fundmorelink")

word = 'https://www.jpmrich.com.tw' + p.attr("href")

很輕鬆的就抓到他的路徑網址,並將其放到word裡,而這個路徑裡正是我們需要的資料,如圖:


資料網頁
資料網頁

那就繼續用pyquery來抓取每個基金的淨值。

d = pq(url=word)
s = ""
p = d("tr.table_level_4, tr.table_level_5")

s = p.text().split(' ')

FILE = codecs.open('jpm03.html','w','utf-8')
for i in range(len(s)):
if i%16 == 0:
FILE.write(s[i] + ',' + s[i+1] + '\n')
FILE.close()
結果如下圖,再來就隨便你是否要存資料庫或要做啥囉。

基金淨值
基金淨值

[+/-] 繼續閱讀...

python UnicodeError

UnicodeError: ASCII decoding error: ordinal not in range(128)' and 'UnicodeError: ASCII encoding error: ordinal not in range(128)

執行時出現以上錯誤就表視編碼上出現錯誤,解決方法:

value = unicode(value, "utf-8")

完整一點:



   1: try:
   2:     unicode(value, "ascii")
   3: except UnicodeError:
   4:     value = unicode(value, "utf-8")
   5: else:
   6:     # value was valid ASCII data
   7:     pass

但有時卻不知道網站或文件編碼,則可以安裝 chardet 套件:

>>> import chardet
>>> import urllib
>>> urlread = lambda url: urllib.urlopen(url).read()
>>> chardet.detect(urlread("http://www.google.com"))
{'confidence': 0.99, 'encoding': 'utf-8'}
>>>

如果是在檔案寫入時發生的錯誤:


FILE = open('jpm03.html','w') 預設是ascii所以得改成


import codecs


FILE = codecs.open('jpm03.html','w','utf-8')  即可。

[+/-] 繼續閱讀...

HTML5標籤向下相容解決

HTML中一個方便的特性就是可以省去一大堆的DIV標籤,直接以有意義的文字去設定標籤區塊,如下:

   1: <!DOCTYPE html>
   2: <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   3:  
   4: <html>
   5:     <head>
   6:         <title><!-- Your Title --></title>
   7:     </head>
   8:  
   9:     <body>
  10:         <header>
  11:             <!-- ... -->
  12:         </header>
  13:  
  14:         <nav>
  15:             <!-- ... -->
  16:         </nav>
  17:  
  18:         <div id="main">
  19:             <!-- ... -->
  20:         </div>
  21:  
  22:         <footer>
  23:             <!-- ... -->
  24:         </footer>
  25:     </body>
  26: </html>

但問題是,那舊的瀏覽器不支援怎麼辦,例如IE,那就幫它設個條件



   1: <!--[if IE]>
   2:     <script src="html5.js"></script>
   3: <![endif]-->

那這個js檔裡應該填入像以下的的程式碼,就可以讓舊流覽器也能正常顯示囉。



   1: document.createElement("article");
   2: document.createElement("footer");
   3: document.createElement("header");
   4: document.createElement("hgroup");
   5: document.createElement("nav");

[+/-] 繼續閱讀...

WLW發佈到blogger發生POST拒絕回應

找尋原因很可能是因為blogger被Chrome開啟後的問題,造成當天無法使用WLW發佈文章,甚至編輯blogger設定讓WLW重新讀取設定也無法取回blogger樣式。

可能的解決方法:

  • 光關閉Chrome的blogger分頁確定無效,若session存於client可能得完全關閉Chrome。
  • 若session存於server,則必須等一陣子後才能恢復。

因為當天無法即時找到解決方法,所以隔天在開WLW後才正常,故無法判定以上兩點,當然也有可能是blogger server的問題。

[+/-] 繼續閱讀...

解決Chrome不支援本地ajax問題

11062404.JPG
11062404.JPG

基本上Chrome有個小小的問題,就是一般如果使用AJAX來做資料交換因為是基於javascript則不管是不是放在http主機上或是單獨的html檔都能夠將資料顯示出來,至少FireFox或IE都可以。

所以以jQuery做一個資料異步傳輸的範例,在FF或IE上都正常,偏偏在Chrome下就看不到資料。

 



這個問題可能是因為Chrome考量未來在WEB APP的安全性所致(我猜的)。但既然大概知道Google的想法,所以就要用新的方法去做而不是受限於以往的習慣,否則再好用的工具也會被習慣(也許是因為之前不好用而不得不為之的方法)所淘汰。

研究了Chrome裡APP的邏輯發現其實Chrome已經把http主機放在核心裡,而不是單純解析javascript而已,所以它的交互方式根本跟在http主機上差不多,所以問題就解決了。

11062401.JPG
11062401.JPG
11062402.JPG
11062402.JPG

首先打開 工具/擴充功能 下的開發人員模式,選擇到你所開發的html檔案的那個目錄,結果啥都沒有是正常的。因為缺了一個檔案,叫 manifest.json 內容如下:

   1: {
   2:   "name": "專案名稱", "version": "1",
   3:   "icons": {"128": "128.png", "24": "24.png"},
   4:   "permissions": [ "notifications" ],
   5:   "app": {"launch": {"local_path": "datagrid.html"}}
   6: }

這個檔案類似一個設定檔,只要把它跟你的html檔放在一起就可以。Google的開發模式裡不好地方都有類似概念,像GAE的yaml或Android…….,這時後再載入一次就可以再擴充功能裡顯示了,如果將來html檔有修改就得"重新載入",這是個缺點也是優點,缺點是有點麻煩,優點是程式可以帶著走了。


然後開啟新的分頁就會看到你APP的頭像,給他執行下去,資料全出來了。


11062403.JPG
11062403.JPG

[+/-] 繼續閱讀...

尋找dropbox資料庫目錄


import ctypes, base64, pickle, sqlite3, os

is_windows = True
try:
# try to get Windows path first
SHGetFolderPath = ctypes.windll.shell32.SHGetFolderPathW
except AttributeError:
is_windows = False

if is_windows:
from ctypes.wintypes import HWND, HANDLE, DWORD, LPCWSTR, MAX_PATH
SHGetFolderPath.argtypes = [HWND, ctypes.c_int, HANDLE, DWORD, LPCWSTR]
path_buffer = ctypes.wintypes.create_unicode_buffer(MAX_PATH)
# 26 is CSIDL_APPDATA, the code for retrieving the user's Application Data folder
SHGetFolderPath(0, 26, 0, 0, path_buffer)
dropbox_db_path = path_buffer.value + '\Dropbox\config.sqlite'
else:
dropbox_db_path = os.path.expanduser('~/.dropbox/dropbox.db')

print dropbox_db_path

[+/-] 繼續閱讀...

python IDLE

 

熱鍵 中文說明 英文說明
alt + / 自動完成單詞(可重複循循) Expand Word
ctrl + → 或 ← 游標移到下一個/前一個單字  
ctrl + ↑ 或 ↓ 算是快速移動吧XD  
ctrl + ] 縮排 Indent Region
ctrl + [ 取消縮排 Dedent Region
alt + 3 注解 Comment Out Region
alt + 4 取消注解 Unconmment Region
ctrl + space 顯示自動完成(註1) Show Completions
alt + m 開啟選取(反白)的Module Open Module
alt + p 前一個指令 Previous Command
alt + n 下一個指令 Next Command
alt + c 瀏覽目前unit下面的class Class Browser
ctrl + F6 重新啟動shell Restart Shell
tab 平常是indent,前面有字時為自動完成,連按兩下可把自動完成的字貼上。  

[+/-] 繼續閱讀...

python開發win app流程



[+/-] 繼續閱讀...

python開發APP(一) GUI




Python的GUI庫很多,在這裡選用的是wxPython,安裝後在Windows下就有以下的工具跟教學範例,其中XRC Resource Editor就是要用來設計GUI的圖型化工具。

打開後如以下一般。設計好之後可以存成XRC檔或直接生成 .py 檔案,現在要使用XRC檔來做連結,將來也方便修改語系問題。

resource1.xrc檔
   1: <?xml version="1.0" ?>
   2: <resource>
   3:  <object class="wxFrame" name="FRAME1">
   4:     <title>測試窗口</title> 
   5:     <icon>favicon.ico</icon>
   6:   <object class="wxPanel" name="MyPanel">
   7:    <object class="wxButton" name="CloseButton">
   8:     <label>關閉</label>
   9:     <pos>15,10</pos>
  10:    </object>
  11:   </object>
  12:  </object>
  13: </resource>
test2.py檔
import wx
import wx.xrc as xrc


class MyApp(wx.App):
    def OnInit(self):

        self.res = xrc.XmlResource(r"./resource1.xrc")       
        self.frame_1 = self.res.LoadFrame(None, "FRAME1")                
        self.Bind(wx.EVT_BUTTON, self.OnClose,  id=xrc.XRCID('CloseButton'))        
        self.frame_1.Show()
        return 1
    # End of OnInit(). 
    
    def OnClose(self, event):
        self.frame_1.Close()    
# End of class MyApp.

if __name__ == "__main__":
    app = MyApp(0)
    app.MainLoop()
執行結果

[+/-] 繼續閱讀...

讓blogger圖片自動燈箱顯示

首先隨便你喜歡哪一套燈箱程式都可以,然後也得讓你的blogger支援 jQuery ,這兩部份資料很多所以省略。

但燈箱範例裡都會要使用者在圖片裡加上 <a class=”lightbox”… 或者 <div id=”gallery”…. 類似的動作,但誰那麼勤勞每次都手動加上勒,所以我就幫他加上一段 jQuery 程式

   1: $(function() {
   2: $('div[id^="post-body-"] a').each(function(){
   3:     if (($(this).attr("href").toUpperCase().indexOf(".JPG")!== -1) || ($(this).attr("href").toUpperCase().indexOf(".PNG")!== -1))
   4:        $(this).lightBox();
   5: });
   6: });

這樣一來管你是JPG或PNG檔,連大小寫都不管,只要貼上全都套上燈箱。

[+/-] 繼續閱讀...

plugin測試

import os
for root, dirs, files in os.walk('.'):
    for file in files:
        if file.endswith('.ui'):
            os.system('pyuic4 -o ui_%s.py %s' % (file.rsplit('.', 1)[0], file))
        elif file.endswith('.qrc'):
         os.system('pyrcc4 -o %s_rc.py %s' % (file.rsplit('.', 1)[0], file))
以上用SyntaxHighlighter for Windows Live Writer 
以下用 Code Snippet


   1: import ctypes, base64, pickle, sqlite3, os 
   2:  
   3: is_windows = True
   4: try:
   5:   # try to get Windows path first
   6:   SHGetFolderPath = ctypes.windll.shell32.SHGetFolderPathW
   7: except AttributeError:
   8:   is_windows = False
   9:   
  10: if is_windows:
  11:   from ctypes.wintypes import HWND, HANDLE, DWORD, LPCWSTR, MAX_PATH
  12:   SHGetFolderPath.argtypes = [HWND, ctypes.c_int, HANDLE, DWORD, LPCWSTR]
  13:   path_buffer = ctypes.wintypes.create_unicode_buffer(MAX_PATH)
  14:   # 26 is CSIDL_APPDATA, the code for retrieving the user's Application Data folder
  15:   SHGetFolderPath(0, 26, 0, 0, path_buffer)
  16:   dropbox_db_path = path_buffer.value + '\Dropbox\config.sqlite'
  17: else:
  18:   dropbox_db_path = os.path.expanduser('~/.dropbox/dropbox.db')
  19:  
  20: db = sqlite3.connect(dropbox_db_path)
  21: cur = db.cursor()
  22: cur.execute('select key, value from config order by key')
  23: for row in cur:
  24:         print row[0], '=', pickle.loads(base64.b64decode(row[1])) if row[1] != None else row[1]
  25: db.close()

測試結果完整呈現於此

[+/-] 繼續閱讀...