呵呵,前兩節好像和python沒多大關係。。這節完全是貼代碼,
這是我第一次寫python,很多地方比較亂,主要就看看邏輯流程吧。
對於編碼格式確實搞得我頭大。。取下來頁面不知道是什麼編碼,所以先找charset,然後轉unicode。統一在unicode下操作,但是資料庫是utf8的,WINDOWS的控制台又必須是gbk的,但是我IDE控制台必須是utf8的。。所以才會有DEBUG這個變數存在。。。主要是為了控制輸出編碼。
本程式連跑了24小時,然後分布式在10台機器上部署,長時間續航基本沒有問題。
之後每天將進行10萬次網頁的爬取。
源碼如下:
內容爬取及工具
[python] view plain copy ''''' Created on 2010-9-15 @author: chenggong ''' import urllib2 import re import socket DEBUG = 0 ''''' 工具類 ''' class Tools(): #log函數 @staticmethod def writelog(level,info,notify=False): if DEBUG == 0: try: print "["+level+"]"+info.decode('UTF-8').encode('GBK') except: print "["+level+"]"+info.encode('GBK') else: print "["+level+"]"+info #if notify: # print "[notify]報告管理員!!" #轉unicode @staticmethod def toUnicode(s,charset): if( charset == "" ): return s else: try: u = unicode( s, charset ) except: u = "" return u #正則抓取 #@param single 是否只抓取一個 @staticmethod def getFromPatten(patten,src,single=False): rst = ""; p = re.compile(patten,re.S) all = p.findall(src) for matcher in all: rst += matcher + " " if( single ): break return rst.strip() ''''' 網頁內容爬蟲 ''' class PageGripper(): URL_OPEN_TIMEOUT = 10 #網頁逾時時間 MAX_RETRY = 3 #最大重試次數 def __init__(self): socket.setdefaulttimeout(self.URL_OPEN_TIMEOUT) #擷取字元集 def getCharset(self,s): rst = Tools.getFromPatten(u'charset=(.*?)"',s,True) if rst != "": if rst == "utf8": rst = "utf-8" return rst #嘗試擷取頁面 def downloadUrl(self,url): charset = "" page = "" retry = 0 while True: try: fp = urllib2.urlopen(url) break except urllib2.HTTPError,e: #狀態錯誤 Tools.writelog('error','HTTP狀態錯誤 code='+e.code) raise urllib2.HTTPError except urllib2.URLError,e: #網路錯誤逾時 Tools.writelog('warn','頁面訪問逾時,重試..') retry+=1 if( retry > self.MAX_RETRY ): Tools.writelog('warn','超過最大重試次數,放棄') raise urllib2.URLError while True: line = fp.readline() if charset == "": charset = self.getCharset(line) if not line: break page += Tools.toUnicode(line,charset) fp.close() return page #擷取頁面 def getPageInfo(self,url): Tools.writelog( "info","開始抓取網頁,url= "+url) info = "" try: info = self.downloadUrl(url) except: raise Tools.writelog("debug","網頁抓取成功") return info ''''' 內容提取類 ''' class InfoGripper(): pageGripper = PageGripper() def __init__(self): Tools.writelog('debug',"爬蟲啟動") #抓取標題 def griptitle(self,data): title = Tools.getFromPatten(u'box2t sp"><h3>(.*?)</h3>', data, True) if title == "": title = Tools.getFromPatten(u'<title>(.*?)[-<]',data,True) return title.strip() #抓取頻道 def gripchannel(self,data): zone = Tools.getFromPatten(u'頻道:(.*?)</span>',data,True) channel = Tools.getFromPatten(u'<a.*?>(.*?)</a>',zone,True) return channel #抓取標籤 def griptag(self,data): zone = Tools.getFromPatten(u'標籤:(.*?)</[^a].*>',data,True); rst = Tools.getFromPatten(u'>(.*?)</a>',zone,False); return rst #抓取觀看次數 def gripviews(self,data): rst = Tools.getFromPatten(u'已經有<em class="hot" id="viewcount">(.*?)</em>次觀看',data); return rst #抓取發布時間 def griptime(self,data): rst = Tools.getFromPatten(u'在<em>(.*?)</em>發布',data,True) return rst #抓取發行者 def gripuser(self,data): rst = Tools.getFromPatten(u'title="點擊進入(.*?)的使用者空間"',data,True) return rst #擷取頁面字元集 def getPageCharset(self,data): charset = Tools.getFromPatten(u'charset=(.*?)"',data,True) if( charset == "utf8" ): charset = "utf-8" return charset #擷取CC相關資料 def getCCData(self,data): zone = Tools.getFromPatten(u'SWFObject(.*?)</script>',data,True) #判斷是否使用bokecc播放 isFromBokeCC = re.match('.*bokecc.com.*', zone) if( not isFromBokeCC ): return "","" ccSiteId = Tools.getFromPatten(u'siteid=(.*?)[&,"]',zone,True) ccVid = Tools.getFromPatten(u'vid=(.*?)[&,"]',zone,True) return ccSiteId,ccVid #擷取站內vid def gripVideoId(self,data): vid = Tools.getFromPatten(u'var vid = "(.*?)"',data,True) return vid #擷取點擊量 def gripViewsAjax(self,vid,url,basedir): host = Tools.getFromPatten(u'http://(.*?)/',url,True) ajaxAddr = "http://" + host + basedir + "/index.php/ajax/video_statistic/" + vid ''''' try: content = self.pageGripper.getPageInfo(ajaxAddr) except Exception,e: print e Tools.writelog ("error", ajaxAddr+u"抓取失敗") return "error" ''' Tools.writelog('debug', u"開始擷取點擊量,url="+ajaxAddr) while True: &nb