利用Python爬蟲爬取你需要的網頁——加速打開速度

  代碼來自於Python核心編程,運行環境爲Python2.7+macOS。直至2月16日運行無誤。代碼中有核心代碼註釋,如需更詳細的解釋,請去書本內容觀看。話不多說,直接上碼。

#!/usr/bin/env python
import cStringIO
import formatter
from htmllib import HTMLParser
import httplib
import os
import sys
import urlparse
import urllib
#urllib:使用其中的urlparse()函數來下載Web頁面。urlparse:使用其中的urlparse()和urljoin()函數來處理URL
class Retriever(object):
    __slots__ = ('url','file')#__slot__變量表示實例只能擁有self.url和self.file屬性
    def __init__(self,url):
        self.url,self.file=self.get_file(url)


    def get_file(self,url,default='index.html'):
        'Create usable local filename from url 將URL的前綴http://前綴移除,丟掉任何爲獲取主機名二附加的額外信息,如用戶名、密碼和端口號'
        parsed=urlparse.urlparse(url)
        host=parsed.netloc.split('@')[-1].split(':')[0]
        filepath='%s%s' %(host,parsed.path)
        if not os.path.splitext(parsed.path)[1]:
            filepath=os.path.join(filepath,default)
        linkdir=os.path.dirname(filepath)
        if not os.path.isdir(linkdir):
            if os.path.exists(linkdir):
                os.unlink(linkdir)
            os.makedirs(linkdir)
        return url,filepath

    def download(self):
        'Download URL to specific named file'
        try:
            retval=urllib.urlretrieve(self.url,self.file)
        except (IOError,httplib.InvalidURL) as e:
            retval=(('*** ERROR: bad URL "%s": %s' %(self.url,e)),)
        return retval

    def parse_links(self):
        'Parse out the links found in download HTML file'
        f=open(self.url,'r')
        data=f.read()
        f.close()
        parser=HTMLParser(formatter.AbstractFormatter(formatter.DumbWriter(cStringIO.StringIO())))
        parser.feed(data)
        parser.close()
        return parser.anchorlist

class Crawler(object):
    count=0#每成功下載一個頁面,增一。

    def __init__(self,url):
        self.q=[url]#待下載的鏈接隊列
        self.seen=set()#已下載鏈接的一個集合
        parsed=urlparse.urlparse(url)
        host=parsed.netloc.split('@')[-1].split(':')[0]
        self.dom='.'.join(host.split('.')[-2:])#存儲主鏈接的域名,並判定後續鏈接的域名與主域名是否一致

    def get_page(self,url,media=False):
        'Download page &parse links,add to queue if nec'
        r=Retriever(url)
        fname=r.download()[0]
        if fname[0]=='*':
            print fname,'...skipping parse'
            return
        Crawler.count+=1
        print '\n(',Crawler.count,')'
        print 'URL:',url
        print 'FILE:',fname
        self.seen.add(url)
        ftype=os.path.splitext(fname)[1]
        if ftype not in ('.htm','html'):#跳過所有非web頁面
            return

        for link in r.parse_links():
            if link.startwith('mailto'):#郵箱連接會被忽略
                print '....discarded,mailto link'
                continue
            if not media:#媒體文件會被忽略
                ftype=os.path.splitext(link)[1]
                if ftype in ('.mp3','.mp4','.m4v','.wav'):
                    print '...discarded,media file'
                    continue
            if not link.startwith('http://'):
                link=urlparse.urljoin(url,link)
                print '*',link

            if link not in self.seen:
                if self.dom not in link:
                    print '....discarded, not in domain'
                else:
                    if link not in self.q:
                        self.q.append(link)
                        print '...new,added to Q'
                    else:#已經位於隊列中處理的連接
                        print '.....discarded,already processed'
            else:#已經下載的連接
                print '....discarded,already processed'

    def go(self,media=False):
        'Process next page in queue(if any)'
        while self.q:
            url=self.q.pop()
            self.get_page(url,media)

def main():
    if len(sys.argv) >1:
        url=sys.argv[1]
    else:
        try:
            url=raw_input('Enter starting URL: ')
        except (KeyboardInterrupt,EOFError):
            url=''
    if not url:
        return
    if not url.startswith('http://') and not url.startswith('ftp://'):
        url='http://%s/' %url
        robot=Crawler(url)
        robot.go()

if __name__=='__main__':
    main()


  需要解釋的是,在Web開發這一塊,Python2.x和Python3.x有一些不同,你可以先熟悉2的一些語法和編程規則,然後將3的代碼再寫出來進行對比,便可以得到一些不同。區別不僅僅是你發現的,還有很多,參考更多的博客和教程來總結。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章