python抓取网页图片
网页的图片大致是用Image导入的,使用的是相对路径,例如
<image src="image/bg.jpg"/>
通过匹配可以获取image/bg.jpg,与页面地址组合可以得到图片的地址
除了直接引入的图片,还有通过CSS,HTML引入的图片,也需要处理
# -*- coding: utf-8 -*- import urllib, httplib, urlparse import sys import re def httpExists(url): host, path = urlparse.urlsplit(url)[1:3] if ':' in host: # port specified, try to use it host, port = host.split(':', 1) try: port = int(port) except ValueError: print 'invalid port number %r' % (port,) return False else: # no port specified, use default port port = None try: connection = httplib.HTTPConnection(host, port=port) connection.request("HEAD", path) resp = connection.getresponse( ) if resp.status == 200: # normal 'found' status found = True elif resp.status == 302: # recurse on temporary redirect found = httpExists(urlparse.urljoin(url,resp.getheader('location', ''))) else: # everything else -> not found print "Status %d %s : %s" % (resp.status, resp.reason, url) found = False except Exception, e: print e.__class__, e, url found = False return found """根据url获取文件名""" def gGetFileName(url): if url==None: return None if url=="" : return "" arr=url.split("/") return arr[len(arr)-1] """根据url下载文件,文件名参数指定""" def gDownloadWithFilename(url,savePath,file): #参数检查,现忽略 try: urlopen=urllib.URLopener() fp = urlopen.open(url) data = fp.read() fp.close() print 'download file url :',url file=open(savePath + file,'w+b') file.write(data) file.close() except IOError: print "download error!"+ url def gDownload(url,savePath): fileName = gGetFileName(url) gDownloadWithFilename(url,savePath,fileName) def getRexgList(lines,regx,searchRegx): if lines==None : return lists =[] for line in lines: ismatch = re.search(regx,line,re.IGNORECASE) if ismatch : matchs = re.search(searchRegx,line,re.IGNORECASE) if matchs != None: groups = matchs.groups() for str in groups: if str not in lists: lists.append(str) return lists def checkLine(lines): for line in lines : matchs = re.search(r'url((S+))',re.IGNORECASE) if matchs != None : print matchs.groups() def getPageLines(url): if url==None : return if not httpExists(url): return try: page = urllib.urlopen(url) html = page.readlines() page.close() return html except: print "getPageLines() error!" return def getCurrentPageImage(url,savePath): lines = getPageLines(url) print 'lines.length',len(lines) regxlists = getRexgList(lines,r'srcs*="images(S+)"',r'srcs*="(S+)"') if regxlists==None: return print 'getCurrentPageImage() images.length',len(regxlists) for jpg in regxlists: jpg =url + jpg gDownload(jpg,savePath) def getCSSImages(link,savePath,url): lines = getPageLines(link) print 'lines.length',len(lines) regxlists = getRexgList(lines,r'url((S+))',r'url((S+))') if regxlists==None: return print 'getCurrentPageImage() images.length',len(regxlists) for jpg in regxlists: jpg =url + jpg gDownload(jpg,savePath) """根据url获取其上的相关htm、html链接,返回list""" def gGetHtmlLink(url): #参数检查,现忽略 rtnList=[] lines=getPageLines(url) regx = r"""href="?(S+).htm""" for link in getRexgList(lines,regx,r'href="(S+)"'): link =url + link if link not in rtnList: rtnList.append(link) print link return rtnList """根据url获取其上的相关css链接,返回list""" def gGetCSSLink(url): #参数检查,现忽略 rtnList=[] lines=getPageLines(url) regx = r"""href="?(S+).css""" for link in getRexgList(lines,regx,r'href="(S+)"'): link = url + link if link not in rtnList: rtnList.append(link) return rtnList def getPageImage(url,savePath): """getCurrentPageImage(url,savePath)""" """读取其他的CSS,html文件中的图片 links=gGetHtmlLink(url) for link in links: print u'get images on link-html读取' getCurrentPageImage(link,savePath)""" links=gGetCSSLink(url) for link in links: print 'get images on link:',link getCSSImages(link,savePath,url) if __name__ == '__main__': url = 'http://www.templatemo.com/templates/templatemo_281_chrome/' savePath = 'd:/tmp/' print 'download pic from [' + url +']' print 'save to [' +savePath+'] ...' getPageImage(url,savePath) print "download finished"
具体使用的时候根据URL的情况,具体分析得到图片地址的方式。
红黑树:个人理解与Python实现
红黑树:个人理解与Python实现 【基本事实1】 红黑树是一种平衡的二叉查找树,无论插入还是删除操作都可以在O(lg n)内实现,而一般的二叉查找树则在极端情况下会退化为线性结构。 红黑树之所以是平衡的二叉查找树,是因为每个节点都有表示其颜色的域值:红或黑,在插入和删除操作的时候依据节点的颜色向平衡的方向调整。根本原因当然是由红黑树定义所决定的: 如果一个二叉查找树满足如下条件,那么它就称作红黑树: 1.每个节点要么是红色,要么是黑色 2.根结点是黑色 3.每个叶节点(NIL)为黑色 4.如果一个节点是红色,其儿子节点一定是黑色 5.对于每个节点,从该节点到其子孙节点的所有路径上包含相同数目的黑节点 【个人理解1】 红黑树的定义中,我认为有这些地方要注意: 1.每个节点只有一种颜色(后面删除节点的操作时引入的“额外一重黑色”则不满足此条件,所以一直要性质1调整) 2.定义中的叶节点是指NIL,它们都是黑色,而且没有子节点。根结点的父节点也是NIL。比如只有一个根节点的红黑树,它有两个叶节点。NIL是没有值的,只是一种存在。(我在Python的实现中,把NIL值都设定为None) 3.如果一个节点是红色的,它一定不是根结点,而且一定有父节点(父节点也一定是黑色的);如果它有儿子节点则一定是黑色儿子节点(每个节点如果左右儿子都是NIL,我认为它没有儿子) 4.性质5说的就是黑高度了 【基本事实2】 红黑树的旋转 红黑树在INSERT和DELETE的过程中,会使用到旋转操作。红黑树有两种旋转:左旋和右旋
左旋x:从右图到左图的过程
右旋y:从左图到右图的过程 【个人理解2】 1.并非每个节点在INSERT或DELETE的过程中都需要旋转操作 2.左旋就是右儿子y取代父节点x,x作为y的做儿子,y原来的左儿子b成为x现在的右儿子 3.右旋就是左旋的逆向过程 【基本事实3】 红黑树的插入 INSERT一个值的过程,就是在二叉查找树的INSERT操作基础上,根据红黑树性质做必要的调整,比如颜色变化,比如旋转,也就是INSERT_FIXUP的过程 插入的节点一般设定为红色然后再调整 【个人理解3】 假设要插入的节点为z,INSERT操作就是把z放到树的最底层,然后用INSERT_FIXUP区调整。INSERT_FIXUP中要注意的是: 1.如果z的父节点是NIL(即:插入节点z之前红黑树为空),那么把z涂黑,并成为根结点(完成插入) 2.如果z的父节点是黑色的,不用调整(完成插入) 3.如果z的父节点是红色的: 3-0:如果z没有叔叔节点,那么: 3-0-0:如果z为右儿子,则左旋z的父节点,成为3-0-1 3-0-1:如果z为左儿子,则“父涂黑,爷涂红”,然后如果父节点是左儿子,则“爷右旋”,否则“爷左旋”(完成插入) 3-1:如果z的叔叔节点为黑色,那么: 3-1-0:如果z是右儿子,那么左旋z的父节点,转化为3-1-1 3-1-1:如果z是左儿子,那么“父涂黑,爷涂红”,然后如果父节点是左儿子,则“爷右旋”,否则“爷左旋”(完成插入) 3-2:如果z的叔叔节点为红色,那么“父涂黑,叔涂黑,爷涂红”,并对爷爷节点g调用INSERT_FIXUP过程 以上序号和《算法导论》中的对应关系:3-2对应case1,3-1-0对应case2,3-1-1对应case3 【基本事实4】 1.红黑树删除一个节点的操作比较复杂,但也是在二叉查查找树的基础上,调用DELETE_FIXUP过程来调整 2.如果要删除的节点z,它有两个儿子,那么让z的值设定为z的后继节点y的值,然后删除y 3.如果要删除的节点z只有一个儿子x,那就让z的节点p和x成为“父子”。如果z原来是红色的,则不必调用DELETE_FIXUP过程,否则要调用 4.如果要删除的节点z没有儿子:那就直接删除z好了 5.删除节点时引入了“额外的一层黑色”,《算法导论》中文第二版P173这样说: “在RB—DELETE中,如果被删除的节点y是黑色的,则会产生三个问题。首先,如果y原来是根结点,而y的一个红色的孩子成为了新的根,这就问犯了性质2)。其次,如果x和p[y](现在也是p[x])都是红的,就违反了性质4)。第三,删除y将导致先前包含y的任何路径上黑节点个数少1。因此,性质5)被y的一个祖先破坏了。不久者恶问题的一个办法就是把结点x视为还有额外的一重黑色。也就是说,如果将人以包含结点x的路径上黑节点个数加1,则在这种假设下,性质5)成立。当将黑节点y删除时,将其黑色“下推”至其子节点。现在为题变为结点x可能既不是红,又不是黑,从而违反了性质1)。结点x是双重黑色或红黑,这就分别给包含x的路径上黑结点个数贡献2个或1个。x的color属性仍然是RED(如果x是红黑的)或BLACK(如果x是双重黑色)。换言之,一个结点额外的黑色反映在x指向它,而不是它的color属性。” 【个人理解4】 1.当你想举反例推翻某个“结论”时,请注意,你的反例中的红黑树可能并不是红黑树;或者,它满足红黑树的定义,但无法判断是否能通过“每次插入一个节点”的方式生成。 2.因为有“额外一重黑色”的存在,《算法导论》中关于红黑树删除的case1中,调整前后的两幅图虽然“看上去是镜面对称”,但前者不满足性质5,调整后满足性质5 3.《算法导论》中关于红黑树删除的case2中,x现在为黑色,且有额外的一重黑色(就像是背负着子孙们的希望。。。),此时将x和w都去掉一个黑色,然后使p(x)增加额外的一层黑色。由于w原本为黑色,则现在令w为红色即可。此时令new_x=p(x),若new_x原本为红色,置黑即可结束;否则,对new_x调用DELETE_FIXUP过程 4.DELETE_FIXUP过程,调整的是DELETE(z)过程中z的左/右儿子(当z只有一个儿子时),或者z的后继的右儿子
我的代码:
#coding:utf8#author:HaxtraZ#description:红黑树,python实现 RED ='red' BLACK ='black'class RBT:def __init__(self):self.items =[]self.root =Nonedef LEFT_ROTATE(self, x):# x是一个RBTnode y = x.right if y isNone:# 右节点为空,不旋转returnelse: beta = y.left x.right = beta if beta isnotNone: beta.parent = x p = x.parent y.parent = p if p isNone:# x原来是rootself.root = y elif x == p.left: p.left = y else: p.right = y y.left = x x.parent = y def RIGHT_ROTATE(self, y):# y是一个节点 x = y.right if x isNone:# 右节点为空,不旋转returnelse: beta = x.right y.left = beta if beta isnotNone: beta.parent = y p = y.parent x.parent = p if p isNone:# y原来是rootself.root = x elif y == p.left: p.left = x else: p.right = x x.right = y y.parent = x def INSERT(self, val): z =RBTnode(val) y =None x =self.root while x isnotNone: y = x if z.val < x.val: x = x.left else: x = x.right z.PAINT(RED) z.parent = y if y isNone:# 插入z之前为空的RBTself.INSERT_FIXUP(z)elif y.color == RED:# z的父节点y为红色,需要fixup。# 如果z的父节点y为黑色,则不用调整if z.val < y.val: y.left = z else: y.right = z self.INSERT_FIXUP(z)def INSERT_FIXUP(self, z):# case 1:z为root节点ifself.root ==None: z.PAINT(BLACK)self.root = z return# case 2:z的父节点为黑色ifself.parent.color == BLACK:# 包括了z处于第二层的情况return# 下面的几种情况,都是z.parent.color == RED:# 节点y为z的uncle p = z.parent if p == p.parent.left: y = p.parent.right else: y = p.parent.left g = p.parent # g为x的grandpa# case 3-0:z没有叔叔。即:y为NIL节点# 注意,此时z的父节点一定是REDif y isNone:if z == p.left:# 3-0-0:z为右儿子,则把p左旋# 转化为3-0-1或3-0-2的情况self.LEFT_ROTATE(p) p, z = z, p g.PAINT(RED) p.PAINT(BLACK)if g.left == p:# 3-0-1:p为g的左儿子self.RIGHT_ROTATE(g)else:# 3-0-2:p为g的右儿子self.LEFT_ROTATE(g)# case 3-1:z有黑叔elif y.color == BLACK:if p.right == z:# 3-1-0:z为右儿子,则左旋p# 转化为3-1-1或3-1-2self.LEFT_ROTATE(p) p, z = z, p p.PAINT(BLACK) g.PAINT(RED)if p == g.left:# 3-1-1:p为g的左儿子,则右旋gself.RIGHT_ROTATE(g)else:# 3-1-2:p为g的右儿子,则左旋gself.LEFT_ROTATE(g)# case 3-2:z有红叔# 则涂黑父和叔,涂红爷,g作为新的z,递归调用else: y.PAINT(BLACK) p.PAINT(BLACK) g.PAINT(RED)self.INSERT_FIXUP(g)def DELETE(self, val): curNode =self.root while curNode isnotNone:if val < curNode.val: curNode = curNode.left elif val > curNode.val: curNode = curNode.right else:# 找到了值为val的元素,正式开始删除if curNode.left isNoneand curNode.right isNone:# case1:curNode为叶子节点:直接删除即可if curNode ==self.root:self.root =Noneelse: p = curNode.parent if curNode == p.left: p.left =Noneelse: p.right =Noneelif curNode.left isnotNoneand curNode.right isnotNone: sucNode =self.SUCCESOR(curNode) curNode.val, sucNode.val = sucNode.val, curNode.val self.DELETE(sucNode.val)else: p = curNode.parent if curNode.left isNone: x = curNode.right else: x = curNode.left if curNode == p.left: p.left = x else: p.right = x x.parent = p if curNode.color == BLACK:self.DELETE_FIXUP(x) curNode =NonereturnFalsedef FIND(self, val):classRBTnode:'''红黑树的节点类型'''def __init__(self, val):self.val = val self.left =Noneself.right =Noneself.parent =Nonedel PAINT(self, color):self.color = color
分类: python