今天,又算是浪費了一天了。python爬蟲,之前寫過簡單的版本,那個時候還不懂原理,現在算是收尾吧。
以前對網頁爬蟲不瞭解,感覺非常神奇,但是解開這面面紗,似乎裡面的原理並不是很難掌握。首先,明白一個概念,HTTP協議,為什麼叫超文本協議。超文本的概念,是所有的資料幾乎都使用文字模式傳輸,包括文字,映像等,然後在一個網頁中,需要做的是解析這些字元資料,並還原成原始的檔案。
爬蟲的概念,是以一個網頁作為起點,從中發現更多的連結和資料資訊,並依此以樹形展開,可以想象成為一顆樹,對每一個網頁,需要按照需求對資料進行篩選(找圖片,呢還是找關鍵字,或者找音頻等),最後,根據篩選出的URL,對資料進行下載。大致步驟為:
網頁==》網頁樹==》篩選資訊==》下載
筆者這裡就以網頁圖片作為例子:
比如,一張網頁裡,可能有很多張圖片,首先最基本的是對這一張網頁中所有的圖片連結要能夠識別出來,這裡一般的方法是對網頁文本根據正規式進行匹配,從而搜集包含圖片的連結。eg:reg = r"""src\s*="?(\S+)\.jpg"""。其次,對於這些連結進行檔案。看起來很抽象的東西,這兩步就能實現。接著,網頁樹就有點難,需要從網頁中找到有用的網頁連結,然後對這些串連又一次進行篩選,有點像遞迴。這裡的痛點很多,比如,當網頁連結數量非常多的時候,如何有效篩選有效串連,如何控制搜尋深度,如何分配進程等等。
另外,由於目前很多國外的網站是上不去的,所以,有些網頁資料下載需要通過代理;另外,考慮到有些機器效能較好,也實現了多線程的機制。筆者進行了一天的調研,終於調試通過。以下是代碼:
import reimport osimport sysimport time import threadingimport socketimport urllibimport urllib2server = '127.0.0.1'port = '8087'timeout = 720socket.setdefaulttimeout(timeout)class timer(threading.Thread): #The timer class is derived from the class threading.Thread def __init__(self, num, interval,dir,url): threading.Thread.__init__(self) self.thread_num = numself.interval = interval self.url = url self.dir = dir self.thread_stop = False def run(self): #Overwrite run() method, put what you want the thread do here #while not self.thread_stop: DownloadImgs(self.interval,self.url,self.dir)#print 'Thread Object(%d), Time:%s' %(self.thread_num, time.ctime()) #time.sleep(self.interval) def stop(self): self.thread_stop = True def getContent(url,type):print(">>start connecting:%s" % url)from urllib2 import Request, urlopen, URLError, HTTPErrorproxy = urllib2.ProxyHandler({'http':'http://127.0.0.1:8087'}) opener = urllib2.build_opener(proxy,urllib2.HTTPHandler) urllib2.install_opener(opener)try:urlHandler = urllib2.urlopen(url)headers = urlHandler.info().headerslength = 0for header in headers:if header.find('Length') != -1:length = header.split(':')[-1].strip()length = int(length)if(type=="img" and length<15000):print(" >>>>>>>>%d" % length)dataStr = 'EOF'else:print(" ++++++++%d" % length)dataStr = urlHandler.read()except HTTPError, e:print 'The server couldn\'t fulfill the request.'print 'Error code: ', e.codeexcept URLError, e:print 'We failed to reach a server.'print 'Reason: ', e.reasonelse:#print("%s" % dataStr)#f = open("text.txt",'wb')#f.write(dataStr)#f.close()return dataStrdef DownloadImgs(interval,url,dir):dataStr = getContent(url,"html")print("...:%s" % url)if(os.path.isdir(dir) == False):os.mkdir(dir);reg = r"""src\s*="?(\S+)\.jpg"""imgre = re.compile(reg)imglist = imgre.findall(dataStr)x = 0for imgurl in imglist:imgurl =''.join('%s.jpg' % imgurl)if(imgurl.find('http:')>=0):print ("\tdownloading: %s,%s" % (x,imgurl))imgdata=getContent(imgurl,"img")if(imgdata != 'EOF'):outputFile = '%s/%s.jpg' % (dir,x)f = open(outputFile,'wb')f.write(imgdata)f.close()x = x + 1else:print ("\tcannot connect: %s" % imgurl)time.sleep(interval)url_="http://tieba.baidu.com/p/";id=2460150866;n=1;thread=[]for i in range(0, n):url=''.join('%s%d' % (url_,id + i))dir=''.join('PIC%d' % (id+i) )print("######dir = %s, id = %d" % (dir,id+i))thread.append(timer(1, 1,dir,url))for i in range(0, n):thread[i].start()#for i in range(0, n):#url=''.join('%s%d' % (url_,id + i))#dir=''.join('PIC%d' % i)#print("######dir = %s, id = %d" % (dir,id))#DownloadImgs(0.1,url,dir)