利用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的代码再写出来进行对比,便可以得到一些不同。区别不仅仅是你发现的,还有很多,参考更多的博客和教程来总结。

你可能感兴趣的:(Python)